[libc-commits] [libc] [libc] Add barebones dl_iterate_phdr implementation (PR #194196)
via libc-commits
libc-commits at lists.llvm.org
Sat Apr 25 17:11:44 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Aiden Grossman (boomanaiden154)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/194196.diff
6 Files Affected:
- (modified) libc/config/linux/x86_64/entrypoints.txt (+3)
- (modified) libc/src/link/CMakeLists.txt (+1)
- (modified) libc/src/link/dl_iterate_phdr.cpp (+48-5)
- (modified) libc/test/src/CMakeLists.txt (+1)
- (added) libc/test/src/link/CMakeLists.txt (+11)
- (added) libc/test/src/link/dl_iterate_phdr_test.cpp (+37)
``````````diff
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);
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/194196
More information about the libc-commits
mailing list