[libc-commits] [libc] a1d21cc - [libc] Add barebones dl_iterate_phdr implementation (#194196)

via libc-commits libc-commits at lists.llvm.org
Sat May 9 23:08:54 PDT 2026


Author: Aiden Grossman
Date: 2026-05-09T23:08:49-07:00
New Revision: a1d21ccf78e7893134c8c8cccd78e7d7d545a9c3

URL: https://github.com/llvm/llvm-project/commit/a1d21ccf78e7893134c8c8cccd78e7d7d545a9c3
DIFF: https://github.com/llvm/llvm-project/commit/a1d21ccf78e7893134c8c8cccd78e7d7d545a9c3.diff

LOG: [libc] Add barebones dl_iterate_phdr implementation (#194196)

Add a basic dl_iterate_phdr implementation so that we can get libunwind
building. This implementation is bare and not fully compliant with the
man page for fully static binaries (which are all that we support
currently with the lack of a dynamic linker) due to the lack of TLS
info, but that can be added at a future date if it is needed, as it is
not needed by libunwind.

Add some very basic smoke tests.

Added: 
    libc/test/src/link/CMakeLists.txt
    libc/test/src/link/dl_iterate_phdr_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/src/link/CMakeLists.txt
    libc/src/link/dl_iterate_phdr.cpp
    libc/test/src/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index a0fb4663c1e54..643bba2aae694 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1243,6 +1243,9 @@ if(LLVM_LIBC_FULL_BUILD)
     # sys/select.h entrypoints
     libc.src.sys.select.select
 
+    # link.h entrypoints
+    libc.src.link.dl_iterate_phdr
+
     # wchar.h entrypoints
     # libc.src.wchar.fgetwc
     # libc.src.wchar.fgetws

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index f67984d4f6484..bbb7aca7f39b6 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1377,6 +1377,9 @@ if(LLVM_LIBC_FULL_BUILD)
     # sys/select.h entrypoints
     libc.src.sys.select.select
 
+    # link.h entrypoints
+    libc.src.link.dl_iterate_phdr
+
     # wchar.h entrypoints
     # libc.src.wchar.fgetwc
     # libc.src.wchar.fgetws

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b6247c1172150..2a0e43744ec0d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1478,6 +1478,9 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.nl_types.catopen
     libc.src.nl_types.catclose
     libc.src.nl_types.catgets
+
+    # link.h entrypoints
+    libc.src.link.dl_iterate_phdr
   )
 endif()
 

diff  --git a/libc/src/link/CMakeLists.txt b/libc/src/link/CMakeLists.txt
index 55f5edfab7d93..ae2b1df6ea71a 100644
--- a/libc/src/link/CMakeLists.txt
+++ b/libc/src/link/CMakeLists.txt
@@ -6,4 +6,6 @@ add_entrypoint_object(
     dl_iterate_phdr.h
   DEPENDS
     libc.hdr.stdint_proxy
+    libc.src.__support.CPP.span
+    libc.src.__support.OSUtil.linux.auxv
 )

diff  --git a/libc/src/link/dl_iterate_phdr.cpp b/libc/src/link/dl_iterate_phdr.cpp
index 7964411598d4a..166f50fdfee86 100644
--- a/libc/src/link/dl_iterate_phdr.cpp
+++ b/libc/src/link/dl_iterate_phdr.cpp
@@ -5,21 +5,68 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===---------------------------------------------------------------------===//
+///
+/// \file
+/// The dl_iterate_phdr implementation.
+///
+//===----------------------------------------------------------------------===/
 
 #include "dl_iterate_phdr.h"
 
+#include "llvm-libc-macros/link-macros.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/OSUtil/linux/auxv.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 
+#include <elf.h>
+
+extern "C" void *__ehdr_start;
+
 namespace LIBC_NAMESPACE_DECL {
 
+struct dl_phdr_info create_executable_info(ElfW(Ehdr) * executable_header) {
+  // TODO: Calculate dlpi_addr in the PIE case and set dlpi_name for VDSO.
+  struct dl_phdr_info to_return;
+  to_return.dlpi_addr = 0;
+  to_return.dlpi_name = "";
+  to_return.dlpi_phdr = reinterpret_cast<ElfW(Phdr) *>(
+      reinterpret_cast<uintptr_t>(executable_header) +
+      executable_header->e_phoff);
+  to_return.dlpi_phnum = executable_header->e_phnum;
+  to_return.dlpi_adds = 0;
+  to_return.dlpi_subs = 0;
+  to_return.dlpi_tls_modid = 0;
+  to_return.dlpi_tls_data = nullptr;
+  return to_return;
+}
+
 LLVM_LIBC_FUNCTION(int, dl_iterate_phdr,
                    (__dl_iterate_phdr_callback_t callback, void *arg)) {
-  // FIXME: For pure static linking, this can report just the executable with
-  // info from __ehdr_start or AT_{PHDR,PHNUM} decoding, and its PT_TLS; and it
-  // could report the vDSO.
-  (void)callback, (void)arg;
-  return 0;
+  ElfW(Ehdr) *executable_header = reinterpret_cast<ElfW(Ehdr) *>(&__ehdr_start);
+  struct dl_phdr_info executable_info =
+      create_executable_info(executable_header);
+  int executable_return_code =
+      callback(&executable_info, sizeof(executable_info), arg);
+  if (executable_return_code != 0)
+    return executable_return_code;
+
+  cpp::optional<unsigned long> vdso_start_address = auxv::get(AT_SYSINFO_EHDR);
+  if (!vdso_start_address)
+    return 0;
+  ElfW(Ehdr) *vdso_header = reinterpret_cast<ElfW(Ehdr) *>(*vdso_start_address);
+  if (vdso_header == nullptr)
+    return 0;
+  struct dl_phdr_info vdso_info = create_executable_info(vdso_header);
+  for (auto elf_headers :
+       cpp::span<const ElfW(Phdr)>(vdso_info.dlpi_phdr, vdso_info.dlpi_phnum)) {
+    if (elf_headers.p_type == PT_LOAD) {
+      vdso_info.dlpi_addr =
+          reinterpret_cast<ElfW(Addr)>(vdso_header) - elf_headers.p_vaddr;
+      break;
+    }
+  }
+  return callback(&vdso_info, sizeof(vdso_info), arg);
 }
 
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 7bdafc6a85706..b877c7455fc34 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -62,6 +62,7 @@ add_subdirectory(complex)
 add_subdirectory(ctype)
 add_subdirectory(errno)
 add_subdirectory(fenv)
+add_subdirectory(link)
 add_subdirectory(math)
 add_subdirectory(search)
 add_subdirectory(setjmp)

diff  --git a/libc/test/src/link/CMakeLists.txt b/libc/test/src/link/CMakeLists.txt
new file mode 100644
index 0000000000000..efae9cf7e3d9b
--- /dev/null
+++ b/libc/test/src/link/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_custom_target(libc_link_unittests)
+
+add_libc_unittest(
+  dl_iterate_phdr_test
+  SUITE
+    libc_link_unittests
+  SRCS
+    dl_iterate_phdr_test.cpp
+  DEPENDS
+    libc.src.link.dl_iterate_phdr
+)

diff  --git a/libc/test/src/link/dl_iterate_phdr_test.cpp b/libc/test/src/link/dl_iterate_phdr_test.cpp
new file mode 100644
index 0000000000000..c3c8a5e89663c
--- /dev/null
+++ b/libc/test/src/link/dl_iterate_phdr_test.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===/
+///
+/// \file
+/// Tests for the dl_iterate_phdr implementation.
+///
+//===----------------------------------------------------------------------===/
+
+#include "hdr/types/size_t.h"
+#include "src/link/dl_iterate_phdr.h"
+#include "test/UnitTest/Test.h"
+
+int save_return_1(struct dl_phdr_info *info, [[maybe_unused]] size_t info_size,
+                  void *arg) {
+  *static_cast<int *>(arg) = info->dlpi_phnum;
+  return 1;
+}
+
+TEST(LlvmLibcLinkDlIteratePhdrTest, OnlyExecutable) {
+  int program_header_count = 0;
+  EXPECT_EQ(
+      LIBC_NAMESPACE::dl_iterate_phdr(save_return_1, &program_header_count), 1);
+  EXPECT_GT(program_header_count, 0);
+}
+
+int save_return_0(struct dl_phdr_info *info, [[maybe_unused]] size_t info_size,
+                  void *arg) {
+  *static_cast<int *>(arg) = info->dlpi_phnum;
+  return 0;
+}
+
+TEST(LlvmLibcLinkDlIteratePhdrTest, BothExecutableAndVDSO) {
+  int program_header_count = 0;
+  EXPECT_EQ(
+      LIBC_NAMESPACE::dl_iterate_phdr(save_return_0, &program_header_count), 0);
+  EXPECT_GT(program_header_count, 0);
+}


        


More information about the libc-commits mailing list