From ce5a19235b90891394d3ff3f9af7359de8560933 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 9 May 2024 04:26:55 -0400 Subject: [PATCH 1/6] [libc] implement vdso --- libc/src/__support/OSUtil/CMakeLists.txt | 8 + libc/src/__support/OSUtil/fuchsia/vdso.h | 12 ++ .../src/__support/OSUtil/linux/CMakeLists.txt | 16 ++ .../OSUtil/linux/aarch64/CMakeLists.txt | 9 + .../src/__support/OSUtil/linux/aarch64/vdso.h | 47 +++++ .../__support/OSUtil/linux/arm/CMakeLists.txt | 9 + libc/src/__support/OSUtil/linux/arm/vdso.h | 36 ++++ .../OSUtil/linux/riscv/CMakeLists.txt | 9 + libc/src/__support/OSUtil/linux/riscv/vdso.h | 55 +++++ libc/src/__support/OSUtil/linux/vdso.cpp | 198 ++++++++++++++++++ libc/src/__support/OSUtil/linux/vdso.h | 29 +++ .../OSUtil/linux/x86_64/CMakeLists.txt | 9 + libc/src/__support/OSUtil/linux/x86_64/vdso.h | 41 ++++ libc/src/__support/OSUtil/vdso.h | 18 ++ 14 files changed, 496 insertions(+) create mode 100644 libc/src/__support/OSUtil/fuchsia/vdso.h create mode 100644 libc/src/__support/OSUtil/linux/aarch64/vdso.h create mode 100644 libc/src/__support/OSUtil/linux/arm/vdso.h create mode 100644 libc/src/__support/OSUtil/linux/riscv/vdso.h create mode 100644 libc/src/__support/OSUtil/linux/vdso.cpp create mode 100644 libc/src/__support/OSUtil/linux/vdso.h create mode 100644 libc/src/__support/OSUtil/linux/x86_64/vdso.h create mode 100644 libc/src/__support/OSUtil/vdso.h diff --git a/libc/src/__support/OSUtil/CMakeLists.txt b/libc/src/__support/OSUtil/CMakeLists.txt index 94d1042ccbb4a..78285c960c0a4 100644 --- a/libc/src/__support/OSUtil/CMakeLists.txt +++ b/libc/src/__support/OSUtil/CMakeLists.txt @@ -15,3 +15,11 @@ add_object_library( DEPENDS ${target_os_util} ) + +add_header_library( + vdso + HDRS + vdso.h + DEPENDS + .${LIBC_TARGET_OS}.vdso +) diff --git a/libc/src/__support/OSUtil/fuchsia/vdso.h b/libc/src/__support/OSUtil/fuchsia/vdso.h new file mode 100644 index 0000000000000..177d29f879693 --- /dev/null +++ b/libc/src/__support/OSUtil/fuchsia/vdso.h @@ -0,0 +1,12 @@ +//===------------- Fuchsia VDSO Header --------------------------*- 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___SUPPORT_OSUTIL_FUCHSIA_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_FUCHSIA_VDSO_H +/// TODO: implement fuchsia VDSO +/// https://fuchsia.dev/fuchsia-src/concepts/kernel/vdso +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_FUCHSIA_VDSO_H diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt index 239d115704927..e7411c14711d2 100644 --- a/libc/src/__support/OSUtil/linux/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt @@ -16,3 +16,19 @@ add_object_library( libc.src.__support.common libc.src.__support.CPP.string_view ) + +add_object_library( + vdso + HDRS + vdso.h + SRCS + vdso.cpp + DEPENDS + .${LIBC_TARGET_ARCHITECTURE}.vdso + libc.src.__support.CPP.array + libc.src.__support.CPP.string_view + libc.src.__support.threads.callonce + libc.src.__support.threads.linux.futex_word_type + libc.src.errno.errno + libc.src.sys.auxv.getauxval +) diff --git a/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt b/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt index eea9badc46cae..68ce1d74c2099 100644 --- a/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt @@ -5,3 +5,12 @@ add_header_library( DEPENDS libc.src.__support.common ) + +add_header_library( + vdso + HDRS + vdso.h + DEPENDS + libc.src.__support.common + libc.src.__support.CPP.string_view +) diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h new file mode 100644 index 0000000000000..55024e61ee914 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h @@ -0,0 +1,47 @@ +//===---------- aarch64 vdso configuration ------------------------* 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 +// +//===----------------------------------------------------------------------===// +#include "src/__support/CPP/string_view.h" +namespace LIBC_NAMESPACE { +namespace vdso { +// macro definitions +#define LIBC_VDSO_HAS_RT_SIGRETURN +#define LIBC_VDSO_HAS_GETTIMEOFDAY +#define LIBC_VDSO_HAS_CLOCK_GETTIME +#define LIBC_VDSO_HAS_CLOCK_GETRES + +// list of VDSO symbols +enum class VDSOSym { + RTSigReturn, + GetTimeOfDay, + ClockGetTime, + ClockGetRes, + VDSOSymCount +}; + +// translate VDSOSym to symbol names +LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) { + switch (sym) { + case VDSOSym::RTSigReturn: + return "__kernel_rt_sigreturn"; + case VDSOSym::GetTimeOfDay: + return "__kernel_gettimeofday"; + case VDSOSym::ClockGetTime: + return "__kernel_clock_gettime"; + case VDSOSym::ClockGetRes: + return "__kernel_clock_getres"; + default: + return ""; + } +} + +// symbol versions +LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { + return "LINUX_2.6.39"; +} +} // namespace vdso +} // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/OSUtil/linux/arm/CMakeLists.txt b/libc/src/__support/OSUtil/linux/arm/CMakeLists.txt index 733366f6d4a2e..36c991425e603 100644 --- a/libc/src/__support/OSUtil/linux/arm/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/arm/CMakeLists.txt @@ -5,3 +5,12 @@ add_header_library( DEPENDS libc.src.__support.common ) + +add_header_library( + vdso + HDRS + vdso.h + DEPENDS + libc.src.__support.common + libc.src.__support.CPP.string_view +) diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h new file mode 100644 index 0000000000000..5d9ff5d929ab6 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/arm/vdso.h @@ -0,0 +1,36 @@ +//===---------- arm vdso configuration ----------------------------* 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 +// +//===----------------------------------------------------------------------===// +#include "src/__support/CPP/string_view.h" +namespace LIBC_NAMESPACE { +namespace vdso { +// macro definitions +#define LIBC_VDSO_HAS_GETTIMEOFDAY +#define LIBC_VDSO_HAS_CLOCK_GETTIME + +// list of VDSO symbols +enum class VDSOSym { + GetTimeOfDay, + ClockGetTime, +}; + +// translate VDSOSym to symbol names +LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) { + switch (sym) { + case VDSOSym::GetTimeOfDay: + return "__vdso_gettimeofday"; + case VDSOSym::ClockGetTime: + return "__vdso_clock_gettime"; + } +} + +// symbol versions +LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { + return "LINUX_2.6"; +} +} // namespace vdso +} // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/OSUtil/linux/riscv/CMakeLists.txt b/libc/src/__support/OSUtil/linux/riscv/CMakeLists.txt index e271204f51982..b2e2401ece1ac 100644 --- a/libc/src/__support/OSUtil/linux/riscv/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/riscv/CMakeLists.txt @@ -5,3 +5,12 @@ add_header_library( DEPENDS libc.src.__support.common ) + +add_header_library( + vdso + HDRS + vdso.h + DEPENDS + libc.src.__support.common + libc.src.__support.CPP.string_view +) diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h new file mode 100644 index 0000000000000..394c06e6a5a72 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h @@ -0,0 +1,55 @@ +//===---------- RISC-V vdso configuration -------------------------* 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 +// +//===----------------------------------------------------------------------===// +#include "src/__support/CPP/string_view.h" +namespace LIBC_NAMESPACE { +namespace vdso { +// macro definitions +#define LIBC_VDSO_HAS_RT_SIGRETURN +#define LIBC_VDSO_HAS_GETTIMEOFDAY +#define LIBC_VDSO_HAS_CLOCK_GETTIME +#define LIBC_VDSO_HAS_CLOCK_GETRES +#define LIBC_VDSO_HAS_GETCPU +#define LIBC_VDSO_HAS_FLUSH_ICACHE + +// list of VDSO symbols +enum class VDSOSym { + RTSigReturn, + GetTimeOfDay, + ClockGetTime, + ClockGetRes, + GetCpu, + FlushICache, + VDSOSymCount +}; + +// translate VDSOSym to symbol names +LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) { + switch (sym) { + case VDSOSym::RTSigReturn: + return "__vdso_rt_sigreturn"; + case VDSOSym::GetTimeOfDay: + return "__vdso_gettimeofday"; + case VDSOSym::ClockGetTime: + return "__vdso_clock_gettime"; + case VDSOSym::ClockGetRes: + return "__vdso_clock_getres"; + case VDSOSym::GetCpu: + return "__vdso_getcpu"; + case VDSOSym::FlushICache: + return "__vdso_flush_icache"; + default: + return ""; + } +} + +// symbol versions +LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { + return "LINUX_4.15"; +} +} // namespace vdso +} // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp new file mode 100644 index 0000000000000..2b2c02ec69fef --- /dev/null +++ b/libc/src/__support/OSUtil/linux/vdso.cpp @@ -0,0 +1,198 @@ +//===------------- Linux VDSO Implementation --------------------*- 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 +// +//===----------------------------------------------------------------------===// +#include "src/__support/OSUtil/linux/vdso.h" +#include "src/__support/CPP/array.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/threads/callonce.h" +#include "src/__support/threads/linux/futex_word.h" +#include "src/errno/libc_errno.h" +#include "src/sys/auxv/getauxval.h" +#include +#include + +#ifndef ElfW +#if __POINTER_WIDTH__ == 32 +#define ElfW(type) Elf32_##type +#else +#define ElfW(type) Elf64_##type +#endif +#endif + +namespace LIBC_NAMESPACE { +namespace vdso { + +// See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html +struct Verdaux { + ElfW(Word) vda_name; /* Version or dependency names */ + ElfW(Word) vda_next; /* Offset in bytes to next verdaux + entry */ +}; +struct Verdef { + ElfW(Half) vd_version; /* Version revision */ + ElfW(Half) vd_flags; /* Version information */ + ElfW(Half) vd_ndx; /* Version Index */ + ElfW(Half) vd_cnt; /* Number of associated aux entries */ + ElfW(Word) vd_hash; /* Version name hash value */ + ElfW(Word) vd_aux; /* Offset in bytes to verdaux array */ + ElfW(Word) vd_next; /* Offset in bytes to next verdef + entry */ + Verdef *next() const { + if (vd_next == 0) + return nullptr; + return reinterpret_cast(reinterpret_cast(this) + + vd_next); + } + Verdaux *aux() const { + return reinterpret_cast(reinterpret_cast(this) + + vd_aux); + } +}; + +// version search procedure specified by +// https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symversion.html#SYMVERTBL +cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym, + const char *strtab, size_t idx) { + static constexpr ElfW(Half) VER_FLG_BASE = 0x1; + ElfW(Half) identifier = versym[idx] & 0x7FFF; + // iterate through all version definitions + for (Verdef *def = verdef; def != nullptr; def = def->next()) { + // skip if this is a file-level version + if (def->vd_flags & VER_FLG_BASE) + continue; + // check if the version identifier matches + if ((def->vd_ndx & 0x7FFF) == identifier) { + Verdaux *aux = def->aux(); + return strtab + aux->vda_name; + } + } + return ""; +} + +using VDSOArray = + cpp::array(VDSOSym::VDSOSymCount)>; + +static VDSOArray symbol_table; + +void *get_symbol(VDSOSym sym) { + // if sym is invalid, return nullptr + const size_t index = static_cast(sym); + if (index >= symbol_table.size()) + return nullptr; + + static FutexWordType once_flag = 0; + callonce(reinterpret_cast(&once_flag), [] { + // first clear the symbol table + for (auto &i : symbol_table) { + i = nullptr; + } + + // get the address of the VDSO, protect errno since getauxval may change it + int errno_backup = libc_errno; + uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR); + // Get the memory address of the vDSO ELF header. + auto vdso_ehdr = reinterpret_cast(vdso_ehdr_addr); + // leave the table unpopulated if we don't have vDSO + if (vdso_ehdr == nullptr) { + libc_errno = errno_backup; + return; + } + + // count entries + size_t symbol_count = 0; + // locate the section header inside the elf using the section header offset + auto vdso_shdr = + reinterpret_cast(vdso_ehdr_addr + vdso_ehdr->e_shoff); + // iterate all sections until we locate the dynamic symbol section + for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) { + if (vdso_shdr[i].sh_type == SHT_DYNSYM) { + // dynamic symbol section is a table section + // therefore, the number of entries can be computed as the ratio + // of the section size to the size of a single entry + symbol_count = vdso_shdr[i].sh_size / vdso_shdr[i].sh_entsize; + break; + } + } + + // early return if no symbol is found + if (symbol_count == 0) + return; + + // We need to find both the loadable segment and the dynamic linking of the + // vDSO. + auto vdso_addr = static_cast(-1); + ElfW(Dyn) *vdso_dyn = nullptr; + // compute vdso_phdr as the program header using the program header offset + ElfW(Phdr) *vdso_phdr = + reinterpret_cast(vdso_ehdr_addr + vdso_ehdr->e_phoff); + // iterate through all the program headers until we get the desired pieces + for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) { + if (vdso_phdr[i].p_type == PT_DYNAMIC) + vdso_dyn = reinterpret_cast(vdso_ehdr_addr + + vdso_phdr[i].p_offset); + + if (vdso_phdr[i].p_type == PT_LOAD) + vdso_addr = + vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr; + + if (vdso_addr && vdso_dyn) + break; + } + // early return if either the dynamic linking or the loadable segment is not + // found + if (vdso_dyn == nullptr || vdso_addr == static_cast(-1)) + return; + + // now, locate several more tables inside the dynmaic linking section + const char *strtab = nullptr; + ElfW(Sym) *symtab = nullptr; + ElfW(Half) *versym = nullptr; + Verdef *verdef = nullptr; + for (ElfW(Dyn) *d = vdso_dyn; d->d_tag != DT_NULL; ++d) { + switch (d->d_tag) { + case DT_STRTAB: + strtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + break; + case DT_SYMTAB: + symtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + break; + case DT_VERSYM: + versym = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + break; + case DT_VERDEF: + verdef = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + break; + } + if (strtab && symtab && versym && verdef) { + break; + } + } + if (strtab == nullptr || symtab == nullptr) + return; + + for (size_t i = 0; i < symbol_table.size(); ++i) { + for (size_t j = 0; j < symbol_count; ++j) { + auto sym = static_cast(i); + if (symbol_name(sym) == strtab + symtab[j].st_name) { + // we find a symbol with desired name + // now we need to check if it has the right version + if (versym && verdef) + if (symbol_version(sym) != find_version(verdef, versym, strtab, j)) + continue; + + // put the symbol address into the symbol table + symbol_table[i] = + reinterpret_cast(vdso_addr + symtab[j].st_value); + } + } + } + }); + + return symbol_table[index]; +} +} // namespace vdso +} // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h new file mode 100644 index 0000000000000..2d71db13303f0 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/vdso.h @@ -0,0 +1,29 @@ +//===------------- Linux VDSO Header ----------------------------*- 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___SUPPORT_OSUTIL_LINUX_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H +#include "src/__support/common.h" +#include "src/__support/macros/properties/architectures.h" + +#if defined(LIBC_TARGET_ARCH_IS_X86) +#include "x86_64/vdso.h" +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) +#include "aarch64/vdso.h" +#elif defined(LIBC_TARGET_ARCH_IS_ARM) +#include "arm/vdso.h" +#elif defined(LIBC_TARGET_ARCH_IS_RISCV) +#include "riscv/vdso.h" +#endif + +namespace LIBC_NAMESPACE { +namespace vdso { +void *get_symbol(VDSOSym); +} // namespace vdso + +} // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H diff --git a/libc/src/__support/OSUtil/linux/x86_64/CMakeLists.txt b/libc/src/__support/OSUtil/linux/x86_64/CMakeLists.txt index a7f2d74e6353e..cb5938ef94d7d 100644 --- a/libc/src/__support/OSUtil/linux/x86_64/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/x86_64/CMakeLists.txt @@ -5,3 +5,12 @@ add_header_library( DEPENDS libc.src.__support.common ) + +add_header_library( + vdso + HDRS + vdso.h + DEPENDS + libc.src.__support.common + libc.src.__support.CPP.string_view +) diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h new file mode 100644 index 0000000000000..13b8e3d8cc6f4 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h @@ -0,0 +1,41 @@ +//===---------- x86/x86_64 vdso configuration ---------------------* 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 +// +//===----------------------------------------------------------------------===// +#include "src/__support/CPP/string_view.h" +namespace LIBC_NAMESPACE { +namespace vdso { +// macro definitions +#define LIBC_VDSO_HAS_CLOCK_GETTIME +#define LIBC_VDSO_HAS_GETCPU +#define LIBC_VDSO_HAS_GETTIMEOFDAY +#define LIBC_VDSO_HAS_TIME + +// list of VDSO symbols +enum class VDSOSym { ClockGetTime, GetCpu, GetTimeOfDay, Time, VDSOSymCount }; + +// translate VDSOSym to symbol names +LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) { + switch (sym) { + case VDSOSym::ClockGetTime: + return "__vdso_clock_gettime"; + case VDSOSym::GetCpu: + return "__vdso_getcpu"; + case VDSOSym::GetTimeOfDay: + return "__vdso_gettimeofday"; + case VDSOSym::Time: + return "__vdso_time"; + default: + return ""; + } +} + +// symbol versions +LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { + return "LINUX_2.6"; +} +} // namespace vdso +} // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/OSUtil/vdso.h b/libc/src/__support/OSUtil/vdso.h new file mode 100644 index 0000000000000..93bbc98da19b4 --- /dev/null +++ b/libc/src/__support/OSUtil/vdso.h @@ -0,0 +1,18 @@ +//===--------------- Virtual DSO Support ------------------------*- 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___SUPPORT_OSUTIL_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_VDSO_H + +#if defined(__linux__) +#include "linux/vdso.h" +#elif defined(__Fuchsia__) +#include "fuchsia/vdso.h" +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_VDSO_H From 4d4ca8f717c7ba30ed06e594a07cc44470b5fdc7 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 9 May 2024 12:18:53 -0400 Subject: [PATCH 2/6] [libc] add simple tests for vDSO symbols --- .../src/__support/OSUtil/linux/CMakeLists.txt | 9 +++++ .../src/__support/OSUtil/linux/vdso_test.cpp | 33 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 libc/test/src/__support/OSUtil/linux/vdso_test.cpp diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt index bfb072c03e971..29c95ea27d70b 100644 --- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt +++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt @@ -1,3 +1,12 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}) add_subdirectory(${LIBC_TARGET_ARCHITECTURE}) endif() + +add_libc_test( + vdso_test + SUITE libc-osutil-tests + SRCS vdso_test.cpp + DEPENDS + libc.src.__support.OSUtil.vdso + libc.include.llvm-libc-types.struct_timeval # TODO: update this to proxy header once available +) diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp new file mode 100644 index 0000000000000..f1148daaccc1a --- /dev/null +++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp @@ -0,0 +1,33 @@ +//===-- Unittests for x86_64 syscalls -------------------------------------===// +// +// 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 "llvm-libc-types/struct_timeval.h" +#include "src/__support/OSUtil/vdso.h" +#include "test/UnitTest/Test.h" + +namespace LIBC_NAMESPACE { +TEST(LlvmLibcOSUtilVDSOTest, SymbolsDefined) { + // for now, we simply test all symbols are provided. + for (size_t i = 0; i < static_cast(vdso::VDSOSym::VDSOSymCount); ++i) + EXPECT_NE(vdso::get_symbol(static_cast(i)), + static_cast(nullptr)); +} + +#ifdef LIBC_VDSO_HAS_GETTIMEOFDAY +TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) { + using FuncTy = int (*)(timeval *, struct timezone *); + auto func = + reinterpret_cast(vdso::get_symbol(vdso::VDSOSym::GetTimeOfDay)); + timeval tv; + EXPECT_EQ(func(&tv, nullptr), 0); + // hopefully people are not building time machines using our libc. + EXPECT_GT(tv.tv_sec, static_cast(0)); +} +#endif + +} // namespace LIBC_NAMESPACE From dfcd2e64f628935f70c4247b9432bc4049499ef9 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 9 May 2024 12:23:42 -0400 Subject: [PATCH 3/6] [libc] fix header --- libc/test/src/__support/OSUtil/linux/vdso_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp index f1148daaccc1a..6dc35589938f6 100644 --- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp +++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp @@ -1,4 +1,4 @@ -//===-- Unittests for x86_64 syscalls -------------------------------------===// +//===-- Unittests for VDSO ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From 1466198cfce66c06cf0119db32f65c7b4f5c4d7f Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 9 May 2024 14:04:52 -0400 Subject: [PATCH 4/6] [libc] add missing header guards --- libc/src/__support/OSUtil/linux/aarch64/vdso.h | 3 +++ libc/src/__support/OSUtil/linux/arm/vdso.h | 3 +++ libc/src/__support/OSUtil/linux/riscv/vdso.h | 3 +++ libc/src/__support/OSUtil/linux/x86_64/vdso.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h index 55024e61ee914..14783b065069a 100644 --- a/libc/src/__support/OSUtil/linux/aarch64/vdso.h +++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h @@ -5,6 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_AARCH64_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_AARCH64_VDSO_H #include "src/__support/CPP/string_view.h" namespace LIBC_NAMESPACE { namespace vdso { @@ -45,3 +47,4 @@ LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { } } // namespace vdso } // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_AARCH64_VDSO_H diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h index 5d9ff5d929ab6..e1495df89d9ad 100644 --- a/libc/src/__support/OSUtil/linux/arm/vdso.h +++ b/libc/src/__support/OSUtil/linux/arm/vdso.h @@ -5,6 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_ARM_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_ARM_VDSO_H #include "src/__support/CPP/string_view.h" namespace LIBC_NAMESPACE { namespace vdso { @@ -34,3 +36,4 @@ LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { } } // namespace vdso } // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_ARM_VDSO_H diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h index 394c06e6a5a72..41681856037c8 100644 --- a/libc/src/__support/OSUtil/linux/riscv/vdso.h +++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h @@ -5,6 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_RISCV_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_RISCV_VDSO_H #include "src/__support/CPP/string_view.h" namespace LIBC_NAMESPACE { namespace vdso { @@ -53,3 +55,4 @@ LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { } } // namespace vdso } // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_RISCV_VDSO_H diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h index 13b8e3d8cc6f4..37580b0201f2c 100644 --- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h +++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h @@ -5,6 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_X86_64_VDSO_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_X86_64_VDSO_H #include "src/__support/CPP/string_view.h" namespace LIBC_NAMESPACE { namespace vdso { @@ -39,3 +41,4 @@ LIBC_INLINE constexpr cpp::string_view symbol_version(VDSOSym) { } } // namespace vdso } // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_X86_64_VDSO_H From e3212e7b03c918d3e754bdee53621aacf1e7452e Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 9 May 2024 14:16:50 -0400 Subject: [PATCH 5/6] [libc] fix overlay build problems --- libc/src/__support/OSUtil/linux/vdso.cpp | 7 ++++++- libc/test/src/__support/OSUtil/linux/CMakeLists.txt | 2 +- libc/test/src/__support/OSUtil/linux/vdso_test.cpp | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp index 2b2c02ec69fef..98372f0ee00e3 100644 --- a/libc/src/__support/OSUtil/linux/vdso.cpp +++ b/libc/src/__support/OSUtil/linux/vdso.cpp @@ -11,7 +11,6 @@ #include "src/__support/threads/callonce.h" #include "src/__support/threads/linux/futex_word.h" #include "src/errno/libc_errno.h" -#include "src/sys/auxv/getauxval.h" #include #include @@ -24,6 +23,12 @@ #endif namespace LIBC_NAMESPACE { + +// we don't include getauxval.h as it may forcibly pull in elf.h (via +// sys/auxv.h) in overlay mode instead, we provide a separate declaration for +// getauxval +unsigned long getauxval(unsigned long id); + namespace vdso { // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt index 29c95ea27d70b..eef7a48255300 100644 --- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt +++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt @@ -8,5 +8,5 @@ add_libc_test( SRCS vdso_test.cpp DEPENDS libc.src.__support.OSUtil.vdso - libc.include.llvm-libc-types.struct_timeval # TODO: update this to proxy header once available + libc.hdr.types.struct_timeval ) diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp index 6dc35589938f6..dcc1c5747b47a 100644 --- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp +++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm-libc-types/struct_timeval.h" +#include "hdr/types/struct_timeval.h" #include "src/__support/OSUtil/vdso.h" #include "test/UnitTest/Test.h" From 6573c1658920f51aaaaff9b6bb63818fa1324ba7 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Fri, 10 May 2024 16:39:18 -0400 Subject: [PATCH 6/6] [libc] update clock_gettime implementation with vDSO --- libc/src/__support/time/linux/CMakeLists.txt | 1 + .../__support/time/linux/clock_gettime.cpp | 31 +++++++++++++------ libc/src/time/linux/time.cpp | 1 - 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libc/src/__support/time/linux/CMakeLists.txt b/libc/src/__support/time/linux/CMakeLists.txt index f04d550555e19..81e1098a066bc 100644 --- a/libc/src/__support/time/linux/CMakeLists.txt +++ b/libc/src/__support/time/linux/CMakeLists.txt @@ -11,4 +11,5 @@ add_object_library( libc.src.__support.common libc.src.__support.error_or libc.src.__support.OSUtil.osutil + libc.src.__support.OSUtil.vdso ) diff --git a/libc/src/__support/time/linux/clock_gettime.cpp b/libc/src/__support/time/linux/clock_gettime.cpp index 7f266b282a391..d8fa60c3ac41c 100644 --- a/libc/src/__support/time/linux/clock_gettime.cpp +++ b/libc/src/__support/time/linux/clock_gettime.cpp @@ -8,24 +8,37 @@ #include "src/__support/time/linux/clock_gettime.h" #include "src/__support/OSUtil/syscall.h" +#include "src/__support/OSUtil/vdso.h" #include namespace LIBC_NAMESPACE { namespace internal { ErrorOr clock_gettime(clockid_t clockid, timespec *ts) { + int ret; + do { +#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME + if (void *symbol = vdso::get_symbol(vdso::VDSOSym::ClockGetTime)) { + using FuncTy = int (*)(clockid_t, timespec *); + auto func = reinterpret_cast(symbol); + ret = func(clockid, ts); + break; + } +#endif #if SYS_clock_gettime - int ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_gettime, - static_cast(clockid), - reinterpret_cast(ts)); + ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_gettime, + static_cast(clockid), + reinterpret_cast(ts)); #elif defined(SYS_clock_gettime64) - static_assert( - sizeof(time_t) == sizeof(int64_t), - "SYS_clock_gettime64 requires struct timespec with 64-bit members."); - int ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_gettime64, - static_cast(clockid), - reinterpret_cast(ts)); + static_assert( + sizeof(time_t) == sizeof(int64_t), + "SYS_clock_gettime64 requires struct timespec with 64-bit members."); + ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_gettime64, + static_cast(clockid), + reinterpret_cast(ts)); #else #error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available." #endif + } while (0); + if (ret < 0) return Error(-ret); return ret; diff --git a/libc/src/time/linux/time.cpp b/libc/src/time/linux/time.cpp index 32f531efb6d15..26b733b2d39b2 100644 --- a/libc/src/time/linux/time.cpp +++ b/libc/src/time/linux/time.cpp @@ -15,7 +15,6 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) { - // TODO: Use the Linux VDSO to fetch the time and avoid the syscall. struct timespec ts; auto result = internal::clock_gettime(CLOCK_REALTIME, &ts); if (!result.has_value()) {