[libc-commits] [libc] [libc] implement vdso (PR #91572)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Sep 10 06:44:41 PDT 2024


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/91572

>From 9673650d6ac1fde0aceb289fef48bd98919f2e95 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 9 May 2024 04:26:55 -0400
Subject: [PATCH 01/27] [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 94d1042ccbb4a0..78285c960c0a40 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 00000000000000..177d29f8796930
--- /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 089cad454d534d..23853bc2273a13 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -23,3 +23,19 @@ add_object_library(
     libc.hdr.types.struct_f_owner_ex
     libc.hdr.types.off_t
 )
+
+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 eea9badc46cae6..68ce1d74c20994 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 00000000000000..55024e61ee914a
--- /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 733366f6d4a2e3..36c991425e6037 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 00000000000000..5d9ff5d929ab6d
--- /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 e271204f519820..b2e2401ece1acf 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 00000000000000..394c06e6a5a720
--- /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 00000000000000..2b2c02ec69fef4
--- /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 <linux/auxvec.h>
+#include <linux/elf.h>
+
+#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<Verdef *>(reinterpret_cast<uintptr_t>(this) +
+                                      vd_next);
+  }
+  Verdaux *aux() const {
+    return reinterpret_cast<Verdaux *>(reinterpret_cast<uintptr_t>(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<void *, static_cast<size_t>(VDSOSym::VDSOSymCount)>;
+
+static VDSOArray symbol_table;
+
+void *get_symbol(VDSOSym sym) {
+  // if sym is invalid, return nullptr
+  const size_t index = static_cast<size_t>(sym);
+  if (index >= symbol_table.size())
+    return nullptr;
+
+  static FutexWordType once_flag = 0;
+  callonce(reinterpret_cast<CallOnceFlag *>(&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<ElfW(Ehdr) *>(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<ElfW(Shdr) *>(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<ElfW(Addr)>(-1);
+    ElfW(Dyn) *vdso_dyn = nullptr;
+    // compute vdso_phdr as the program header using the program header offset
+    ElfW(Phdr) *vdso_phdr =
+        reinterpret_cast<ElfW(Phdr) *>(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<ElfW(Dyn) *>(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<ElfW(Addr)>(-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<const char *>(vdso_addr + d->d_un.d_ptr);
+        break;
+      case DT_SYMTAB:
+        symtab = reinterpret_cast<ElfW(Sym) *>(vdso_addr + d->d_un.d_ptr);
+        break;
+      case DT_VERSYM:
+        versym = reinterpret_cast<uint16_t *>(vdso_addr + d->d_un.d_ptr);
+        break;
+      case DT_VERDEF:
+        verdef = reinterpret_cast<Verdef *>(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<VDSOSym>(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<void *>(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 00000000000000..2d71db13303f00
--- /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 a7f2d74e6353e0..cb5938ef94d7de 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 00000000000000..13b8e3d8cc6f4e
--- /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 00000000000000..93bbc98da19b45
--- /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 fad0a8e9928bfcd2c08f6f078ce431814df841dd Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 9 May 2024 12:18:53 -0400
Subject: [PATCH 02/27] [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 bfb072c03e9712..29c95ea27d70b0 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 00000000000000..f1148daaccc1ad
--- /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<size_t>(vdso::VDSOSym::VDSOSymCount); ++i)
+    EXPECT_NE(vdso::get_symbol(static_cast<vdso::VDSOSym>(i)),
+              static_cast<void *>(nullptr));
+}
+
+#ifdef LIBC_VDSO_HAS_GETTIMEOFDAY
+TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
+  using FuncTy = int (*)(timeval *, struct timezone *);
+  auto func =
+      reinterpret_cast<FuncTy>(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<decltype(tv.tv_sec)>(0));
+}
+#endif
+
+} // namespace LIBC_NAMESPACE

>From 7975840b5283750daed29b8ce5efa29f2deaad9b Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 9 May 2024 12:23:42 -0400
Subject: [PATCH 03/27] [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 f1148daaccc1ad..6dc35589938f6f 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 fce9d127317067f6f32fe40b3f40def4888134a6 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 9 May 2024 14:04:52 -0400
Subject: [PATCH 04/27] [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 55024e61ee914a..14783b065069a8 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 5d9ff5d929ab6d..e1495df89d9add 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 394c06e6a5a720..41681856037c82 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 13b8e3d8cc6f4e..37580b0201f2c2 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 9c0668d83aa6dd8a7a8f6baf4ba43c6800327faf Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 9 May 2024 14:16:50 -0400
Subject: [PATCH 05/27] [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 2b2c02ec69fef4..98372f0ee00e3c 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 <linux/auxvec.h>
 #include <linux/elf.h>
 
@@ -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 29c95ea27d70b0..eef7a48255300d 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 6dc35589938f6f..dcc1c5747b47a6 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 2a43d7e4fda33bd7613d03e001e6200b41b77ef5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 10 May 2024 17:04:58 -0400
Subject: [PATCH 06/27] [libc] remove toplevel vdso and non-linux vdso

---
 libc/src/__support/OSUtil/CMakeLists.txt       |  8 --------
 libc/src/__support/OSUtil/fuchsia/vdso.h       | 12 ------------
 libc/src/__support/OSUtil/vdso.h               | 18 ------------------
 .../src/__support/OSUtil/linux/CMakeLists.txt  |  2 +-
 .../src/__support/OSUtil/linux/vdso_test.cpp   |  2 +-
 5 files changed, 2 insertions(+), 40 deletions(-)
 delete mode 100644 libc/src/__support/OSUtil/fuchsia/vdso.h
 delete 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 78285c960c0a40..94d1042ccbb4a0 100644
--- a/libc/src/__support/OSUtil/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/CMakeLists.txt
@@ -15,11 +15,3 @@ 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
deleted file mode 100644
index 177d29f8796930..00000000000000
--- a/libc/src/__support/OSUtil/fuchsia/vdso.h
+++ /dev/null
@@ -1,12 +0,0 @@
-//===------------- 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/vdso.h b/libc/src/__support/OSUtil/vdso.h
deleted file mode 100644
index 93bbc98da19b45..00000000000000
--- a/libc/src/__support/OSUtil/vdso.h
+++ /dev/null
@@ -1,18 +0,0 @@
-//===--------------- 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
diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index eef7a48255300d..34c6c755a39eb0 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -7,6 +7,6 @@ add_libc_test(
   SUITE libc-osutil-tests
   SRCS vdso_test.cpp
   DEPENDS
-    libc.src.__support.OSUtil.vdso
+    libc.src.__support.OSUtil.linux.vdso
     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 dcc1c5747b47a6..28cf8bd1c297ac 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "hdr/types/struct_timeval.h"
-#include "src/__support/OSUtil/vdso.h"
+#include "src/__support/OSUtil/linux/vdso.h"
 #include "test/UnitTest/Test.h"
 
 namespace LIBC_NAMESPACE {

>From 4d93cc0812c2e182cc9ea3ffbd42b72a7a1b0cc2 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 13 May 2024 17:34:03 -0400
Subject: [PATCH 07/27] wrap vDSO parsing utilities in unnamed namespace

---
 libc/src/__support/OSUtil/linux/vdso.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 98372f0ee00e3c..970308eeaa8557 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -31,6 +31,7 @@ unsigned long getauxval(unsigned long id);
 
 namespace vdso {
 
+namespace {
 // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html
 struct Verdaux {
   ElfW(Word) vda_name; /* Version or dependency names */
@@ -82,6 +83,7 @@ using VDSOArray =
     cpp::array<void *, static_cast<size_t>(VDSOSym::VDSOSymCount)>;
 
 static VDSOArray symbol_table;
+} // namespace
 
 void *get_symbol(VDSOSym sym) {
   // if sym is invalid, return nullptr

>From a575ca93b34f1899713683582957ea0c37e5e7cc Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 21 May 2024 20:15:06 -0700
Subject: [PATCH 08/27] use `auto` after explicit casting

Co-authored-by: Nick Desaulniers (paternity leave) <nickdesaulniers at users.noreply.github.com>
---
 libc/src/__support/OSUtil/linux/vdso.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 970308eeaa8557..a1110323a91c99 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -87,7 +87,7 @@ static VDSOArray symbol_table;
 
 void *get_symbol(VDSOSym sym) {
   // if sym is invalid, return nullptr
-  const size_t index = static_cast<size_t>(sym);
+  const auto index = static_cast<size_t>(sym);
   if (index >= symbol_table.size())
     return nullptr;
 

>From 5dc47375584bcedc6ea014e7dfbf710888e6ea41 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 21 May 2024 20:18:11 -0700
Subject: [PATCH 09/27] error on failure of arch resolution.

Co-authored-by: Nick Desaulniers (paternity leave) <nickdesaulniers at users.noreply.github.com>
---
 libc/src/__support/OSUtil/linux/vdso.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h
index 2d71db13303f00..31d3e413e242dd 100644
--- a/libc/src/__support/OSUtil/linux/vdso.h
+++ b/libc/src/__support/OSUtil/linux/vdso.h
@@ -18,6 +18,8 @@
 #include "arm/vdso.h"
 #elif defined(LIBC_TARGET_ARCH_IS_RISCV)
 #include "riscv/vdso.h"
+#else
+#error "unknown arch"
 #endif
 
 namespace LIBC_NAMESPACE {

>From 9852d549f3ba4b7d3fc0fc9dbef7a7ee7b00b052 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Sat, 25 May 2024 21:24:12 -0700
Subject: [PATCH 10/27] remove extra brace

Co-authored-by: Nick Desaulniers (paternity leave) <nickdesaulniers at users.noreply.github.com>
---
 libc/src/__support/OSUtil/linux/vdso.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index a1110323a91c99..f5166bc1934874 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -94,9 +94,8 @@ void *get_symbol(VDSOSym sym) {
   static FutexWordType once_flag = 0;
   callonce(reinterpret_cast<CallOnceFlag *>(&once_flag), [] {
     // first clear the symbol table
-    for (auto &i : 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;

>From ad62a03447b0f80d34f03f6593b032c11a3f7a30 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 25 May 2024 22:15:06 -0700
Subject: [PATCH 11/27] restructure vdso initialization routine

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |   1 +
 libc/src/__support/OSUtil/linux/vdso.cpp      | 188 +++++++++++-------
 2 files changed, 118 insertions(+), 71 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 23853bc2273a13..cf30155eef848e 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -33,6 +33,7 @@ add_object_library(
   DEPENDS
     .${LIBC_TARGET_ARCHITECTURE}.vdso
     libc.src.__support.CPP.array
+    libc.src.__support.CPP.optional
     libc.src.__support.CPP.string_view
     libc.src.__support.threads.callonce
     libc.src.__support.threads.linux.futex_word_type
diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index f5166bc1934874..af1ef8630d846e 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #include "src/__support/OSUtil/linux/vdso.h"
 #include "src/__support/CPP/array.h"
+#include "src/__support/CPP/optional.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/threads/callonce.h"
 #include "src/__support/threads/linux/futex_word.h"
@@ -70,7 +71,9 @@ cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym,
     // skip if this is a file-level version
     if (def->vd_flags & VER_FLG_BASE)
       continue;
-    // check if the version identifier matches
+    // check if the version identifier matches. Highest bit is used to determine
+    // whether the symbol is local. Only lower 15 bits are used for version
+    // identifier.
     if ((def->vd_ndx & 0x7FFF) == identifier) {
       Verdaux *aux = def->aux();
       return strtab + aux->vda_name;
@@ -82,61 +85,58 @@ cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym,
 using VDSOArray =
     cpp::array<void *, static_cast<size_t>(VDSOSym::VDSOSymCount)>;
 
-static VDSOArray symbol_table;
-} // namespace
+VDSOArray symbol_table;
 
-void *get_symbol(VDSOSym sym) {
-  // if sym is invalid, return nullptr
-  const auto index = static_cast<size_t>(sym);
-  if (index >= symbol_table.size())
-    return nullptr;
+size_t shdr_get_symbol_count(ElfW(Shdr) * vdso_shdr, size_t e_shnum) {
+  // iterate all sections until we locate the dynamic symbol section
+  for (size_t i = 0; i < e_shnum; ++i) {
+    // 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
+    if (vdso_shdr[i].sh_type == SHT_DYNSYM)
+      return vdso_shdr[i].sh_size / vdso_shdr[i].sh_entsize;
+  }
+  return 0;
+}
 
-  static FutexWordType once_flag = 0;
-  callonce(reinterpret_cast<CallOnceFlag *>(&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<ElfW(Ehdr) *>(vdso_ehdr_addr);
-    // leave the table unpopulated if we don't have vDSO
-    if (vdso_ehdr == nullptr) {
-      libc_errno = errno_backup;
-      return;
-    }
+struct VDSOSymbolTable {
+  const char *strtab;
+  ElfW(Sym) * symtab;
+  ElfW(Half) * versym;
+  Verdef *verdef;
 
-    // count entries
-    size_t symbol_count = 0;
-    // locate the section header inside the elf using the section header offset
-    auto vdso_shdr =
-        reinterpret_cast<ElfW(Shdr) *>(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;
+  void populate_symbol_cache(size_t symbol_count, ElfW(Addr) vdso_addr) {
+    for (size_t i = 0; i < symbol_table.size(); ++i) {
+      auto sym = static_cast<VDSOSym>(i);
+      cpp::string_view name = symbol_name(sym);
+      cpp::string_view version = symbol_version(sym);
+      for (size_t j = 0; j < symbol_count; ++j) {
+        if (name == 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 (version != find_version(verdef, versym, strtab, j))
+              continue;
+
+          // put the symbol address into the symbol table
+          symbol_table[i] =
+              reinterpret_cast<void *>(vdso_addr + symtab[j].st_value);
+        }
       }
     }
+  }
+};
 
-    // 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<ElfW(Addr)>(-1);
+struct PhdrInfo {
+  ElfW(Addr) vdso_addr;
+  ElfW(Dyn) * vdso_dyn;
+  static cpp::optional<PhdrInfo> from(ElfW(Phdr) * vdso_phdr, size_t e_phnum,
+                                      uintptr_t vdso_ehdr_addr) {
+    static constexpr ElfW(Addr) INVALID_ADDR = static_cast<ElfW(Addr)>(-1);
+    ElfW(Addr) vdso_addr = INVALID_ADDR;
     ElfW(Dyn) *vdso_dyn = nullptr;
-    // compute vdso_phdr as the program header using the program header offset
-    ElfW(Phdr) *vdso_phdr =
-        reinterpret_cast<ElfW(Phdr) *>(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) {
+    for (size_t i = 0; i < e_phnum; ++i) {
       if (vdso_phdr[i].p_type == PT_DYNAMIC)
         vdso_dyn = reinterpret_cast<ElfW(Dyn) *>(vdso_ehdr_addr +
                                                  vdso_phdr[i].p_offset);
@@ -146,14 +146,13 @@ void *get_symbol(VDSOSym sym) {
             vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
 
       if (vdso_addr && vdso_dyn)
-        break;
+        return PhdrInfo{vdso_addr, vdso_dyn};
     }
-    // early return if either the dynamic linking or the loadable segment is not
-    // found
-    if (vdso_dyn == nullptr || vdso_addr == static_cast<ElfW(Addr)>(-1))
-      return;
 
-    // now, locate several more tables inside the dynmaic linking section
+    return cpp::nullopt;
+  }
+
+  cpp::optional<VDSOSymbolTable> populate_symbol_table() {
     const char *strtab = nullptr;
     ElfW(Sym) *symtab = nullptr;
     ElfW(Half) *versym = nullptr;
@@ -178,26 +177,73 @@ void *get_symbol(VDSOSym sym) {
       }
     }
     if (strtab == nullptr || symtab == nullptr)
-      return;
+      return cpp::nullopt;
 
-    for (size_t i = 0; i < symbol_table.size(); ++i) {
-      for (size_t j = 0; j < symbol_count; ++j) {
-        auto sym = static_cast<VDSOSym>(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;
+    return VDSOSymbolTable{strtab, symtab, versym, verdef};
+  }
+};
 
-          // put the symbol address into the symbol table
-          symbol_table[i] =
-              reinterpret_cast<void *>(vdso_addr + symtab[j].st_value);
-        }
-      }
-    }
-  });
+void initialize_vdso_global_cache() {
+  // 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<ElfW(Ehdr) *>(vdso_ehdr_addr);
+  // leave the table unpopulated if we don't have vDSO
+  if (vdso_ehdr == nullptr) {
+    libc_errno = errno_backup;
+    return;
+  }
 
+  // locate the section header inside the elf using the section header
+  // offset
+  auto vdso_shdr =
+      reinterpret_cast<ElfW(Shdr) *>(vdso_ehdr_addr + vdso_ehdr->e_shoff);
+  size_t symbol_count = shdr_get_symbol_count(vdso_shdr, vdso_ehdr->e_shnum);
+
+  // 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. compute vdso_phdr as the program header using the program
+  // header offset
+  ElfW(Phdr) *vdso_phdr =
+      reinterpret_cast<ElfW(Phdr) *>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
+  cpp::optional<PhdrInfo> phdr_info =
+      PhdrInfo::from(vdso_phdr, vdso_ehdr->e_phnum, vdso_ehdr_addr);
+  // early return if either the dynamic linking or the loadable segment is
+  // not found
+  if (!phdr_info.has_value())
+    return;
+
+  // now, locate several more tables inside the dynmaic linking section
+  cpp::optional<VDSOSymbolTable> vdso_symbol_table =
+      phdr_info->populate_symbol_table();
+
+  // early return if we can't find any required fields of the symbol table
+  if (!vdso_symbol_table.has_value())
+    return;
+
+  // finally, populate the global symbol table cache
+  vdso_symbol_table->populate_symbol_cache(symbol_count, phdr_info->vdso_addr);
+}
+} // namespace
+
+void *get_symbol(VDSOSym sym) {
+  // if sym is invalid, return nullptr
+  const auto index = static_cast<size_t>(sym);
+  if (index >= symbol_table.size())
+    return nullptr;
+
+  static FutexWordType once_flag = 0;
+  callonce(reinterpret_cast<CallOnceFlag *>(&once_flag),
+           initialize_vdso_global_cache);
   return symbol_table[index];
 }
 } // namespace vdso

>From 4aead1e1c966c17c6ecd2164d35a64c54fdb8235 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sun, 26 May 2024 13:30:36 -0700
Subject: [PATCH 12/27] adjust vDSO definitions

---
 .../src/__support/OSUtil/linux/aarch64/vdso.h |  1 +
 libc/src/__support/OSUtil/linux/arm/vdso.h    | 20 +++++++++++++++----
 libc/src/__support/OSUtil/linux/riscv/vdso.h  |  5 +++++
 libc/src/__support/OSUtil/linux/x86_64/vdso.h | 19 ++++++++++++++----
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 10 ++++++++--
 5 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
index 14783b065069a8..27659e686506d7 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
@@ -17,6 +17,7 @@ namespace vdso {
 #define LIBC_VDSO_HAS_CLOCK_GETRES
 
 // list of VDSO symbols
+// following the order in arch/arm64/kernel/vdso/vdso.lds.S
 enum class VDSOSym {
   RTSigReturn,
   GetTimeOfDay,
diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h
index e1495df89d9add..17d09a69db03bd 100644
--- a/libc/src/__support/OSUtil/linux/arm/vdso.h
+++ b/libc/src/__support/OSUtil/linux/arm/vdso.h
@@ -11,22 +11,34 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
-#define LIBC_VDSO_HAS_GETTIMEOFDAY
+// following the order in arch/arm/vdso/vdso.lds.S
 #define LIBC_VDSO_HAS_CLOCK_GETTIME
+#define LIBC_VDSO_HAS_GETTIMEOFDAY
+#define LIBC_VDSO_HAS_CLOCK_GETRES
+#define LIBC_VDSO_HAS_CLOCK_GETTIME64
 
 // list of VDSO symbols
 enum class VDSOSym {
-  GetTimeOfDay,
   ClockGetTime,
+  GetTimeOfDay,
+  ClockGetRes,
+  ClockGetTime64,
+  VDSOSymCount
 };
 
 // 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";
+  case VDSOSym::GetTimeOfDay:
+    return "__vdso_gettimeofday";
+  case VDSOSym::ClockGetRes:
+    return "__vdso_clock_getres";
+  case VDSOSym::ClockGetTime64:
+    return "__vdso_clock_gettime64";
+  default:
+    return "";
   }
 }
 
diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h
index 41681856037c82..10e5c9a54a982c 100644
--- a/libc/src/__support/OSUtil/linux/riscv/vdso.h
+++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h
@@ -11,12 +11,14 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
+// following the order in arch/riscv/kernel/vdso/vdso.lds.S
 #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
+#define LIBC_VDSO_HAS_RISCV_HWPROBE
 
 // list of VDSO symbols
 enum class VDSOSym {
@@ -26,6 +28,7 @@ enum class VDSOSym {
   ClockGetRes,
   GetCpu,
   FlushICache,
+  RiscvHwProbe,
   VDSOSymCount
 };
 
@@ -44,6 +47,8 @@ LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
     return "__vdso_getcpu";
   case VDSOSym::FlushICache:
     return "__vdso_flush_icache";
+  case VDSOSym::RiscvHwProbe:
+    return "__vdso_riscv_hwprobe";
   default:
     return "";
   }
diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
index 37580b0201f2c2..96e50c25aab8a1 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
@@ -11,25 +11,36 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
+// following the order in arch/x86/entry/vdso/vdso.lds.S
 #define LIBC_VDSO_HAS_CLOCK_GETTIME
-#define LIBC_VDSO_HAS_GETCPU
 #define LIBC_VDSO_HAS_GETTIMEOFDAY
+#define LIBC_VDSO_HAS_GETCPU
 #define LIBC_VDSO_HAS_TIME
+#define LIBC_VDSO_HAS_CLOCK_GETRES
 
 // list of VDSO symbols
-enum class VDSOSym { ClockGetTime, GetCpu, GetTimeOfDay, Time, VDSOSymCount };
+enum class VDSOSym {
+  ClockGetTime,
+  GetTimeOfDay,
+  GetCpu,
+  Time,
+  ClockGetRes,
+  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::GetCpu:
+    return "__vdso_getcpu";
   case VDSOSym::Time:
     return "__vdso_time";
+  case VDSOSym::ClockGetRes:
+    return "__vdso_clock_getres";
   default:
     return "";
   }
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index 28cf8bd1c297ac..543292bae7223f 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -12,10 +12,16 @@
 
 namespace LIBC_NAMESPACE {
 TEST(LlvmLibcOSUtilVDSOTest, SymbolsDefined) {
-  // for now, we simply test all symbols are provided.
-  for (size_t i = 0; i < static_cast<size_t>(vdso::VDSOSym::VDSOSymCount); ++i)
+  for (size_t i = 0; i < static_cast<size_t>(vdso::VDSOSym::VDSOSymCount);
+       ++i) {
+    // RiscvHwProbe is provided only on >=6.4 kernels. Skip it for now.
+#ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
+    if (static_cast<vdso::VDSOSym>(i) == vdso::VDSOSym::RiscvHwProbe)
+      continue;
+#endif
     EXPECT_NE(vdso::get_symbol(static_cast<vdso::VDSOSym>(i)),
               static_cast<void *>(nullptr));
+  }
 }
 
 #ifdef LIBC_VDSO_HAS_GETTIMEOFDAY

>From 347c1f72fdab169dfae407153acdd28cd0f58705 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sun, 26 May 2024 13:40:05 -0700
Subject: [PATCH 13/27] add more tests

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |  3 ++
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 34 ++++++++++++++++++-
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index 34c6c755a39eb0..c2363927e0ec3f 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -9,4 +9,7 @@ add_libc_test(
   DEPENDS
     libc.src.__support.OSUtil.linux.vdso
     libc.hdr.types.struct_timeval
+    libc.hdr.types.struct_timespec
+    libc.hdr.types.clockid_t
+    libc.hdr.time_macros
 )
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index 543292bae7223f..0c937c0cd86589 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -6,15 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/time_macros.h"
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/struct_timespec.h"
 #include "hdr/types/struct_timeval.h"
+#include "include/llvm-libc-macros/linux/time-macros.h"
 #include "src/__support/OSUtil/linux/vdso.h"
+#include "test/UnitTest/LibcTest.h"
 #include "test/UnitTest/Test.h"
 
 namespace LIBC_NAMESPACE {
 TEST(LlvmLibcOSUtilVDSOTest, SymbolsDefined) {
   for (size_t i = 0; i < static_cast<size_t>(vdso::VDSOSym::VDSOSymCount);
        ++i) {
-    // RiscvHwProbe is provided only on >=6.4 kernels. Skip it for now.
+    // riscv_hwprobe is provided only on >=6.4 kernels. Skip it for now.
 #ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
     if (static_cast<vdso::VDSOSym>(i) == vdso::VDSOSym::RiscvHwProbe)
       continue;
@@ -36,4 +41,31 @@ TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
 }
 #endif
 
+#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME
+TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
+  using FuncTy = int (*)(clockid_t, timespec *);
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetTime));
+  timespec a, b;
+  EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
+  EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
+  if (a.tv_sec == b.tv_sec) {
+    EXPECT_LT(a.tv_nsec, b.tv_nsec);
+  } else {
+    EXPECT_LT(a.tv_sec, b.tv_sec);
+  }
+}
+#endif
+
+#ifdef LIBC_VDSO_HAS_CLOCK_GETRES
+TEST(LlvmLibcOSUtilVDSOTest, ClockGetRes) {
+  using FuncTy = int (*)(clockid_t, timespec *);
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetRes));
+  timespec res{};
+  EXPECT_EQ(func(CLOCK_MONOTONIC, &res), 0);
+  EXPECT_TRUE(res.tv_sec > 0 || res.tv_nsec > 0);
+}
+#endif
+
 } // namespace LIBC_NAMESPACE

>From 16f74268cb505fdf58dc3dd1e8e5b9a576e6e8b3 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Tue, 28 May 2024 23:27:50 -0700
Subject: [PATCH 14/27] address CRs

---
 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/vdso.cpp       | 18 +++++++++++++-----
 libc/src/__support/OSUtil/linux/x86_64/vdso.h  |  3 ++-
 5 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
index 27659e686506d7..cf14ed724a186c 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
@@ -17,7 +17,8 @@ namespace vdso {
 #define LIBC_VDSO_HAS_CLOCK_GETRES
 
 // list of VDSO symbols
-// following the order in arch/arm64/kernel/vdso/vdso.lds.S
+// following the order in
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/vdso/vdso.lds.S
 enum class VDSOSym {
   RTSigReturn,
   GetTimeOfDay,
diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h
index 17d09a69db03bd..4cc5bbbb6777ea 100644
--- a/libc/src/__support/OSUtil/linux/arm/vdso.h
+++ b/libc/src/__support/OSUtil/linux/arm/vdso.h
@@ -11,7 +11,8 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
-// following the order in arch/arm/vdso/vdso.lds.S
+// following the order in
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/vdso/vdso.lds.S
 #define LIBC_VDSO_HAS_CLOCK_GETTIME
 #define LIBC_VDSO_HAS_GETTIMEOFDAY
 #define LIBC_VDSO_HAS_CLOCK_GETRES
diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h
index 10e5c9a54a982c..313a94a8af00fc 100644
--- a/libc/src/__support/OSUtil/linux/riscv/vdso.h
+++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h
@@ -11,7 +11,8 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
-// following the order in arch/riscv/kernel/vdso/vdso.lds.S
+// following the order in
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/kernel/vdso/vdso.lds.S
 #define LIBC_VDSO_HAS_RT_SIGRETURN
 #define LIBC_VDSO_HAS_GETTIMEOFDAY
 #define LIBC_VDSO_HAS_CLOCK_GETTIME
diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index af1ef8630d846e..46b8d897d99f6a 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -12,6 +12,8 @@
 #include "src/__support/threads/callonce.h"
 #include "src/__support/threads/linux/futex_word.h"
 #include "src/errno/libc_errno.h"
+#include "x86_64/vdso.h"
+#include <cstddef>
 #include <linux/auxvec.h>
 #include <linux/elf.h>
 
@@ -33,6 +35,13 @@ unsigned long getauxval(unsigned long id);
 namespace vdso {
 
 namespace {
+
+// Helper functions to convert between VDSOSym and its index
+constexpr VDSOSym symbolize(size_t index) {
+  return static_cast<VDSOSym>(index);
+}
+constexpr size_t numeralize(VDSOSym sym) { return static_cast<size_t>(sym); }
+
 // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html
 struct Verdaux {
   ElfW(Word) vda_name; /* Version or dependency names */
@@ -82,8 +91,7 @@ cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym,
   return "";
 }
 
-using VDSOArray =
-    cpp::array<void *, static_cast<size_t>(VDSOSym::VDSOSymCount)>;
+using VDSOArray = cpp::array<void *, numeralize(VDSOSym::VDSOSymCount)>;
 
 VDSOArray symbol_table;
 
@@ -106,8 +114,8 @@ struct VDSOSymbolTable {
   Verdef *verdef;
 
   void populate_symbol_cache(size_t symbol_count, ElfW(Addr) vdso_addr) {
-    for (size_t i = 0; i < symbol_table.size(); ++i) {
-      auto sym = static_cast<VDSOSym>(i);
+    for (size_t i = 0, e = symbol_table.size(); i < e; ++i) {
+      VDSOSym sym = symbolize(i);
       cpp::string_view name = symbol_name(sym);
       cpp::string_view version = symbol_version(sym);
       for (size_t j = 0; j < symbol_count; ++j) {
@@ -237,7 +245,7 @@ void initialize_vdso_global_cache() {
 
 void *get_symbol(VDSOSym sym) {
   // if sym is invalid, return nullptr
-  const auto index = static_cast<size_t>(sym);
+  const size_t index = numeralize(sym);
   if (index >= symbol_table.size())
     return nullptr;
 
diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
index 96e50c25aab8a1..95a43d4fa070a1 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
@@ -11,7 +11,8 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // macro definitions
-// following the order in arch/x86/entry/vdso/vdso.lds.S
+// following the order in
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/vdso/vdso.lds.S
 #define LIBC_VDSO_HAS_CLOCK_GETTIME
 #define LIBC_VDSO_HAS_GETTIMEOFDAY
 #define LIBC_VDSO_HAS_GETCPU

>From 1614d0f310312ebeb52bf7487f93e25c53b200fd Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 14:19:55 -0700
Subject: [PATCH 15/27] [libc] add comment for x86 vdso

---
 libc/src/__support/OSUtil/linux/x86_64/vdso.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
index 95a43d4fa070a1..c5b5c45b5b01f9 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
@@ -30,6 +30,10 @@ enum class VDSOSym {
 };
 
 // translate VDSOSym to symbol names
+// On x86, there are symbols defined without the __vdso_ prefix, however,
+// it is suggested that one should use the __vdso_ prefix.
+// Additionally, there is also an __vdso_sgx_enter_enclave, it is for the SGX
+// support, we do not include it here for now.
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
   case VDSOSym::ClockGetTime:

>From 6e90bcddf1a43d4b5e2bcd4566946336c4807334 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 14:33:43 -0700
Subject: [PATCH 16/27] [libc] fix

---
 libc/src/__support/OSUtil/linux/vdso.cpp | 36 +++++++++++++++---------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 46b8d897d99f6a..377648fb9a3539 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -12,8 +12,6 @@
 #include "src/__support/threads/callonce.h"
 #include "src/__support/threads/linux/futex_word.h"
 #include "src/errno/libc_errno.h"
-#include "x86_64/vdso.h"
-#include <cstddef>
 #include <linux/auxvec.h>
 #include <linux/elf.h>
 
@@ -36,11 +34,21 @@ namespace vdso {
 
 namespace {
 
-// Helper functions to convert between VDSOSym and its index
-constexpr VDSOSym symbolize(size_t index) {
-  return static_cast<VDSOSym>(index);
-}
-constexpr size_t numeralize(VDSOSym sym) { return static_cast<size_t>(sym); }
+// This class is an internal helper for symbol <-> index conversion and
+// improve the readability of the code.
+// We keep this class internal on purpose to avoid users from implicitly
+// converting between size_t and VDSOSym.
+class Symbol {
+  VDSOSym sym;
+
+public:
+  static constexpr size_t COUNT = static_cast<size_t>(VDSOSym::VDSOSymCount);
+  constexpr Symbol(VDSOSym sym) : sym(sym) {}
+  constexpr Symbol(size_t idx) : sym(static_cast<VDSOSym>(idx)) {}
+  constexpr cpp::string_view name() const { return symbol_name(sym); }
+  constexpr cpp::string_view version() const { return symbol_version(sym); }
+  operator size_t() const { return static_cast<size_t>(sym); }
+};
 
 // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html
 struct Verdaux {
@@ -91,7 +99,7 @@ cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym,
   return "";
 }
 
-using VDSOArray = cpp::array<void *, numeralize(VDSOSym::VDSOSymCount)>;
+using VDSOArray = cpp::array<void *, Symbol::COUNT>;
 
 VDSOArray symbol_table;
 
@@ -115,9 +123,9 @@ struct VDSOSymbolTable {
 
   void populate_symbol_cache(size_t symbol_count, ElfW(Addr) vdso_addr) {
     for (size_t i = 0, e = symbol_table.size(); i < e; ++i) {
-      VDSOSym sym = symbolize(i);
-      cpp::string_view name = symbol_name(sym);
-      cpp::string_view version = symbol_version(sym);
+      Symbol sym = i;
+      cpp::string_view name = sym.name();
+      cpp::string_view version = sym.version();
       for (size_t j = 0; j < symbol_count; ++j) {
         if (name == strtab + symtab[j].st_name) {
           // we find a symbol with desired name
@@ -245,14 +253,14 @@ void initialize_vdso_global_cache() {
 
 void *get_symbol(VDSOSym sym) {
   // if sym is invalid, return nullptr
-  const size_t index = numeralize(sym);
-  if (index >= symbol_table.size())
+  Symbol symbol(sym);
+  if (symbol >= symbol_table.size())
     return nullptr;
 
   static FutexWordType once_flag = 0;
   callonce(reinterpret_cast<CallOnceFlag *>(&once_flag),
            initialize_vdso_global_cache);
-  return symbol_table[index];
+  return symbol_table[symbol];
 }
 } // namespace vdso
 } // namespace LIBC_NAMESPACE

>From 66a7e5bde1798a96d82096d955d90bdd2c9e4b3d Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 14:36:21 -0700
Subject: [PATCH 17/27] [libc] fix

---
 libc/src/__support/OSUtil/linux/vdso.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 377648fb9a3539..615b6cd3de5e2e 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -47,7 +47,7 @@ class Symbol {
   constexpr Symbol(size_t idx) : sym(static_cast<VDSOSym>(idx)) {}
   constexpr cpp::string_view name() const { return symbol_name(sym); }
   constexpr cpp::string_view version() const { return symbol_version(sym); }
-  operator size_t() const { return static_cast<size_t>(sym); }
+  constexpr operator size_t() const { return static_cast<size_t>(sym); }
 };
 
 // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html

>From a0110ea8a1caf5790dcffbc7ca8a766266c58d3b Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 14:57:55 -0700
Subject: [PATCH 18/27] [libc] fix

---
 libc/src/__support/OSUtil/linux/vdso.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 615b6cd3de5e2e..d1ea951f22ae93 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -15,6 +15,8 @@
 #include <linux/auxvec.h>
 #include <linux/elf.h>
 
+// TODO: This is a temporary workaround to avoid including elf.h
+// Include our own headers for ElfW and friends once we have them.
 #ifndef ElfW
 #if __POINTER_WIDTH__ == 32
 #define ElfW(type) Elf32_##type

>From 4baa641bb7835c91de6dfc956fe3fffbb0a57513 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 16:32:48 -0700
Subject: [PATCH 19/27] [libc] fix

---
 libc/src/sched/linux/CMakeLists.txt           |   2 +-
 .../src/__support/OSUtil/linux/CMakeLists.txt |   6 +
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 162 ++++++++++++++++--
 3 files changed, 155 insertions(+), 15 deletions(-)

diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt
index ac95bf85da534f..03f513cac644a0 100644
--- a/libc/src/sched/linux/CMakeLists.txt
+++ b/libc/src/sched/linux/CMakeLists.txt
@@ -29,7 +29,7 @@ add_entrypoint_object(
   HDRS
     ../sched_getcpucount.h
   DEPENDS
-    libc.include.sched
+    libc.hdr.types.cpu_set_t
   )
 
 add_entrypoint_object(
diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index c2363927e0ec3f..ff82616cc4a701 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -8,8 +8,14 @@ add_libc_test(
   SRCS vdso_test.cpp
   DEPENDS
     libc.src.__support.OSUtil.linux.vdso
+    libc.src.__support.OSUtil.osutil
+    libc.hdr.types.struct_sigaction
     libc.hdr.types.struct_timeval
     libc.hdr.types.struct_timespec
     libc.hdr.types.clockid_t
+    libc.hdr.types.time_t
     libc.hdr.time_macros
+    libc.hdr.signal_macros
+    libc.src.signal.sigaction
+    libc.src.signal.raise
 )
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index 0c937c0cd86589..f023acff5642ff 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -6,34 +6,31 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/signal_macros.h"
 #include "hdr/time_macros.h"
 #include "hdr/types/clockid_t.h"
+#include "hdr/types/struct_sigaction.h"
 #include "hdr/types/struct_timespec.h"
 #include "hdr/types/struct_timeval.h"
-#include "include/llvm-libc-macros/linux/time-macros.h"
+#include "hdr/types/time_t.h"
 #include "src/__support/OSUtil/linux/vdso.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/signal/raise.h"
+#include "src/signal/sigaction.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/LibcTest.h"
 #include "test/UnitTest/Test.h"
+#include <linux/time_types.h>
+#include <sys/syscall.h>
 
 namespace LIBC_NAMESPACE {
-TEST(LlvmLibcOSUtilVDSOTest, SymbolsDefined) {
-  for (size_t i = 0; i < static_cast<size_t>(vdso::VDSOSym::VDSOSymCount);
-       ++i) {
-    // riscv_hwprobe is provided only on >=6.4 kernels. Skip it for now.
-#ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
-    if (static_cast<vdso::VDSOSym>(i) == vdso::VDSOSym::RiscvHwProbe)
-      continue;
-#endif
-    EXPECT_NE(vdso::get_symbol(static_cast<vdso::VDSOSym>(i)),
-              static_cast<void *>(nullptr));
-  }
-}
-
 #ifdef LIBC_VDSO_HAS_GETTIMEOFDAY
 TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
   using FuncTy = int (*)(timeval *, struct timezone *);
   auto func =
       reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::GetTimeOfDay));
+  if (func == nullptr)
+    return;
   timeval tv;
   EXPECT_EQ(func(&tv, nullptr), 0);
   // hopefully people are not building time machines using our libc.
@@ -41,11 +38,26 @@ TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
 }
 #endif
 
+#ifdef LIBC_VDSO_HAS_TIME
+TEST(LlvmLibcOSUtilVDSOTest, Time) {
+  using FuncTy = time_t (*)(time_t *);
+  auto func = reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::Time));
+  if (func == nullptr)
+    return;
+  time_t a, b;
+  EXPECT_GT(func(&a), static_cast<time_t>(0));
+  EXPECT_GT(func(&b), static_cast<time_t>(0));
+  EXPECT_GE(b, a);
+}
+#endif
+
 #ifdef LIBC_VDSO_HAS_CLOCK_GETTIME
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
   using FuncTy = int (*)(clockid_t, timespec *);
   auto func =
       reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetTime));
+  if (func == nullptr)
+    return;
   timespec a, b;
   EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
   EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
@@ -57,15 +69,137 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
 }
 #endif
 
+#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME64
+TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
+  using FuncTy = int (*)(clockid_t, __kernel_timespec *);
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetTime64));
+  if (func == nullptr)
+    return;
+  // See kernel API at
+  // https://elixir.bootlin.com/linux/latest/source/tools/testing/selftests/vDSO/vdso_test_correctness.c#L155
+  __kernel_timespec a, b;
+  EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
+  EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
+  if (a.tv_sec == b.tv_sec) {
+    EXPECT_LT(a.tv_nsec, b.tv_nsec);
+  } else {
+    EXPECT_LT(a.tv_sec, b.tv_sec);
+  }
+}
+#endif
+
 #ifdef LIBC_VDSO_HAS_CLOCK_GETRES
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetRes) {
   using FuncTy = int (*)(clockid_t, timespec *);
   auto func =
       reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetRes));
+  if (func == nullptr)
+    return;
   timespec res{};
   EXPECT_EQ(func(CLOCK_MONOTONIC, &res), 0);
   EXPECT_TRUE(res.tv_sec > 0 || res.tv_nsec > 0);
 }
 #endif
 
+#ifdef LIBC_VDSO_HAS_GETCPU
+TEST(LlvmLibcOSUtilVDSOTest, GetCpu) {
+  // The kernel system call has a third argument, which should be passed as
+  // nullptr.
+  using FuncTy = int (*)(int *, int *, void *);
+  auto func = reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::GetCpu));
+  if (func == nullptr)
+    return;
+  int cpu = -1, node = -1;
+  EXPECT_EQ(func(&cpu, &node, nullptr), 0);
+  EXPECT_GE(cpu, 0);
+  EXPECT_GE(node, 0);
+}
+#endif
+
+// TODO: apply this change to __restore_rt in
+// libc/src/signal/linux/sigaction.cpp
+// Caution: user application typically should not play with the trampoline.
+// Let the libc handle it.
+[[gnu::noreturn]] static void __restore_rt() {
+#ifdef LIBC_VDSO_HAS_RT_SIGRETURN
+  using FuncTy = void (*)();
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::RTSigReturn));
+  if (func) {
+    func();
+    __builtin_trap();
+  }
+#endif
+  LIBC_NAMESPACE::syscall_impl<long>(SYS_rt_sigreturn);
+  __builtin_trap();
+}
+
+static bool flag = false;
+
+static void sigprof_handler [[gnu::used]] (int) { flag = true; }
+
+TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {
+  using namespace testing::ErrnoSetterMatcher;
+  // must use struct since there is a function of the same name in the same
+  // scope.
+  struct sigaction sa{};
+  struct sigaction old_sa{};
+  sa.sa_handler = sigprof_handler;
+  sa.sa_flags = SA_RESTORER;
+  sa.sa_restorer = __restore_rt;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &sa, &old_sa), Succeeds());
+  raise(SIGPROF);
+  ASSERT_TRUE(flag);
+  flag = false;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &old_sa, nullptr), Succeeds());
+}
+
+#ifdef LIBC_VDSO_HAS_FLUSH_ICACHE
+TEST(LlvmLibcOSUtilVDSOTest, FlushICache) {
+  using FuncTy = void (*)(void *, void *, unsigned long);
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::FlushICache));
+  if (func == nullptr)
+    return;
+  char buf[512];
+  // we just check that the flush will not panic the program.
+  // the flags part only take 0/1 as up to kernel 6.10, which is used to
+  // indicate whether the flush is local to the core or global.
+  func(buf, buf + sizeof(buf), 0);
+  func(buf, buf + sizeof(buf), 1);
+}
+#endif
+
+// https://docs.kernel.org/6.5/riscv/hwprobe.html
+
+#ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
+TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
+  using namespace testing::ErrnoSetterMatcher;
+  struct riscv_hwprobe {
+    int64_t key;
+    uint64_t value;
+  };
+  using FuncTy =
+      long (*)(riscv_hwprobe *, size_t, size_t, struct cpu_set_t *, unsigned);
+  auto func =
+      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::RiscvHwProbe));
+  if (func == nullptr)
+    return;
+  // If a key is unknown to the kernel, its key field will be cleared to -1, and
+  // its value set to 0. We expect probes.value are all 0.
+  // Usermode can supply NULL for cpus and 0 for cpu_count as a shortcut for all
+  // online CPUs
+  riscv_hwprobe probes[2] = {{-1, 1}, {-1, 1}};
+  ASSERT_THAT(func(/*pairs=*/probes, /*count=*/2, /*cpusetsize=*/0,
+                   /*cpuset=*/nullptr,
+                   /*flags=*/0),
+              Succeeds());
+  for (auto &probe : probes) {
+    EXPECT_EQ(probe.key, static_cast<decltype(probe.key)>(-1));
+    EXPECT_EQ(probe.value, static_cast<decltype(probe.value)>(0));
+  }
+}
+#endif
+
 } // namespace LIBC_NAMESPACE

>From b0462dd985e40127bf13f6c8a9e9db4fe81b4385 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 1 Jun 2024 16:36:15 -0700
Subject: [PATCH 20/27] [libc] undo extra changes

---
 libc/src/sched/linux/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt
index 03f513cac644a0..ac95bf85da534f 100644
--- a/libc/src/sched/linux/CMakeLists.txt
+++ b/libc/src/sched/linux/CMakeLists.txt
@@ -29,7 +29,7 @@ add_entrypoint_object(
   HDRS
     ../sched_getcpucount.h
   DEPENDS
-    libc.hdr.types.cpu_set_t
+    libc.include.sched
   )
 
 add_entrypoint_object(

>From 4e48674ff6c0dbb4ce0f47d2647a36e276b92b30 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 8 Jun 2024 17:21:10 -0700
Subject: [PATCH 21/27] address CRs and improve inlining of fastpaths

---
 .../src/__support/OSUtil/linux/aarch64/vdso.h | 17 ----
 libc/src/__support/OSUtil/linux/arm/vdso.h    | 17 ----
 libc/src/__support/OSUtil/linux/riscv/vdso.h  | 23 ------
 libc/src/__support/OSUtil/linux/vdso.cpp      | 50 +++--------
 libc/src/__support/OSUtil/linux/vdso.h        | 59 ++++++++++++-
 libc/src/__support/OSUtil/linux/x86_64/vdso.h | 19 -----
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 82 +++++++------------
 7 files changed, 99 insertions(+), 168 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
index cf14ed724a186c..68d2bdaac4fc7f 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
@@ -10,23 +10,6 @@
 #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
-// following the order in
-// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/vdso/vdso.lds.S
-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) {
diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h
index 4cc5bbbb6777ea..1cc41e47a2b7c2 100644
--- a/libc/src/__support/OSUtil/linux/arm/vdso.h
+++ b/libc/src/__support/OSUtil/linux/arm/vdso.h
@@ -10,23 +10,6 @@
 #include "src/__support/CPP/string_view.h"
 namespace LIBC_NAMESPACE {
 namespace vdso {
-// macro definitions
-// following the order in
-// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/vdso/vdso.lds.S
-#define LIBC_VDSO_HAS_CLOCK_GETTIME
-#define LIBC_VDSO_HAS_GETTIMEOFDAY
-#define LIBC_VDSO_HAS_CLOCK_GETRES
-#define LIBC_VDSO_HAS_CLOCK_GETTIME64
-
-// list of VDSO symbols
-enum class VDSOSym {
-  ClockGetTime,
-  GetTimeOfDay,
-  ClockGetRes,
-  ClockGetTime64,
-  VDSOSymCount
-};
-
 // translate VDSOSym to symbol names
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h
index 313a94a8af00fc..9a494437fd05fa 100644
--- a/libc/src/__support/OSUtil/linux/riscv/vdso.h
+++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h
@@ -10,29 +10,6 @@
 #include "src/__support/CPP/string_view.h"
 namespace LIBC_NAMESPACE {
 namespace vdso {
-// macro definitions
-// following the order in
-// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/kernel/vdso/vdso.lds.S
-#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
-#define LIBC_VDSO_HAS_RISCV_HWPROBE
-
-// list of VDSO symbols
-enum class VDSOSym {
-  RTSigReturn,
-  GetTimeOfDay,
-  ClockGetTime,
-  ClockGetRes,
-  GetCpu,
-  FlushICache,
-  RiscvHwProbe,
-  VDSOSymCount
-};
-
 // translate VDSOSym to symbol names
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index d1ea951f22ae93..4e0467d6dade85 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -34,24 +34,10 @@ unsigned long getauxval(unsigned long id);
 
 namespace vdso {
 
-namespace {
-
-// This class is an internal helper for symbol <-> index conversion and
-// improve the readability of the code.
-// We keep this class internal on purpose to avoid users from implicitly
-// converting between size_t and VDSOSym.
-class Symbol {
-  VDSOSym sym;
-
-public:
-  static constexpr size_t COUNT = static_cast<size_t>(VDSOSym::VDSOSymCount);
-  constexpr Symbol(VDSOSym sym) : sym(sym) {}
-  constexpr Symbol(size_t idx) : sym(static_cast<VDSOSym>(idx)) {}
-  constexpr cpp::string_view name() const { return symbol_name(sym); }
-  constexpr cpp::string_view version() const { return symbol_version(sym); }
-  constexpr operator size_t() const { return static_cast<size_t>(sym); }
-};
+Symbol::VDSOArray Symbol::global_cache{};
+CallOnceFlag Symbol::once_flag = callonce_impl::NOT_CALLED;
 
+namespace {
 // See https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html
 struct Verdaux {
   ElfW(Word) vda_name; /* Version or dependency names */
@@ -101,10 +87,6 @@ cpp::string_view find_version(Verdef *verdef, ElfW(Half) * versym,
   return "";
 }
 
-using VDSOArray = cpp::array<void *, Symbol::COUNT>;
-
-VDSOArray symbol_table;
-
 size_t shdr_get_symbol_count(ElfW(Shdr) * vdso_shdr, size_t e_shnum) {
   // iterate all sections until we locate the dynamic symbol section
   for (size_t i = 0; i < e_shnum; ++i) {
@@ -123,11 +105,14 @@ struct VDSOSymbolTable {
   ElfW(Half) * versym;
   Verdef *verdef;
 
-  void populate_symbol_cache(size_t symbol_count, ElfW(Addr) vdso_addr) {
+  void populate_symbol_cache(Symbol::VDSOArray &symbol_table,
+                             size_t symbol_count, ElfW(Addr) vdso_addr) {
     for (size_t i = 0, e = symbol_table.size(); i < e; ++i) {
       Symbol sym = i;
       cpp::string_view name = sym.name();
       cpp::string_view version = sym.version();
+      if (name.empty())
+        return;
       for (size_t j = 0; j < symbol_count; ++j) {
         if (name == strtab + symtab[j].st_name) {
           // we find a symbol with desired name
@@ -200,10 +185,11 @@ struct PhdrInfo {
     return VDSOSymbolTable{strtab, symtab, versym, verdef};
   }
 };
+} // namespace
 
-void initialize_vdso_global_cache() {
+void Symbol::initialize_vdso_global_cache() {
   // first clear the symbol table
-  for (auto &i : symbol_table)
+  for (auto &i : global_cache)
     i = nullptr;
 
   // get the address of the VDSO, protect errno since getauxval may change
@@ -249,20 +235,8 @@ void initialize_vdso_global_cache() {
     return;
 
   // finally, populate the global symbol table cache
-  vdso_symbol_table->populate_symbol_cache(symbol_count, phdr_info->vdso_addr);
-}
-} // namespace
-
-void *get_symbol(VDSOSym sym) {
-  // if sym is invalid, return nullptr
-  Symbol symbol(sym);
-  if (symbol >= symbol_table.size())
-    return nullptr;
-
-  static FutexWordType once_flag = 0;
-  callonce(reinterpret_cast<CallOnceFlag *>(&once_flag),
-           initialize_vdso_global_cache);
-  return symbol_table[symbol];
+  vdso_symbol_table->populate_symbol_cache(global_cache, symbol_count,
+                                           phdr_info->vdso_addr);
 }
 } // namespace vdso
 } // namespace LIBC_NAMESPACE
diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h
index 31d3e413e242dd..6e74d69b4d50c3 100644
--- a/libc/src/__support/OSUtil/linux/vdso.h
+++ b/libc/src/__support/OSUtil/linux/vdso.h
@@ -7,8 +7,28 @@
 //===----------------------------------------------------------------------===//
 #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H
+#include "src/__support/CPP/array.h"
 #include "src/__support/common.h"
+#include "src/__support/macros/attributes.h"
 #include "src/__support/macros/properties/architectures.h"
+#include "src/__support/threads/callonce.h"
+
+namespace LIBC_NAMESPACE {
+namespace vdso {
+enum class VDSOSym {
+  ClockGetTime,
+  ClockGetTime64,
+  GetTimeOfDay,
+  GetCpu,
+  Time,
+  ClockGetRes,
+  RTSigReturn,
+  FlushICache,
+  RiscvHwProbe,
+  VDSOSymCount
+};
+} // namespace vdso
+} // namespace LIBC_NAMESPACE
 
 #if defined(LIBC_TARGET_ARCH_IS_X86)
 #include "x86_64/vdso.h"
@@ -24,7 +44,44 @@
 
 namespace LIBC_NAMESPACE {
 namespace vdso {
-void *get_symbol(VDSOSym);
+class Symbol {
+  VDSOSym sym;
+
+public:
+  LIBC_INLINE_VAR static constexpr size_t COUNT =
+      static_cast<size_t>(VDSOSym::VDSOSymCount);
+  LIBC_INLINE constexpr explicit Symbol(VDSOSym sym) : sym(sym) {}
+  LIBC_INLINE constexpr Symbol(size_t idx) : sym(static_cast<VDSOSym>(idx)) {}
+  LIBC_INLINE constexpr cpp::string_view name() const {
+    return symbol_name(sym);
+  }
+  LIBC_INLINE constexpr cpp::string_view version() const {
+    return symbol_version(sym);
+  }
+  LIBC_INLINE constexpr operator size_t() const {
+    return static_cast<size_t>(sym);
+  }
+  LIBC_INLINE constexpr bool is_valid() const {
+    return *this < Symbol::global_cache.size();
+  }
+  using VDSOArray = cpp::array<void *, Symbol::COUNT>;
+
+private:
+  static CallOnceFlag once_flag;
+  static VDSOArray global_cache;
+  static void initialize_vdso_global_cache();
+  friend void *get_symbol(VDSOSym sym);
+
+public:
+  template <typename T> LIBC_INLINE T get() {
+    if (name().empty() || !is_valid())
+      return nullptr;
+
+    callonce(&once_flag, Symbol::initialize_vdso_global_cache);
+    return cpp::bit_cast<T>(global_cache[*this]);
+  }
+};
+
 } // namespace vdso
 
 } // namespace LIBC_NAMESPACE
diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
index c5b5c45b5b01f9..659d0b6e9a20d3 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
@@ -10,25 +10,6 @@
 #include "src/__support/CPP/string_view.h"
 namespace LIBC_NAMESPACE {
 namespace vdso {
-// macro definitions
-// following the order in
-// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/vdso/vdso.lds.S
-#define LIBC_VDSO_HAS_CLOCK_GETTIME
-#define LIBC_VDSO_HAS_GETTIMEOFDAY
-#define LIBC_VDSO_HAS_GETCPU
-#define LIBC_VDSO_HAS_TIME
-#define LIBC_VDSO_HAS_CLOCK_GETRES
-
-// list of VDSO symbols
-enum class VDSOSym {
-  ClockGetTime,
-  GetTimeOfDay,
-  GetCpu,
-  Time,
-  ClockGetRes,
-  VDSOSymCount
-};
-
 // translate VDSOSym to symbol names
 // On x86, there are symbols defined without the __vdso_ prefix, however,
 // it is suggested that one should use the __vdso_ prefix.
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index f023acff5642ff..9787e8b4561191 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -15,6 +15,7 @@
 #include "hdr/types/time_t.h"
 #include "src/__support/OSUtil/linux/vdso.h"
 #include "src/__support/OSUtil/syscall.h"
+#include "src/__support/macros/properties/architectures.h"
 #include "src/signal/raise.h"
 #include "src/signal/sigaction.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
@@ -24,11 +25,11 @@
 #include <sys/syscall.h>
 
 namespace LIBC_NAMESPACE {
-#ifdef LIBC_VDSO_HAS_GETTIMEOFDAY
+
 TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
   using FuncTy = int (*)(timeval *, struct timezone *);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::GetTimeOfDay));
+  vdso::Symbol symbol{vdso::VDSOSym::GetTimeOfDay};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   timeval tv;
@@ -36,12 +37,11 @@ TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
   // hopefully people are not building time machines using our libc.
   EXPECT_GT(tv.tv_sec, static_cast<decltype(tv.tv_sec)>(0));
 }
-#endif
 
-#ifdef LIBC_VDSO_HAS_TIME
 TEST(LlvmLibcOSUtilVDSOTest, Time) {
   using FuncTy = time_t (*)(time_t *);
-  auto func = reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::Time));
+  vdso::Symbol symbol{vdso::VDSOSym::Time};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   time_t a, b;
@@ -49,15 +49,17 @@ TEST(LlvmLibcOSUtilVDSOTest, Time) {
   EXPECT_GT(func(&b), static_cast<time_t>(0));
   EXPECT_GE(b, a);
 }
-#endif
 
-#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
   using FuncTy = int (*)(clockid_t, timespec *);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetTime));
+  vdso::Symbol symbol{vdso::VDSOSym::ClockGetTime};
+  auto func = symbol.get<FuncTy>();
+#ifdef LIBC_TARGET_ARCH_IS_X86
+  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+#else
   if (func == nullptr)
     return;
+#endif
   timespec a, b;
   EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
   EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
@@ -67,13 +69,11 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
     EXPECT_LT(a.tv_sec, b.tv_sec);
   }
 }
-#endif
 
-#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME64
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
   using FuncTy = int (*)(clockid_t, __kernel_timespec *);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetTime64));
+  vdso::Symbol symbol{vdso::VDSOSym::ClockGetTime64};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   // See kernel API at
@@ -87,27 +87,24 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
     EXPECT_LT(a.tv_sec, b.tv_sec);
   }
 }
-#endif
 
-#ifdef LIBC_VDSO_HAS_CLOCK_GETRES
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetRes) {
   using FuncTy = int (*)(clockid_t, timespec *);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::ClockGetRes));
+  vdso::Symbol symbol{vdso::VDSOSym::ClockGetRes};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   timespec res{};
   EXPECT_EQ(func(CLOCK_MONOTONIC, &res), 0);
   EXPECT_TRUE(res.tv_sec > 0 || res.tv_nsec > 0);
 }
-#endif
 
-#ifdef LIBC_VDSO_HAS_GETCPU
 TEST(LlvmLibcOSUtilVDSOTest, GetCpu) {
   // The kernel system call has a third argument, which should be passed as
   // nullptr.
   using FuncTy = int (*)(int *, int *, void *);
-  auto func = reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::GetCpu));
+  vdso::Symbol symbol{vdso::VDSOSym::GetCpu};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   int cpu = -1, node = -1;
@@ -115,39 +112,23 @@ TEST(LlvmLibcOSUtilVDSOTest, GetCpu) {
   EXPECT_GE(cpu, 0);
   EXPECT_GE(node, 0);
 }
-#endif
-
-// TODO: apply this change to __restore_rt in
-// libc/src/signal/linux/sigaction.cpp
-// Caution: user application typically should not play with the trampoline.
-// Let the libc handle it.
-[[gnu::noreturn]] static void __restore_rt() {
-#ifdef LIBC_VDSO_HAS_RT_SIGRETURN
-  using FuncTy = void (*)();
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::RTSigReturn));
-  if (func) {
-    func();
-    __builtin_trap();
-  }
-#endif
-  LIBC_NAMESPACE::syscall_impl<long>(SYS_rt_sigreturn);
-  __builtin_trap();
-}
 
 static bool flag = false;
-
 static void sigprof_handler [[gnu::used]] (int) { flag = true; }
 
 TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {
   using namespace testing::ErrnoSetterMatcher;
   // must use struct since there is a function of the same name in the same
   // scope.
-  struct sigaction sa{};
-  struct sigaction old_sa{};
+  struct sigaction sa {};
+  struct sigaction old_sa {};
   sa.sa_handler = sigprof_handler;
   sa.sa_flags = SA_RESTORER;
-  sa.sa_restorer = __restore_rt;
+  vdso::Symbol symbol{vdso::VDSOSym::RTSigReturn};
+  auto func = symbol.get<decltype(sa.sa_restorer)>();
+  if (func == nullptr)
+    return;
+  sa.sa_restorer = func;
   ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &sa, &old_sa), Succeeds());
   raise(SIGPROF);
   ASSERT_TRUE(flag);
@@ -155,11 +136,10 @@ TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {
   ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &old_sa, nullptr), Succeeds());
 }
 
-#ifdef LIBC_VDSO_HAS_FLUSH_ICACHE
 TEST(LlvmLibcOSUtilVDSOTest, FlushICache) {
   using FuncTy = void (*)(void *, void *, unsigned long);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::FlushICache));
+  vdso::Symbol symbol{vdso::VDSOSym::FlushICache};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   char buf[512];
@@ -169,11 +149,8 @@ TEST(LlvmLibcOSUtilVDSOTest, FlushICache) {
   func(buf, buf + sizeof(buf), 0);
   func(buf, buf + sizeof(buf), 1);
 }
-#endif
 
 // https://docs.kernel.org/6.5/riscv/hwprobe.html
-
-#ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
 TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
   using namespace testing::ErrnoSetterMatcher;
   struct riscv_hwprobe {
@@ -182,8 +159,8 @@ TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
   };
   using FuncTy =
       long (*)(riscv_hwprobe *, size_t, size_t, struct cpu_set_t *, unsigned);
-  auto func =
-      reinterpret_cast<FuncTy>(vdso::get_symbol(vdso::VDSOSym::RiscvHwProbe));
+  vdso::Symbol symbol{vdso::VDSOSym::RiscvHwProbe};
+  auto func = symbol.get<FuncTy>();
   if (func == nullptr)
     return;
   // If a key is unknown to the kernel, its key field will be cleared to -1, and
@@ -200,6 +177,5 @@ TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
     EXPECT_EQ(probe.value, static_cast<decltype(probe.value)>(0));
   }
 }
-#endif
 
 } // namespace LIBC_NAMESPACE

>From 67053456481e9bbd14aea78f607619c501eb2780 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 8 Jun 2024 17:51:29 -0700
Subject: [PATCH 22/27] add back links to kernel sources

---
 libc/src/__support/OSUtil/linux/aarch64/vdso.h | 1 +
 libc/src/__support/OSUtil/linux/arm/vdso.h     | 1 +
 libc/src/__support/OSUtil/linux/riscv/vdso.h   | 1 +
 libc/src/__support/OSUtil/linux/x86_64/vdso.h  | 1 +
 4 files changed, 4 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/aarch64/vdso.h b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
index 68d2bdaac4fc7f..7e03b6ae41efcf 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/vdso.h
@@ -11,6 +11,7 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // translate VDSOSym to symbol names
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/vdso/vdso.lds.S
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
   case VDSOSym::RTSigReturn:
diff --git a/libc/src/__support/OSUtil/linux/arm/vdso.h b/libc/src/__support/OSUtil/linux/arm/vdso.h
index 1cc41e47a2b7c2..55c39788b16474 100644
--- a/libc/src/__support/OSUtil/linux/arm/vdso.h
+++ b/libc/src/__support/OSUtil/linux/arm/vdso.h
@@ -11,6 +11,7 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // translate VDSOSym to symbol names
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/vdso/vdso.lds.S
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
   case VDSOSym::ClockGetTime:
diff --git a/libc/src/__support/OSUtil/linux/riscv/vdso.h b/libc/src/__support/OSUtil/linux/riscv/vdso.h
index 9a494437fd05fa..37b68bbdd1fe73 100644
--- a/libc/src/__support/OSUtil/linux/riscv/vdso.h
+++ b/libc/src/__support/OSUtil/linux/riscv/vdso.h
@@ -11,6 +11,7 @@
 namespace LIBC_NAMESPACE {
 namespace vdso {
 // translate VDSOSym to symbol names
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/kernel/vdso/vdso.lds.S
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
   case VDSOSym::RTSigReturn:
diff --git a/libc/src/__support/OSUtil/linux/x86_64/vdso.h b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
index 659d0b6e9a20d3..c079e7eb276dbc 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/vdso.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/vdso.h
@@ -15,6 +15,7 @@ namespace vdso {
 // it is suggested that one should use the __vdso_ prefix.
 // Additionally, there is also an __vdso_sgx_enter_enclave, it is for the SGX
 // support, we do not include it here for now.
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/vdso/vdso.lds.S
 LIBC_INLINE constexpr cpp::string_view symbol_name(VDSOSym sym) {
   switch (sym) {
   case VDSOSym::ClockGetTime:

>From 37644c90f288e7ecbdef4344bbe2611953413bbf Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 8 Jun 2024 18:01:59 -0700
Subject: [PATCH 23/27] fix silly bugs

---
 libc/src/__support/OSUtil/linux/vdso.cpp           |  3 ++-
 libc/test/src/__support/OSUtil/linux/vdso_test.cpp | 10 ++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp
index 4e0467d6dade85..211112eca6ad12 100644
--- a/libc/src/__support/OSUtil/linux/vdso.cpp
+++ b/libc/src/__support/OSUtil/linux/vdso.cpp
@@ -112,7 +112,8 @@ struct VDSOSymbolTable {
       cpp::string_view name = sym.name();
       cpp::string_view version = sym.version();
       if (name.empty())
-        return;
+        continue;
+
       for (size_t j = 0; j < symbol_count; ++j) {
         if (name == strtab + symtab[j].st_name) {
           // we find a symbol with desired name
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index 9787e8b4561191..ef0d72d4503b86 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -25,13 +25,19 @@
 #include <sys/syscall.h>
 
 namespace LIBC_NAMESPACE {
+// For x86_64, we explicit that some traditional vdso symbols are indeed
+// available.
 
 TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
   using FuncTy = int (*)(timeval *, struct timezone *);
   vdso::Symbol symbol{vdso::VDSOSym::GetTimeOfDay};
   auto func = symbol.get<FuncTy>();
+#ifdef LIBC_TARGET_ARCH_IS_X86
+  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+#else
   if (func == nullptr)
     return;
+#endif
   timeval tv;
   EXPECT_EQ(func(&tv, nullptr), 0);
   // hopefully people are not building time machines using our libc.
@@ -42,8 +48,12 @@ TEST(LlvmLibcOSUtilVDSOTest, Time) {
   using FuncTy = time_t (*)(time_t *);
   vdso::Symbol symbol{vdso::VDSOSym::Time};
   auto func = symbol.get<FuncTy>();
+#ifdef LIBC_TARGET_ARCH_IS_X86
+  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+#else
   if (func == nullptr)
     return;
+#endif
   time_t a, b;
   EXPECT_GT(func(&a), static_cast<time_t>(0));
   EXPECT_GT(func(&b), static_cast<time_t>(0));

>From 6478047fbbc47876f851066a29bdd6052aba74b3 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sat, 8 Jun 2024 18:06:11 -0700
Subject: [PATCH 24/27] remove extra friend

---
 libc/src/__support/OSUtil/linux/vdso.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h
index 6e74d69b4d50c3..1e31d670d48298 100644
--- a/libc/src/__support/OSUtil/linux/vdso.h
+++ b/libc/src/__support/OSUtil/linux/vdso.h
@@ -70,7 +70,6 @@ class Symbol {
   static CallOnceFlag once_flag;
   static VDSOArray global_cache;
   static void initialize_vdso_global_cache();
-  friend void *get_symbol(VDSOSym sym);
 
 public:
   template <typename T> LIBC_INLINE T get() {

>From 3fefec5b47da0bd359943820a26fedec5be90361 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sun, 9 Jun 2024 15:04:20 -0700
Subject: [PATCH 25/27] fix riscv

---
 libc/src/__support/OSUtil/linux/vdso.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h
index 1e31d670d48298..2a473d72087cc5 100644
--- a/libc/src/__support/OSUtil/linux/vdso.h
+++ b/libc/src/__support/OSUtil/linux/vdso.h
@@ -36,7 +36,7 @@ enum class VDSOSym {
 #include "aarch64/vdso.h"
 #elif defined(LIBC_TARGET_ARCH_IS_ARM)
 #include "arm/vdso.h"
-#elif defined(LIBC_TARGET_ARCH_IS_RISCV)
+#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
 #include "riscv/vdso.h"
 #else
 #error "unknown arch"

>From a275cb87695849601ad0eb6b6ca60617a249dafa Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sun, 9 Jun 2024 15:10:45 -0700
Subject: [PATCH 26/27] fix typo

---
 libc/test/src/__support/OSUtil/linux/vdso_test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index ef0d72d4503b86..b02a30d32e4f9b 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -19,13 +19,13 @@
 #include "src/signal/raise.h"
 #include "src/signal/sigaction.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/LibcTest.h"
+#include "test/UnitTest/LibcTest.h" vdso_test
 #include "test/UnitTest/Test.h"
 #include <linux/time_types.h>
 #include <sys/syscall.h>
 
 namespace LIBC_NAMESPACE {
-// For x86_64, we explicit that some traditional vdso symbols are indeed
+// For x86_64, we explicitly test some traditional vdso symbols are indeed
 // available.
 
 TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {

>From db4ccf5678a9fa5809e480da2f71a24decf24986 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yifzhu at nvidia.com>
Date: Sun, 9 Jun 2024 16:21:48 -0700
Subject: [PATCH 27/27] add typed symbol

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |   4 +
 libc/src/__support/OSUtil/linux/vdso.h        |  80 ++++++++++++-
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 108 ++++++++----------
 3 files changed, 129 insertions(+), 63 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index cf30155eef848e..f04ebed1a17ea9 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -37,6 +37,10 @@ add_object_library(
     libc.src.__support.CPP.string_view
     libc.src.__support.threads.callonce
     libc.src.__support.threads.linux.futex_word_type
+    libc.hdr.types.struct_timeval
+    libc.hdr.types.struct_timespec
+    libc.hdr.types.clockid_t
+    libc.hdr.types.time_t
     libc.src.errno.errno
     libc.src.sys.auxv.getauxval
 )
diff --git a/libc/src/__support/OSUtil/linux/vdso.h b/libc/src/__support/OSUtil/linux/vdso.h
index 2a473d72087cc5..25d2292206ec57 100644
--- a/libc/src/__support/OSUtil/linux/vdso.h
+++ b/libc/src/__support/OSUtil/linux/vdso.h
@@ -7,14 +7,37 @@
 //===----------------------------------------------------------------------===//
 #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_VDSO_H
+#include "hdr/types/clock_t.h"
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "hdr/types/struct_timeval.h"
+#include "hdr/types/time_t.h"
 #include "src/__support/CPP/array.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/attributes.h"
 #include "src/__support/macros/properties/architectures.h"
 #include "src/__support/threads/callonce.h"
 
+// NOLINTBEGIN(llvmlibc-implementation-in-namespace)
+// TODO: some of the following can be defined via proxy headers.
+struct __kernel_timespec;
+struct timezone;
+struct riscv_hwprobe;
+struct getcpu_cache;
+struct cpu_set_t;
+// NOLINTEND(llvmlibc-implementation-in-namespace)
+
 namespace LIBC_NAMESPACE {
 namespace vdso {
+
+#ifdef __clang__
+__extension__ template <typename T> using NullablePtr = T *_Nullable;
+__extension__ template <typename T> using NonNullPtr = T *_Nonnull;
+#else
+template <typename T> using NullablePtr = T *;
+template <typename T> using NonNullPtr = T *;
+#endif
+
 enum class VDSOSym {
   ClockGetTime,
   ClockGetTime64,
@@ -44,6 +67,52 @@ enum class VDSOSym {
 
 namespace LIBC_NAMESPACE {
 namespace vdso {
+
+template <VDSOSym sym> struct VDSOTypeDispatch {
+  using Type = void *;
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::ClockGetTime> {
+  using Type = int (*)(clockid_t, NonNullPtr<timespec>);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::ClockGetTime64> {
+  using Type = int (*)(clockid_t, NonNullPtr<__kernel_timespec>);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::GetTimeOfDay> {
+  using Type = int (*)(NonNullPtr<timeval> __restrict,
+                       NullablePtr<timezone> __restrict);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::GetCpu> {
+  using Type = int (*)(NullablePtr<unsigned>, NullablePtr<unsigned>,
+                       NullablePtr<getcpu_cache>);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::Time> {
+  using Type = time_t (*)(NullablePtr<time_t>);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::ClockGetRes> {
+  using Type = int (*)(clockid_t, NullablePtr<timespec>);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::RTSigReturn> {
+  using Type = void (*)(void);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::FlushICache> {
+  using Type = void (*)(NullablePtr<void>, NullablePtr<void>, unsigned int);
+};
+
+template <> struct VDSOTypeDispatch<VDSOSym::RiscvHwProbe> {
+  using Type = int (*)(NullablePtr<riscv_hwprobe> __restrict, size_t, size_t,
+                       NullablePtr<cpu_set_t> __restrict, unsigned);
+};
+
+template <VDSOSym sym> using VDSOSymType = typename VDSOTypeDispatch<sym>::Type;
+
 class Symbol {
   VDSOSym sym;
 
@@ -71,7 +140,6 @@ class Symbol {
   static VDSOArray global_cache;
   static void initialize_vdso_global_cache();
 
-public:
   template <typename T> LIBC_INLINE T get() {
     if (name().empty() || !is_valid())
       return nullptr;
@@ -79,6 +147,16 @@ class Symbol {
     callonce(&once_flag, Symbol::initialize_vdso_global_cache);
     return cpp::bit_cast<T>(global_cache[*this]);
   }
+  template <VDSOSym sym> friend struct TypedSymbol;
+};
+
+template <VDSOSym sym> struct TypedSymbol {
+  LIBC_INLINE constexpr operator VDSOSymType<sym>() const {
+    return Symbol{sym}.get<VDSOSymType<sym>>();
+  }
+  template <typename... Args> LIBC_INLINE auto operator()(Args &&...args) {
+    return this->operator VDSOSymType<sym>()(cpp::forward<Args>(args)...);
+  }
 };
 
 } // namespace vdso
diff --git a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
index b02a30d32e4f9b..808fd9b9e5eb24 100644
--- a/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -19,60 +19,60 @@
 #include "src/signal/raise.h"
 #include "src/signal/sigaction.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/LibcTest.h" vdso_test
+#include "test/UnitTest/LibcTest.h"
 #include "test/UnitTest/Test.h"
 #include <linux/time_types.h>
 #include <sys/syscall.h>
 
+struct riscv_hwprobe {
+  int64_t key;
+  uint64_t value;
+};
+
 namespace LIBC_NAMESPACE {
 // For x86_64, we explicitly test some traditional vdso symbols are indeed
 // available.
 
 TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
-  using FuncTy = int (*)(timeval *, struct timezone *);
-  vdso::Symbol symbol{vdso::VDSOSym::GetTimeOfDay};
-  auto func = symbol.get<FuncTy>();
+  vdso::TypedSymbol<vdso::VDSOSym::GetTimeOfDay> symbol;
+
 #ifdef LIBC_TARGET_ARCH_IS_X86
-  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+  ASSERT_TRUE(symbol != nullptr);
 #else
-  if (func == nullptr)
+  if (!symbol)
     return;
 #endif
   timeval tv;
-  EXPECT_EQ(func(&tv, nullptr), 0);
+  EXPECT_EQ(symbol(&tv, nullptr), 0);
   // hopefully people are not building time machines using our libc.
   EXPECT_GT(tv.tv_sec, static_cast<decltype(tv.tv_sec)>(0));
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, Time) {
-  using FuncTy = time_t (*)(time_t *);
-  vdso::Symbol symbol{vdso::VDSOSym::Time};
-  auto func = symbol.get<FuncTy>();
+  vdso::TypedSymbol<vdso::VDSOSym::Time> symbol;
 #ifdef LIBC_TARGET_ARCH_IS_X86
-  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+  ASSERT_TRUE(symbol != nullptr);
 #else
-  if (func == nullptr)
+  if (!symbol)
     return;
 #endif
   time_t a, b;
-  EXPECT_GT(func(&a), static_cast<time_t>(0));
-  EXPECT_GT(func(&b), static_cast<time_t>(0));
+  EXPECT_GT(symbol(&a), static_cast<time_t>(0));
+  EXPECT_GT(symbol(&b), static_cast<time_t>(0));
   EXPECT_GE(b, a);
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
-  using FuncTy = int (*)(clockid_t, timespec *);
-  vdso::Symbol symbol{vdso::VDSOSym::ClockGetTime};
-  auto func = symbol.get<FuncTy>();
+  vdso::TypedSymbol<vdso::VDSOSym::ClockGetTime> symbol;
 #ifdef LIBC_TARGET_ARCH_IS_X86
-  ASSERT_NE(func, static_cast<FuncTy>(nullptr));
+  ASSERT_TRUE(symbol != nullptr);
 #else
-  if (func == nullptr)
+  if (!symbol)
     return;
 #endif
   timespec a, b;
-  EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
-  EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
+  EXPECT_EQ(symbol(CLOCK_MONOTONIC, &a), 0);
+  EXPECT_EQ(symbol(CLOCK_MONOTONIC, &b), 0);
   if (a.tv_sec == b.tv_sec) {
     EXPECT_LT(a.tv_nsec, b.tv_nsec);
   } else {
@@ -81,16 +81,14 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
-  using FuncTy = int (*)(clockid_t, __kernel_timespec *);
-  vdso::Symbol symbol{vdso::VDSOSym::ClockGetTime64};
-  auto func = symbol.get<FuncTy>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::ClockGetTime64> symbol;
+  if (!symbol)
     return;
   // See kernel API at
   // https://elixir.bootlin.com/linux/latest/source/tools/testing/selftests/vDSO/vdso_test_correctness.c#L155
   __kernel_timespec a, b;
-  EXPECT_EQ(func(CLOCK_MONOTONIC, &a), 0);
-  EXPECT_EQ(func(CLOCK_MONOTONIC, &b), 0);
+  EXPECT_EQ(symbol(CLOCK_MONOTONIC, &a), 0);
+  EXPECT_EQ(symbol(CLOCK_MONOTONIC, &b), 0);
   if (a.tv_sec == b.tv_sec) {
     EXPECT_LT(a.tv_nsec, b.tv_nsec);
   } else {
@@ -99,28 +97,24 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, ClockGetRes) {
-  using FuncTy = int (*)(clockid_t, timespec *);
-  vdso::Symbol symbol{vdso::VDSOSym::ClockGetRes};
-  auto func = symbol.get<FuncTy>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::ClockGetRes> symbol;
+  if (!symbol)
     return;
   timespec res{};
-  EXPECT_EQ(func(CLOCK_MONOTONIC, &res), 0);
+  EXPECT_EQ(symbol(CLOCK_MONOTONIC, &res), 0);
   EXPECT_TRUE(res.tv_sec > 0 || res.tv_nsec > 0);
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, GetCpu) {
   // The kernel system call has a third argument, which should be passed as
   // nullptr.
-  using FuncTy = int (*)(int *, int *, void *);
-  vdso::Symbol symbol{vdso::VDSOSym::GetCpu};
-  auto func = symbol.get<FuncTy>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::GetCpu> symbol;
+  if (!symbol)
     return;
-  int cpu = -1, node = -1;
-  EXPECT_EQ(func(&cpu, &node, nullptr), 0);
-  EXPECT_GE(cpu, 0);
-  EXPECT_GE(node, 0);
+  unsigned cpu = static_cast<unsigned>(-1), node = static_cast<unsigned>(-1);
+  EXPECT_EQ(symbol(&cpu, &node, nullptr), 0);
+  EXPECT_GE(cpu, 0u);
+  EXPECT_GE(node, 0u);
 }
 
 static bool flag = false;
@@ -134,11 +128,10 @@ TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {
   struct sigaction old_sa {};
   sa.sa_handler = sigprof_handler;
   sa.sa_flags = SA_RESTORER;
-  vdso::Symbol symbol{vdso::VDSOSym::RTSigReturn};
-  auto func = symbol.get<decltype(sa.sa_restorer)>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::RTSigReturn> symbol;
+  if (!symbol)
     return;
-  sa.sa_restorer = func;
+  sa.sa_restorer = symbol;
   ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &sa, &old_sa), Succeeds());
   raise(SIGPROF);
   ASSERT_TRUE(flag);
@@ -147,40 +140,31 @@ TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {
 }
 
 TEST(LlvmLibcOSUtilVDSOTest, FlushICache) {
-  using FuncTy = void (*)(void *, void *, unsigned long);
-  vdso::Symbol symbol{vdso::VDSOSym::FlushICache};
-  auto func = symbol.get<FuncTy>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::FlushICache> symbol;
+  if (!symbol)
     return;
   char buf[512];
   // we just check that the flush will not panic the program.
   // the flags part only take 0/1 as up to kernel 6.10, which is used to
   // indicate whether the flush is local to the core or global.
-  func(buf, buf + sizeof(buf), 0);
-  func(buf, buf + sizeof(buf), 1);
+  symbol(buf, buf + sizeof(buf), 0);
+  symbol(buf, buf + sizeof(buf), 1);
 }
 
 // https://docs.kernel.org/6.5/riscv/hwprobe.html
 TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
   using namespace testing::ErrnoSetterMatcher;
-  struct riscv_hwprobe {
-    int64_t key;
-    uint64_t value;
-  };
-  using FuncTy =
-      long (*)(riscv_hwprobe *, size_t, size_t, struct cpu_set_t *, unsigned);
-  vdso::Symbol symbol{vdso::VDSOSym::RiscvHwProbe};
-  auto func = symbol.get<FuncTy>();
-  if (func == nullptr)
+  vdso::TypedSymbol<vdso::VDSOSym::RiscvHwProbe> symbol;
+  if (!symbol)
     return;
   // If a key is unknown to the kernel, its key field will be cleared to -1, and
   // its value set to 0. We expect probes.value are all 0.
   // Usermode can supply NULL for cpus and 0 for cpu_count as a shortcut for all
   // online CPUs
   riscv_hwprobe probes[2] = {{-1, 1}, {-1, 1}};
-  ASSERT_THAT(func(/*pairs=*/probes, /*count=*/2, /*cpusetsize=*/0,
-                   /*cpuset=*/nullptr,
-                   /*flags=*/0),
+  ASSERT_THAT(symbol(/*pairs=*/probes, /*count=*/2, /*cpusetsize=*/0,
+                     /*cpuset=*/nullptr,
+                     /*flags=*/0),
               Succeeds());
   for (auto &probe : probes) {
     EXPECT_EQ(probe.key, static_cast<decltype(probe.key)>(-1));



More information about the libc-commits mailing list