[libc-commits] [libc] Libc/expose auxv (PR #74166)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Fri Dec 1 18:58:24 PST 2023


https://github.com/SchrodingerZhu created https://github.com/llvm/llvm-project/pull/74166

None

>From ba99c966130d9017fa59392da1c789d73e093536 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 1 Dec 2023 00:56:15 -0500
Subject: [PATCH 1/2] [libc][NFC] unify startup library's code style with the
 rest

---
 libc/config/linux/app.h              |  4 +--
 libc/src/stdlib/getenv.cpp           |  2 +-
 libc/startup/linux/aarch64/start.cpp | 18 +++++-----
 libc/startup/linux/riscv/start.cpp   | 18 +++++-----
 libc/startup/linux/x86_64/start.cpp  | 53 ++++++++++++++--------------
 5 files changed, 48 insertions(+), 47 deletions(-)

diff --git a/libc/config/linux/app.h b/libc/config/linux/app.h
index b17026a7832a3c4..0d2f9475c10db64 100644
--- a/libc/config/linux/app.h
+++ b/libc/config/linux/app.h
@@ -69,7 +69,7 @@ struct Args {
 // Data structure which captures properties of a linux application.
 struct AppProperties {
   // Page size used for the application.
-  uintptr_t pageSize;
+  uintptr_t page_size;
 
   Args *args;
 
@@ -77,7 +77,7 @@ struct AppProperties {
   TLSImage tls;
 
   // Environment data.
-  EnvironType *envPtr;
+  EnvironType *env_ptr;
 };
 
 extern AppProperties app;
diff --git a/libc/src/stdlib/getenv.cpp b/libc/src/stdlib/getenv.cpp
index 08397e0d8057161..7a8eb1943c0a9c4 100644
--- a/libc/src/stdlib/getenv.cpp
+++ b/libc/src/stdlib/getenv.cpp
@@ -16,7 +16,7 @@
 namespace LIBC_NAMESPACE {
 
 LLVM_LIBC_FUNCTION(char *, getenv, (const char *name)) {
-  char **env_ptr = reinterpret_cast<char **>(LIBC_NAMESPACE::app.envPtr);
+  char **env_ptr = reinterpret_cast<char **>(LIBC_NAMESPACE::app.env_ptr);
 
   if (name == nullptr || env_ptr == nullptr)
     return nullptr;
diff --git a/libc/startup/linux/aarch64/start.cpp b/libc/startup/linux/aarch64/start.cpp
index 002af5313cc82dd..b5c426866b56d74 100644
--- a/libc/startup/linux/aarch64/start.cpp
+++ b/libc/startup/linux/aarch64/start.cpp
@@ -74,7 +74,7 @@ void init_tls(TLSDescriptor &tls_descriptor) {
       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   // We cannot check the return value with MAP_FAILED as that is the return
   // of the mmap function and not the mmap syscall.
-  if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.pageSize)
+  if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.page_size)
     LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 1);
   uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val));
   uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
@@ -144,7 +144,7 @@ __attribute__((noinline)) static void do_start() {
   // value. We step over it (the "+ 1" below) to get to the env values.
   uint64_t *env_ptr = app.args->argv + app.args->argc + 1;
   uint64_t *env_end_marker = env_ptr;
-  app.envPtr = env_ptr;
+  app.env_ptr = env_ptr;
   while (*env_end_marker)
     ++env_end_marker;
 
@@ -153,19 +153,19 @@ __attribute__((noinline)) static void do_start() {
 
   // After the env array, is the aux-vector. The end of the aux-vector is
   // denoted by an AT_NULL entry.
-  Elf64_Phdr *programHdrTable = nullptr;
-  uintptr_t programHdrCount;
+  Elf64_Phdr *program_hdr_table = nullptr;
+  uintptr_t program_hdr_count;
   for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
        aux_entry->type != AT_NULL; ++aux_entry) {
     switch (aux_entry->type) {
     case AT_PHDR:
-      programHdrTable = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
+      program_hdr_table = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
       break;
     case AT_PHNUM:
-      programHdrCount = aux_entry->value;
+      program_hdr_count = aux_entry->value;
       break;
     case AT_PAGESZ:
-      app.pageSize = aux_entry->value;
+      app.page_size = aux_entry->value;
       break;
     default:
       break; // TODO: Read other useful entries from the aux vector.
@@ -173,8 +173,8 @@ __attribute__((noinline)) static void do_start() {
   }
 
   app.tls.size = 0;
-  for (uintptr_t i = 0; i < programHdrCount; ++i) {
-    Elf64_Phdr *phdr = programHdrTable + i;
+  for (uintptr_t i = 0; i < program_hdr_count; ++i) {
+    Elf64_Phdr *phdr = program_hdr_table + i;
     if (phdr->p_type != PT_TLS)
       continue;
     // TODO: p_vaddr value has to be adjusted for static-pie executables.
diff --git a/libc/startup/linux/riscv/start.cpp b/libc/startup/linux/riscv/start.cpp
index ed976d294d94215..bf04be5ad14ad1d 100644
--- a/libc/startup/linux/riscv/start.cpp
+++ b/libc/startup/linux/riscv/start.cpp
@@ -61,7 +61,7 @@ void init_tls(TLSDescriptor &tls_descriptor) {
       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   // We cannot check the return value with MAP_FAILED as that is the return
   // of the mmap function and not the mmap syscall.
-  if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.pageSize)
+  if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.page_size)
     LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 1);
   uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val));
   uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
@@ -147,7 +147,7 @@ __attribute__((noinline)) static void do_start() {
   // value. We step over it (the "+ 1" below) to get to the env values.
   LIBC_NAMESPACE::ArgVEntryType *env_ptr = app.args->argv + app.args->argc + 1;
   LIBC_NAMESPACE::ArgVEntryType *env_end_marker = env_ptr;
-  app.envPtr = env_ptr;
+  app.env_ptr = env_ptr;
   while (*env_end_marker)
     ++env_end_marker;
 
@@ -156,19 +156,19 @@ __attribute__((noinline)) static void do_start() {
 
   // After the env array, is the aux-vector. The end of the aux-vector is
   // denoted by an AT_NULL entry.
-  PgrHdrTableType *programHdrTable = nullptr;
-  uintptr_t programHdrCount;
+  PgrHdrTableType *program_hdr_table = nullptr;
+  uintptr_t program_hdr_count;
   for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
        aux_entry->type != AT_NULL; ++aux_entry) {
     switch (aux_entry->type) {
     case AT_PHDR:
-      programHdrTable = reinterpret_cast<PgrHdrTableType *>(aux_entry->value);
+      program_hdr_table = reinterpret_cast<PgrHdrTableType *>(aux_entry->value);
       break;
     case AT_PHNUM:
-      programHdrCount = aux_entry->value;
+      program_hdr_count = aux_entry->value;
       break;
     case AT_PAGESZ:
-      app.pageSize = aux_entry->value;
+      app.page_size = aux_entry->value;
       break;
     default:
       break; // TODO: Read other useful entries from the aux vector.
@@ -176,8 +176,8 @@ __attribute__((noinline)) static void do_start() {
   }
 
   app.tls.size = 0;
-  for (uintptr_t i = 0; i < programHdrCount; ++i) {
-    PgrHdrTableType *phdr = programHdrTable + i;
+  for (uintptr_t i = 0; i < program_hdr_count; ++i) {
+    PgrHdrTableType *phdr = program_hdr_table + i;
     if (phdr->p_type != PT_TLS)
       continue;
     // TODO: p_vaddr value has to be adjusted for static-pie executables.
diff --git a/libc/startup/linux/x86_64/start.cpp b/libc/startup/linux/x86_64/start.cpp
index af95d2702ded975..bc1b4f0487f316a 100644
--- a/libc/startup/linux/x86_64/start.cpp
+++ b/libc/startup/linux/x86_64/start.cpp
@@ -33,9 +33,9 @@ extern "C" void __stack_chk_fail() {
 namespace LIBC_NAMESPACE {
 
 #ifdef SYS_mmap2
-static constexpr long mmapSyscallNumber = SYS_mmap2;
+static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2;
 #elif SYS_mmap
-static constexpr long mmapSyscallNumber = SYS_mmap;
+static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
 #else
 #error "mmap and mmap2 syscalls not available."
 #endif
@@ -54,49 +54,50 @@ void init_tls(TLSDescriptor &tls_descriptor) {
   }
 
   // We will assume the alignment is always a power of two.
-  uintptr_t tlsSize = app.tls.size & -app.tls.align;
-  if (tlsSize != app.tls.size)
-    tlsSize += app.tls.align;
+  uintptr_t tls_size = app.tls.size & -app.tls.align;
+  if (tls_size != app.tls.size)
+    tls_size += app.tls.align;
 
   // Per the x86_64 TLS ABI, the entry pointed to by the thread pointer is the
   // address of the TLS block. So, we add more size to accomodate this address
   // entry.
   // We also need to include space for the stack canary. The canary is at
   // offset 0x28 (40) and is of size uintptr_t.
-  uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t) + 40;
+  uintptr_t tls_size_with_addr = tls_size + sizeof(uintptr_t) + 40;
 
   // We cannot call the mmap function here as the functions set errno on
   // failure. Since errno is implemented via a thread local variable, we cannot
   // use errno before TLS is setup.
-  long mmapRetVal = LIBC_NAMESPACE::syscall_impl<long>(
-      mmapSyscallNumber, nullptr, tlsSizeWithAddr, PROT_READ | PROT_WRITE,
+  long mmap_retval = LIBC_NAMESPACE::syscall_impl<long>(
+      MMAP_SYSCALL_NUMBER, nullptr, tls_size_with_addr, PROT_READ | PROT_WRITE,
       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   // We cannot check the return value with MAP_FAILED as that is the return
   // of the mmap function and not the mmap syscall.
-  if (mmapRetVal < 0 && static_cast<uintptr_t>(mmapRetVal) > -app.pageSize)
+  if (mmap_retval < 0 && static_cast<uintptr_t>(mmap_retval) > -app.page_size)
     LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 1);
-  uintptr_t *tlsAddr = reinterpret_cast<uintptr_t *>(mmapRetVal);
+  uintptr_t *tls_addr = reinterpret_cast<uintptr_t *>(mmap_retval);
 
   // x86_64 TLS faces down from the thread pointer with the first entry
   // pointing to the address of the first real TLS byte.
-  uintptr_t endPtr = reinterpret_cast<uintptr_t>(tlsAddr) + tlsSize;
-  *reinterpret_cast<uintptr_t *>(endPtr) = endPtr;
+  uintptr_t end_ptr = reinterpret_cast<uintptr_t>(tls_addr) + tls_size;
+  *reinterpret_cast<uintptr_t *>(end_ptr) = end_ptr;
 
-  LIBC_NAMESPACE::inline_memcpy(reinterpret_cast<char *>(tlsAddr),
+  LIBC_NAMESPACE::inline_memcpy(reinterpret_cast<char *>(tls_addr),
                                 reinterpret_cast<const char *>(app.tls.address),
                                 app.tls.init_size);
-  uintptr_t *stackGuardAddr = reinterpret_cast<uintptr_t *>(endPtr + 40);
+  uintptr_t *stack_guard_addr = reinterpret_cast<uintptr_t *>(end_ptr + 40);
   // Setting the stack guard to a random value.
   // We cannot call the get_random function here as the function sets errno on
   // failure. Since errno is implemented via a thread local variable, we cannot
   // use errno before TLS is setup.
-  ssize_t stackGuardRetVal = LIBC_NAMESPACE::syscall_impl<ssize_t>(
-      SYS_getrandom, reinterpret_cast<long>(stackGuardAddr), sizeof(uint64_t),
+  ssize_t stack_guard_retval = LIBC_NAMESPACE::syscall_impl<ssize_t>(
+      SYS_getrandom, reinterpret_cast<long>(stack_guard_addr), sizeof(uint64_t),
       0);
-  if (stackGuardRetVal < 0)
+  if (stack_guard_retval < 0)
     LIBC_NAMESPACE::syscall_impl(SYS_exit, 1);
 
-  tls_descriptor = {tlsSizeWithAddr, uintptr_t(tlsAddr), endPtr};
+  tls_descriptor = {tls_size_with_addr, reinterpret_cast<uintptr_t>(tls_addr),
+                    end_ptr};
   return;
 }
 
@@ -181,7 +182,7 @@ extern "C" void _start() {
   // value. We step over it (the "+ 1" below) to get to the env values.
   uint64_t *env_ptr = app.args->argv + app.args->argc + 1;
   uint64_t *env_end_marker = env_ptr;
-  app.envPtr = env_ptr;
+  app.env_ptr = env_ptr;
   while (*env_end_marker)
     ++env_end_marker;
 
@@ -190,19 +191,19 @@ extern "C" void _start() {
 
   // After the env array, is the aux-vector. The end of the aux-vector is
   // denoted by an AT_NULL entry.
-  Elf64_Phdr *programHdrTable = nullptr;
-  uintptr_t programHdrCount;
+  Elf64_Phdr *program_hdr_table = nullptr;
+  uintptr_t program_hdr_count = 0;
   for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
        aux_entry->type != AT_NULL; ++aux_entry) {
     switch (aux_entry->type) {
     case AT_PHDR:
-      programHdrTable = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
+      program_hdr_table = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
       break;
     case AT_PHNUM:
-      programHdrCount = aux_entry->value;
+      program_hdr_count = aux_entry->value;
       break;
     case AT_PAGESZ:
-      app.pageSize = aux_entry->value;
+      app.page_size = aux_entry->value;
       break;
     default:
       break; // TODO: Read other useful entries from the aux vector.
@@ -210,8 +211,8 @@ extern "C" void _start() {
   }
 
   app.tls.size = 0;
-  for (uintptr_t i = 0; i < programHdrCount; ++i) {
-    Elf64_Phdr *phdr = programHdrTable + i;
+  for (uintptr_t i = 0; i < program_hdr_count; ++i) {
+    Elf64_Phdr *phdr = program_hdr_table + i;
     if (phdr->p_type != PT_TLS)
       continue;
     // TODO: p_vaddr value has to be adjusted for static-pie executables.

>From 1a576db89a7c31caf8e80f0ac9615f4663020f9e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 1 Dec 2023 21:57:39 -0500
Subject: [PATCH 2/2] [libc][WIP] try fix getting page size from sysconf

---
 libc/config/linux/aarch64/entrypoints.txt |   6 +
 libc/config/linux/app.h                   |  33 +++--
 libc/config/linux/arm/entrypoints.txt     |   6 +
 libc/config/linux/riscv/entrypoints.txt   |   6 +
 libc/config/linux/x86_64/entrypoints.txt  |   6 +
 libc/src/sys/CMakeLists.txt               |   2 +
 libc/src/sys/auxv/CMakeLists.txt          |  10 ++
 libc/src/sys/auxv/getauxval.h             |  20 +++
 libc/src/sys/auxv/linux/CMakeLists.txt    |  18 +++
 libc/src/sys/auxv/linux/getauxval.cpp     | 141 ++++++++++++++++++++++
 libc/src/sys/prctl/CMakeLists.txt         |  10 ++
 libc/src/sys/prctl/linux/CMakeLists.txt   |  12 ++
 libc/src/sys/prctl/linux/prctl.cpp        |  30 +++++
 libc/src/sys/prctl/prctl.h                |  21 ++++
 libc/src/unistd/linux/CMakeLists.txt      |   2 +
 libc/src/unistd/linux/sysconf.cpp         |  11 +-
 libc/startup/linux/aarch64/start.cpp      |  17 +--
 libc/startup/linux/riscv/start.cpp        |  17 +--
 libc/startup/linux/x86_64/start.cpp       |  17 +--
 19 files changed, 335 insertions(+), 50 deletions(-)
 create mode 100644 libc/src/sys/auxv/CMakeLists.txt
 create mode 100644 libc/src/sys/auxv/getauxval.h
 create mode 100644 libc/src/sys/auxv/linux/CMakeLists.txt
 create mode 100644 libc/src/sys/auxv/linux/getauxval.cpp
 create mode 100644 libc/src/sys/prctl/CMakeLists.txt
 create mode 100644 libc/src/sys/prctl/linux/CMakeLists.txt
 create mode 100644 libc/src/sys/prctl/linux/prctl.cpp
 create mode 100644 libc/src/sys/prctl/prctl.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ba3a7c557964889..37b50b7ad62c178 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -166,6 +166,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/auxv.h entrypoints
+    libc.src.sys.auxv.getauxval
+
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/config/linux/app.h b/libc/config/linux/app.h
index 0d2f9475c10db64..f805ab9cd3dfb2d 100644
--- a/libc/config/linux/app.h
+++ b/libc/config/linux/app.h
@@ -9,8 +9,10 @@
 #ifndef LLVM_LIBC_CONFIG_LINUX_APP_H
 #define LLVM_LIBC_CONFIG_LINUX_APP_H
 
+#include "src/__support/macros/attributes.h"
 #include "src/__support/macros/properties/architectures.h"
 
+#include <linux/auxvec.h>
 #include <stdint.h>
 
 namespace LIBC_NAMESPACE {
@@ -18,21 +20,21 @@ namespace LIBC_NAMESPACE {
 // Data structure to capture properties of the linux/ELF TLS image.
 struct TLSImage {
   // The load address of the TLS.
-  uintptr_t address;
+  uintptr_t address = 0;
 
   // The byte size of the TLS image consisting of both initialized and
   // uninitialized memory. In ELF executables, it is size of .tdata + size of
   // .tbss. Put in another way, it is the memsz field of the PT_TLS header.
-  uintptr_t size;
+  uintptr_t size = 0;
 
   // The byte size of initialized memory in the TLS image. In ELF exectubles,
   // this is the size of .tdata. Put in another way, it is the filesz of the
   // PT_TLS header.
-  uintptr_t init_size;
+  uintptr_t init_size = 0;
 
   // The alignment of the TLS layout. It assumed that the alignment
   // value is a power of 2.
-  uintptr_t align;
+  uintptr_t align = 0;
 };
 
 #if defined(LIBC_TARGET_ARCH_IS_X86_64) ||                                     \
@@ -49,11 +51,19 @@ typedef uintptr_t ArgcType;
 typedef uintptr_t ArgVEntryType;
 
 typedef uintptr_t EnvironType;
-typedef uintptr_t AuxEntryType;
 #else
 #error "argc and argv types are not defined for the target platform."
 #endif
 
+// According the manpage associated to /proc/<pid>/auxv:
+// ... The format is one unsigned long ID plus one unsigned long
+// value for each entry ...
+// https://man7.org/linux/man-pages/man5/proc.5.html
+struct AuxEntryType {
+  unsigned long id;
+  unsigned long value;
+};
+
 struct Args {
   ArgcType argc;
 
@@ -69,18 +79,21 @@ struct Args {
 // Data structure which captures properties of a linux application.
 struct AppProperties {
   // Page size used for the application.
-  uintptr_t page_size;
+  uintptr_t page_size = 0;
 
-  Args *args;
+  Args *args = nullptr;
 
   // The properties of an application's TLS image.
-  TLSImage tls;
+  TLSImage tls{};
 
   // Environment data.
-  EnvironType *env_ptr;
+  EnvironType *env_ptr = nullptr;
+
+  // Auxiliary vector data.
+  const AuxEntryType *auxv_ptr = nullptr;
 };
 
-extern AppProperties app;
+LIBC_INLINE_VAR AppProperties app{};
 
 // The descriptor of a thread's TLS area.
 struct TLSDescriptor {
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index b7783ace90a886d..8955cbfa4708581 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -92,6 +92,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     # sys/mman.h entrypoints
     libc.src.sys.mman.mmap
     libc.src.sys.mman.munmap
+
+    # sys/auxv.h entrypoints
+    libc.src.sys.auxv.getauxval
+
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 63c1f9227f91ce3..aa6a999aad02779 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -172,6 +172,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/auxv.h entrypoints
+    libc.src.sys.auxv.getauxval
+
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index eb5457678e99091..d45caf7c056067e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -175,6 +175,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/auxv.h entrypoints
+    libc.src.sys.auxv.getauxval
+
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index bf869ddc6a23cd4..8bb719713d2bffd 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -7,3 +7,5 @@ add_subdirectory(sendfile)
 add_subdirectory(stat)
 add_subdirectory(utsname)
 add_subdirectory(wait)
+add_subdirectory(auxv)
+add_subdirectory(prctl)
\ No newline at end of file
diff --git a/libc/src/sys/auxv/CMakeLists.txt b/libc/src/sys/auxv/CMakeLists.txt
new file mode 100644
index 000000000000000..45ff23f2c7d437f
--- /dev/null
+++ b/libc/src/sys/auxv/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  getauxval
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.getauxval
+)
\ No newline at end of file
diff --git a/libc/src/sys/auxv/getauxval.h b/libc/src/sys/auxv/getauxval.h
new file mode 100644
index 000000000000000..ce05f2624826910
--- /dev/null
+++ b/libc/src/sys/auxv/getauxval.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for getauxval ----------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_AUXV_GETAUXVAL_H
+#define LLVM_LIBC_SRC_SYS_AUXV_GETAUXVAL_H
+
+#include <sys/auxv.h>
+
+namespace LIBC_NAMESPACE {
+
+unsigned long getauxval(unsigned long id);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_AUXV_GETAUXVAL_H
diff --git a/libc/src/sys/auxv/linux/CMakeLists.txt b/libc/src/sys/auxv/linux/CMakeLists.txt
new file mode 100644
index 000000000000000..99f8d80ceddaaa1
--- /dev/null
+++ b/libc/src/sys/auxv/linux/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_entrypoint_object(
+  getauxval
+  SRCS
+    getauxval.cpp
+  HDRS
+    ../getauxval.h
+  DEPENDS
+    libc.include.sys_auxv
+    libc.src.errno.errno
+    libc.src.fcntl.open
+    libc.src.unistd.read
+    libc.src.unistd.close
+    libc.src.sys.prctl.prctl
+    libc.src.sys.mman.mmap
+    libc.src.sys.mman.munmap
+    libc.config.linux.app_h
+    libc.src.__support.macros.optimization
+)
\ No newline at end of file
diff --git a/libc/src/sys/auxv/linux/getauxval.cpp b/libc/src/sys/auxv/linux/getauxval.cpp
new file mode 100644
index 000000000000000..ab24e6ba61a2af0
--- /dev/null
+++ b/libc/src/sys/auxv/linux/getauxval.cpp
@@ -0,0 +1,141 @@
+//===---------- Linux implementation of the getauxval function ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/auxv/getauxval.h"
+#include "config/linux/app.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/optimization.h"
+#include "src/errno/libc_errno.h"
+#include "src/fcntl/open.h"
+#include "src/sys/mman/mmap.h"
+#include "src/sys/mman/munmap.h"
+#include "src/sys/prctl/prctl.h"
+#include "src/unistd/close.h"
+#include "src/unistd/read.h"
+
+#include <linux/auxvec.h> // AT_NULL
+#include <sys/mman.h>     // MAP_FAILED, MAP_PRIVATE, MAP_ANONYMOUS
+
+namespace LIBC_NAMESPACE {
+
+constexpr size_t AUXV_MMAP_SIZE = sizeof(AuxEntryType) * 64;
+
+struct ErrorNo {
+  ErrorNo() : errno_backup(libc_errno), failure(false) {}
+  ~ErrorNo() { libc_errno = failure ? ENOENT : errno_backup; }
+  void mark_failure() { failure = true; }
+  int errno_backup;
+  bool failure;
+};
+
+struct TempAuxv {
+  TempAuxv() : ptr(nullptr) {}
+  ~TempAuxv() {
+    if (ptr != nullptr)
+      munmap(ptr, AUXV_MMAP_SIZE);
+  }
+  AuxEntryType *ptr;
+};
+
+struct TempFD {
+  TempFD(const char *path) : fd(open(path, O_RDONLY | O_CLOEXEC)) {}
+  ~TempFD() {
+    if (fd >= 0)
+      close(fd);
+  }
+  operator int() const { return fd; }
+  int fd;
+};
+
+static AuxEntryType read_entry(int fd) {
+  AuxEntryType buf;
+  ssize_t size = sizeof(AuxEntryType);
+  while (size > 0) {
+    ssize_t ret = read(fd, &buf, size);
+    if (ret < 0) {
+      if (libc_errno == EINTR)
+        continue;
+      buf.id = AT_NULL;
+      buf.value = AT_NULL;
+      break;
+    }
+    size -= ret;
+  }
+  return buf;
+}
+
+LLVM_LIBC_FUNCTION(unsigned long, getauxval, (unsigned long id)) {
+  // if llvm-libc's loader is applied, app.auxv_ptr should have been
+  // initialized, then we can directly get the auxillary vector
+  const AuxEntryType *auxv_ptr = app.auxv_ptr;
+  ErrorNo errno_holder;
+  TempAuxv temp_auxv;
+
+  // Compatible layer for the overlay mode.
+  // first check if PR_GET_AUXV is supported. Unfortunately, this is not
+  // supported until Linux 6.0+. We check this syscall first since it may be
+  // the case that /proc is not mounted.
+#ifdef PR_GET_AUXV
+  do {
+    if (LIBC_UNLIKELY(auxv_ptr == nullptr)) {
+      // no need to backup errno: once it has error, we will modify it
+      void *ptr = mmap(nullptr, AUXV_MMAP_SIZE, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      if (LIBC_UNLIKELY(ptr == MAP_FAILED))
+        break;
+
+      temp_auxv.ptr = reinterpret_cast<AuxEntryType *>(ptr);
+      for (size_t i = 0; i < AUXV_MMAP_SIZE / sizeof(AuxEntryType); ++i) {
+        temp_auxv.ptr[i].id = AT_NULL;
+        temp_auxv.ptr[i].value = AT_NULL;
+      }
+
+      // We keeps the last entry to be AT_NULL, so we can always terminate the
+      // loop.
+      int ret =
+          prctl(PR_GET_AUXV, reinterpret_cast<unsigned long>(temp_auxv.ptr),
+                AUXV_MMAP_SIZE - sizeof(AuxEntryType), 0, 0);
+      if (ret < 0)
+        break;
+
+      auxv_ptr = temp_auxv.ptr;
+    }
+  } while (0);
+#endif
+
+  if (LIBC_LIKELY(auxv_ptr != nullptr)) {
+    for (; auxv_ptr->id != AT_NULL; ++auxv_ptr) {
+      if (auxv_ptr->id == id)
+        return auxv_ptr->value;
+    }
+    errno_holder.mark_failure();
+    return 0;
+  }
+
+  // now attempt to read from /proc/self/auxv
+  do {
+    TempFD fd{"/proc/self/auxv"};
+    if (fd < 0)
+      break;
+
+    while (true) {
+      AuxEntryType buf = read_entry(fd);
+      if (buf.id == AT_NULL)
+        break;
+      if (buf.id == id)
+        return buf.value;
+    }
+
+  } while (0);
+
+  errno_holder.mark_failure();
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/prctl/CMakeLists.txt b/libc/src/sys/prctl/CMakeLists.txt
new file mode 100644
index 000000000000000..850e635066ad2d2
--- /dev/null
+++ b/libc/src/sys/prctl/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  prctl
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.prctl
+)
\ No newline at end of file
diff --git a/libc/src/sys/prctl/linux/CMakeLists.txt b/libc/src/sys/prctl/linux/CMakeLists.txt
new file mode 100644
index 000000000000000..9bd3a77a0d1c649
--- /dev/null
+++ b/libc/src/sys/prctl/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+  prctl
+  SRCS
+    prctl.cpp
+  HDRS
+    ../prctl.h
+  DEPENDS
+    libc.include.sys_prctl
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
\ No newline at end of file
diff --git a/libc/src/sys/prctl/linux/prctl.cpp b/libc/src/sys/prctl/linux/prctl.cpp
new file mode 100644
index 000000000000000..9ebc25a32337f6d
--- /dev/null
+++ b/libc/src/sys/prctl/linux/prctl.cpp
@@ -0,0 +1,30 @@
+//===---------- Linux implementation of the prctl function ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/prctl/prctl.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+
+#include "src/errno/libc_errno.h"
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, prctl,
+                   (int option, unsigned long arg2, unsigned long arg3,
+                    unsigned long arg4, unsigned long arg5)) {
+  long ret =
+      LIBC_NAMESPACE::syscall_impl(SYS_prctl, option, arg2, arg3, arg4, arg5);
+  if (ret < 0) {
+    libc_errno = static_cast<int>(-ret);
+    return -1;
+  }
+  return static_cast<int>(ret);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/prctl/prctl.h b/libc/src/sys/prctl/prctl.h
new file mode 100644
index 000000000000000..158739607e9f7de
--- /dev/null
+++ b/libc/src/sys/prctl/prctl.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for prctl --------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_PRCTL_PRCTL_H
+#define LLVM_LIBC_SRC_SYS_PRCTL_PRCTL_H
+
+#include <sys/prctl.h>
+
+namespace LIBC_NAMESPACE {
+
+int prctl(int option, unsigned long arg2, unsigned long arg3,
+          unsigned long arg4, unsigned long arg5);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_PRCTL_PRCTL_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 2507e1e9a9387ad..e37420beb0fc9f2 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -402,6 +402,8 @@ add_entrypoint_object(
   DEPENDS
     libc.include.unistd
     libc.src.errno.errno
+    libc.config.linux.app_h
+    libc.src.sys.auxv.getauxval
 )
 
 add_entrypoint_object(
diff --git a/libc/src/unistd/linux/sysconf.cpp b/libc/src/unistd/linux/sysconf.cpp
index b16e15551fc7889..73c470206ec87d8 100644
--- a/libc/src/unistd/linux/sysconf.cpp
+++ b/libc/src/unistd/linux/sysconf.cpp
@@ -8,10 +8,10 @@
 
 #include "src/unistd/sysconf.h"
 
+#include "config/linux/app.h"
 #include "src/__support/common.h"
-
 #include "src/errno/libc_errno.h"
-#include <linux/param.h> // For EXEC_PAGESIZE.
+#include "src/sys/auxv/getauxval.h"
 #include <unistd.h>
 
 namespace LIBC_NAMESPACE {
@@ -19,8 +19,11 @@ namespace LIBC_NAMESPACE {
 LLVM_LIBC_FUNCTION(long, sysconf, (int name)) {
   long ret = 0;
   if (name == _SC_PAGESIZE) {
-    // TODO: get this information from the auxvector.
-    return EXEC_PAGESIZE;
+    if (app.page_size)
+      return app.page_size;
+    int errno_backup = libc_errno;
+    ret = static_cast<long>(getauxval(AT_PAGESZ));
+    libc_errno = errno_backup;
   }
   // TODO: Complete the rest of the sysconf options.
   if (ret < 0) {
diff --git a/libc/startup/linux/aarch64/start.cpp b/libc/startup/linux/aarch64/start.cpp
index b5c426866b56d74..bcc65d6ad90bcea 100644
--- a/libc/startup/linux/aarch64/start.cpp
+++ b/libc/startup/linux/aarch64/start.cpp
@@ -15,7 +15,6 @@
 
 #include <arm_acle.h>
 
-#include <linux/auxvec.h>
 #include <linux/elf.h>
 #include <stdint.h>
 #include <sys/mman.h>
@@ -37,8 +36,6 @@ static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
 #error "mmap and mmap2 syscalls not available."
 #endif
 
-AppProperties app;
-
 static ThreadAttributes main_thread_attrib;
 
 void init_tls(TLSDescriptor &tls_descriptor) {
@@ -127,12 +124,6 @@ static void call_fini_array_callbacks() {
 
 using LIBC_NAMESPACE::app;
 
-// TODO: Would be nice to use the aux entry structure from elf.h when available.
-struct AuxEntry {
-  uint64_t type;
-  uint64_t value;
-};
-
 __attribute__((noinline)) static void do_start() {
   auto tid = LIBC_NAMESPACE::syscall_impl<long>(SYS_gettid);
   if (tid <= 0)
@@ -155,9 +146,11 @@ __attribute__((noinline)) static void do_start() {
   // denoted by an AT_NULL entry.
   Elf64_Phdr *program_hdr_table = nullptr;
   uintptr_t program_hdr_count;
-  for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
-       aux_entry->type != AT_NULL; ++aux_entry) {
-    switch (aux_entry->type) {
+  app.auxv_ptr = reinterpret_cast<const LIBC_NAMESPACE::AuxEntryType *>(
+      env_end_marker + 1);
+  for (const LIBC_NAMESPACE::AuxEntryType *aux_entry = app.auxv_ptr;
+       aux_entry->id != AT_NULL; ++aux_entry) {
+    switch (aux_entry->id) {
     case AT_PHDR:
       program_hdr_table = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
       break;
diff --git a/libc/startup/linux/riscv/start.cpp b/libc/startup/linux/riscv/start.cpp
index bf04be5ad14ad1d..c93c2af702ab269 100644
--- a/libc/startup/linux/riscv/start.cpp
+++ b/libc/startup/linux/riscv/start.cpp
@@ -13,7 +13,6 @@
 #include "src/stdlib/exit.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 
-#include <linux/auxvec.h>
 #include <linux/elf.h>
 #include <stdint.h>
 #include <sys/mman.h>
@@ -32,8 +31,6 @@ static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
 #error "mmap and mmap2 syscalls not available."
 #endif
 
-AppProperties app;
-
 static ThreadAttributes main_thread_attrib;
 
 void init_tls(TLSDescriptor &tls_descriptor) {
@@ -116,12 +113,6 @@ static void call_fini_array_callbacks() {
 
 using LIBC_NAMESPACE::app;
 
-// TODO: Would be nice to use the aux entry structure from elf.h when available.
-struct AuxEntry {
-  LIBC_NAMESPACE::AuxEntryType type;
-  LIBC_NAMESPACE::AuxEntryType value;
-};
-
 #if defined(LIBC_TARGET_ARCH_IS_X86_64) ||                                     \
     defined(LIBC_TARGET_ARCH_IS_AARCH64) ||                                    \
     defined(LIBC_TARGET_ARCH_IS_RISCV64)
@@ -158,9 +149,11 @@ __attribute__((noinline)) static void do_start() {
   // denoted by an AT_NULL entry.
   PgrHdrTableType *program_hdr_table = nullptr;
   uintptr_t program_hdr_count;
-  for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
-       aux_entry->type != AT_NULL; ++aux_entry) {
-    switch (aux_entry->type) {
+  app.auxv_ptr = reinterpret_cast<const LIBC_NAMESPACE::AuxEntryType *>(
+      env_end_marker + 1);
+  for (const LIBC_NAMESPACE::AuxEntryType *aux_entry = app.auxv_ptr;
+       aux_entry->id != AT_NULL; ++aux_entry) {
+    switch (aux_entry->id) {
     case AT_PHDR:
       program_hdr_table = reinterpret_cast<PgrHdrTableType *>(aux_entry->value);
       break;
diff --git a/libc/startup/linux/x86_64/start.cpp b/libc/startup/linux/x86_64/start.cpp
index bc1b4f0487f316a..b5f0f3ca81d4cd2 100644
--- a/libc/startup/linux/x86_64/start.cpp
+++ b/libc/startup/linux/x86_64/start.cpp
@@ -16,7 +16,6 @@
 #include "src/string/memory_utils/inline_memcpy.h"
 
 #include <asm/prctl.h>
-#include <linux/auxvec.h>
 #include <linux/elf.h>
 #include <stdint.h>
 #include <sys/mman.h>
@@ -40,8 +39,6 @@ static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
 #error "mmap and mmap2 syscalls not available."
 #endif
 
-AppProperties app;
-
 static ThreadAttributes main_thread_attrib;
 
 // TODO: The function is x86_64 specific. Move it to config/linux/app.h
@@ -145,12 +142,6 @@ static void call_fini_array_callbacks() {
 
 using LIBC_NAMESPACE::app;
 
-// TODO: Would be nice to use the aux entry structure from elf.h when available.
-struct AuxEntry {
-  uint64_t type;
-  uint64_t value;
-};
-
 extern "C" void _start() {
   // This TU is compiled with -fno-omit-frame-pointer. Hence, the previous value
   // of the base pointer is pushed on to the stack. So, we step over it (the
@@ -193,9 +184,11 @@ extern "C" void _start() {
   // denoted by an AT_NULL entry.
   Elf64_Phdr *program_hdr_table = nullptr;
   uintptr_t program_hdr_count = 0;
-  for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
-       aux_entry->type != AT_NULL; ++aux_entry) {
-    switch (aux_entry->type) {
+  app.auxv_ptr = reinterpret_cast<const LIBC_NAMESPACE::AuxEntryType *>(
+      env_end_marker + 1);
+  for (const LIBC_NAMESPACE::AuxEntryType *aux_entry = app.auxv_ptr;
+       aux_entry->id != AT_NULL; ++aux_entry) {
+    switch (aux_entry->id) {
     case AT_PHDR:
       program_hdr_table = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
       break;



More information about the libc-commits mailing list