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

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Thu May 9 09:19:08 PDT 2024


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

>From 3c30e8fadb8a8e8362458087a0d5c573e3708ad4 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 1/2] [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 94d1042ccbb4..78285c960c0a 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 000000000000..177d29f87969
--- /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 239d11570492..e7411c14711d 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -16,3 +16,19 @@ add_object_library(
     libc.src.__support.common
     libc.src.__support.CPP.string_view
 )
+
+add_object_library(
+  vdso
+  HDRS
+    vdso.h
+  SRCS
+    vdso.cpp
+  DEPENDS
+    .${LIBC_TARGET_ARCHITECTURE}.vdso
+    libc.src.__support.CPP.array
+    libc.src.__support.CPP.string_view
+    libc.src.__support.threads.callonce
+    libc.src.__support.threads.linux.futex_word_type
+    libc.src.errno.errno
+    libc.src.sys.auxv.getauxval
+)
diff --git a/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt b/libc/src/__support/OSUtil/linux/aarch64/CMakeLists.txt
index eea9badc46ca..68ce1d74c209 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 000000000000..55024e61ee91
--- /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 733366f6d4a2..36c991425e60 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 000000000000..5d9ff5d929ab
--- /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 e271204f5198..b2e2401ece1a 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 000000000000..394c06e6a5a7
--- /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 000000000000..2b2c02ec69fe
--- /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 000000000000..2d71db13303f
--- /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 a7f2d74e6353..cb5938ef94d7 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 000000000000..13b8e3d8cc6f
--- /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 000000000000..93bbc98da19b
--- /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 d77f0c55ad73c465d3689675a8a3a58c4eeb70d5 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 2/2] [libc] add simple tests for vDSO symbols

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |  9 +++++
 .../src/__support/OSUtil/linux/vdso_test.cpp  | 34 +++++++++++++++++++
 2 files changed, 43 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 bfb072c03e97..29c95ea27d70 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 000000000000..e55a387b5f88
--- /dev/null
+++ b/libc/test/src/__support/OSUtil/linux/vdso_test.cpp
@@ -0,0 +1,34 @@
+//===-- 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) {
+  // for now, we simply test all symbols are provided.
+  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 timemachines using our libc.
+  EXPECT_GT(tv.tv_sec, static_cast<decltype(tv.tv_sec)>(0));
+}
+#endif
+
+} // namespace LIBC_NAMESPACE



More information about the libc-commits mailing list