[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