[libc-commits] [libc] [libc] Add barebones dl_iterate_phdr implementation (PR #194196)
Aiden Grossman via libc-commits
libc-commits at lists.llvm.org
Sat Apr 25 17:11:11 PDT 2026
https://github.com/boomanaiden154 created https://github.com/llvm/llvm-project/pull/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.
>From 8f102d069ba37a723f51ee1b33ba521f3efe8e0b Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sun, 26 Apr 2026 00:08:44 +0000
Subject: [PATCH] [libc] Add barebones dl_iterate_phdr implementation
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.
---
libc/config/linux/x86_64/entrypoints.txt | 3 ++
libc/src/link/CMakeLists.txt | 1 +
libc/src/link/dl_iterate_phdr.cpp | 53 +++++++++++++++++++--
libc/test/src/CMakeLists.txt | 1 +
libc/test/src/link/CMakeLists.txt | 11 +++++
libc/test/src/link/dl_iterate_phdr_test.cpp | 37 ++++++++++++++
6 files changed, 101 insertions(+), 5 deletions(-)
create mode 100644 libc/test/src/link/CMakeLists.txt
create mode 100644 libc/test/src/link/dl_iterate_phdr_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d1c1d9496af67..9c796bf4ac94e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1462,6 +1462,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..47a7f5a2af605 100644
--- a/libc/src/link/CMakeLists.txt
+++ b/libc/src/link/CMakeLists.txt
@@ -6,4 +6,5 @@ add_entrypoint_object(
dl_iterate_phdr.h
DEPENDS
libc.hdr.stdint_proxy
+ libc.hdr.sys_auxv_macros
)
diff --git a/libc/src/link/dl_iterate_phdr.cpp b/libc/src/link/dl_iterate_phdr.cpp
index 7964411598d4a..bb0f0edb15fc4 100644
--- a/libc/src/link/dl_iterate_phdr.cpp
+++ b/libc/src/link/dl_iterate_phdr.cpp
@@ -8,18 +8,61 @@
#include "dl_iterate_phdr.h"
+#include "llvm-libc-macros/link-macros.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 *__executable_start;
+
namespace LIBC_NAMESPACE_DECL {
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) *>(&__executable_start);
+ struct dl_phdr_info executable_info;
+ executable_info.dlpi_addr = 0;
+ executable_info.dlpi_name = nullptr;
+ executable_info.dlpi_phdr = reinterpret_cast<ElfW(Phdr) *>(
+ reinterpret_cast<uintptr_t>(executable_header) +
+ executable_header->e_phoff);
+ executable_info.dlpi_phnum = executable_header->e_phnum;
+ executable_info.dlpi_adds = 0;
+ executable_info.dlpi_subs = 0;
+ executable_info.dlpi_tls_modid = 0;
+ executable_info.dlpi_tls_data = nullptr;
+ 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 =
+ LIBC_NAMESPACE::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;
+ vdso_info.dlpi_addr = 0;
+ vdso_info.dlpi_phdr = reinterpret_cast<ElfW(Phdr) *>(
+ reinterpret_cast<char *>(vdso_header) + vdso_header->e_phoff);
+ vdso_info.dlpi_phnum = vdso_header->e_phnum;
+ vdso_info.dlpi_adds = 0;
+ vdso_info.dlpi_subs = 0;
+ vdso_info.dlpi_tls_modid = 0;
+ vdso_info.dlpi_tls_data = nullptr;
+ for (size_t i = 0; i < vdso_info.dlpi_phnum; ++i) {
+ if (vdso_info.dlpi_phdr[i].p_type == PT_LOAD) {
+ vdso_info.dlpi_addr =
+ (ElfW(Addr))vdso_header - vdso_info.dlpi_phdr[i].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..4817b0fe7957b
--- /dev/null
+++ b/libc/test/src/link/dl_iterate_phdr_test.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "hdr/types/size_t.h"
+#include "src/link/dl_iterate_phdr.h"
+#include "test/UnitTest/Test.h"
+
+int SaveReturn1(struct dl_phdr_info *info, [[maybe_unused]] size_t info_size,
+ void *arg) {
+ *static_cast<void **>(arg) = info;
+ return 1;
+}
+
+TEST(LlvmLibcLinkDlIteratePhdrTest, OnlyExecutable) {
+ struct dl_phdr_info executable_info;
+ EXPECT_EQ(LIBC_NAMESPACE::dl_iterate_phdr(SaveReturn1, &executable_info), 1);
+ int program_header_count = executable_info.dlpi_phnum;
+ EXPECT_GT(program_header_count, 0);
+}
+
+int SaveReturn0(struct dl_phdr_info *info, [[maybe_unused]] size_t info_size,
+ void *arg) {
+ *static_cast<void **>(arg) = info;
+ return 0;
+}
+
+TEST(LlvmLibcLinkDlIteratePhdrTest, BothExecutableAndVDSO) {
+ struct dl_phdr_info executable_info;
+ EXPECT_EQ(LIBC_NAMESPACE::dl_iterate_phdr(SaveReturn0, &executable_info), 0);
+ int program_header_count = executable_info.dlpi_phnum;
+ EXPECT_GT(program_header_count, 0);
+}
More information about the libc-commits
mailing list