diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 00f0c6a8bfb8e..ad71df4e6801d 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -18,11 +18,15 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.ctype.toupper # dlfcn.h entrypoints + libc.src.dlfcn.dladdr libc.src.dlfcn.dlclose libc.src.dlfcn.dlerror libc.src.dlfcn.dlopen libc.src.dlfcn.dlsym + # link.h entrypoints + libc.src.link.dl_iterate_phdr + # errno.h entrypoints libc.src.errno.errno diff --git a/libc/hdrgen/yaml/dlfcn.yaml b/libc/hdrgen/yaml/dlfcn.yaml index 725ee705714a7..56c37bf20b2f9 100644 --- a/libc/hdrgen/yaml/dlfcn.yaml +++ b/libc/hdrgen/yaml/dlfcn.yaml @@ -8,7 +8,8 @@ macros: macro_value: null - macro_name: RTLD_LOCAL macro_value: null -types: [] +types: + - type_name: Dl_info enums: [] objects: [] functions: @@ -37,3 +38,10 @@ functions: arguments: - type: void *__restrict - type: const char *__restrict + - name: dladdr + standards: + - GNUExtensions + return_type: int + arguments: + - type: const void * + - type: Dl_info * diff --git a/libc/hdrgen/yaml/link.yaml b/libc/hdrgen/yaml/link.yaml index d1963a86813af..acc96eb8fc27b 100644 --- a/libc/hdrgen/yaml/link.yaml +++ b/libc/hdrgen/yaml/link.yaml @@ -2,7 +2,16 @@ header: link.h standards: - Linux macros: [] -types: [] +types: + - type_name: struct_dl_phdr_info + - type_name: __dl_iterate_phdr_callback_t enums: [] objects: [] -functions: [] +functions: + - name: dl_iterate_phdr + standards: + - Linux + return_type: int + arguments: + - type: __dl_iterate_phdr_callback_t + - type: void * diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 3a05c01abba5a..21bb341664eff 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -75,6 +75,7 @@ add_header_macro( dlfcn.h DEPENDS .llvm-libc-macros.dlfcn_macros + .llvm-libc-types.Dl_info .llvm_libc_common_h ) @@ -444,6 +445,8 @@ add_header_macro( link.h DEPENDS .llvm_libc_common_h + .llvm-libc-types.__dl_iterate_phdr_callback_t + .llvm-libc-types.struct_dl_phdr_info .llvm-libc-macros.link_macros ) diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index ee734eafce362..6698516be189a 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -1,3 +1,4 @@ +add_header(Dl_info HDR Dl_info.h) add_header(off64_t HDR off64_t.h) add_header(size_t HDR size_t.h) add_header(ssize_t HDR ssize_t.h) @@ -67,6 +68,8 @@ else() endif() add_header(stack_t HDR stack_t.h DEPENDS .size_t) add_header(suseconds_t HDR suseconds_t.h) +add_header(struct_dl_phdr_info HDR struct_dl_phdr_info.h DEPENDS .size_t libc.include.llvm-libc-macros.link_macros) +add_header(__dl_iterate_phdr_callback_t HDR __dl_iterate_phdr_callback_t.h DEPENDS .size_t .struct_dl_phdr_info) add_header(struct_flock HDR struct_flock.h DEPENDS .off_t .pid_t) add_header(struct_flock64 HDR struct_flock64.h DEPENDS .off64_t .pid_t) add_header(struct_f_owner_ex HDR struct_f_owner_ex.h DEPENDS .pid_t) diff --git a/libc/include/llvm-libc-types/Dl_info.h b/libc/include/llvm-libc-types/Dl_info.h new file mode 100644 index 0000000000000..b082e30549a02 --- /dev/null +++ b/libc/include/llvm-libc-types/Dl_info.h @@ -0,0 +1,19 @@ +//===-- Definition of Dl_info type ----------------------------------------===// +// +// 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_TYPES_DL_INFO_H +#define LLVM_LIBC_TYPES_DL_INFO_H + +typedef struct { + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +#endif // LLVM_LIBC_TYPES_DL_INFO_H diff --git a/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h b/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h new file mode 100644 index 0000000000000..2f9a14cf5706c --- /dev/null +++ b/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h @@ -0,0 +1,18 @@ +//===-- Definition of type __dl_iterate_phdr_callback_t -------------------===// +// +// 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_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H +#define LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H + +#include "size_t.h" +#include "struct_dl_phdr_info.h" + +typedef int (*__dl_iterate_phdr_callback_t)(struct dl_phdr_info *, size_t, + void *); + +#endif // LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H diff --git a/libc/include/llvm-libc-types/struct_dl_phdr_info.h b/libc/include/llvm-libc-types/struct_dl_phdr_info.h new file mode 100644 index 0000000000000..fc407e3e954e7 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_dl_phdr_info.h @@ -0,0 +1,26 @@ +//===-- Definition of type struct dl_phdr_info ----------------------------===// +// +// 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_TYPES_STRUCT_DL_PHDR_INFO_H +#define LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H + +#include "../llvm-libc-macros/link-macros.h" +#include "size_t.h" + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) * dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long dlpi_adds; + unsigned long long dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +#endif // LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt index 9fc331ad18a39..268d977d28a8c 100644 --- a/libc/src/CMakeLists.txt +++ b/libc/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(dlfcn) add_subdirectory(errno) add_subdirectory(fenv) add_subdirectory(inttypes) +add_subdirectory(link) add_subdirectory(math) add_subdirectory(stdbit) add_subdirectory(stdfix) diff --git a/libc/src/dlfcn/CMakeLists.txt b/libc/src/dlfcn/CMakeLists.txt index e3a51ba65764d..205275a682573 100644 --- a/libc/src/dlfcn/CMakeLists.txt +++ b/libc/src/dlfcn/CMakeLists.txt @@ -1,3 +1,13 @@ +add_entrypoint_object( + dladdr + SRCS + dladdr.cpp + HDRS + dladdr.h + DEPENDS + libc.include.dlfcn +) + add_entrypoint_object( dlclose SRCS diff --git a/libc/src/dlfcn/dladdr.cpp b/libc/src/dlfcn/dladdr.cpp new file mode 100644 index 0000000000000..824b4553120a2 --- /dev/null +++ b/libc/src/dlfcn/dladdr.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of dladdr -----------------------------------------===// +// +// 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 "dladdr.h" + +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, dladdr, (const void *, Dl_info *)) { return -1; } + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/dlfcn/dladdr.h b/libc/src/dlfcn/dladdr.h new file mode 100644 index 0000000000000..58b859ff91e7e --- /dev/null +++ b/libc/src/dlfcn/dladdr.h @@ -0,0 +1,21 @@ +//===-- Implementation header of dladdr ------------------------*- 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_DLFCN_DLADDR_H +#define LLVM_LIBC_SRC_DLFCN_DLADDR_H + +#include "include/llvm-libc-types/Dl_info.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int dladdr(const void *, Dl_info *); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_DLFCN_DLADDR_H diff --git a/libc/src/link/CMakeLists.txt b/libc/src/link/CMakeLists.txt new file mode 100644 index 0000000000000..05c73a999d549 --- /dev/null +++ b/libc/src/link/CMakeLists.txt @@ -0,0 +1,10 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif() + +add_entrypoint_object( + dl_iterate_phdr + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.dl_iterate_phdr +) diff --git a/libc/src/link/dl_iterate_phdr.h b/libc/src/link/dl_iterate_phdr.h new file mode 100644 index 0000000000000..9ef12839b4303 --- /dev/null +++ b/libc/src/link/dl_iterate_phdr.h @@ -0,0 +1,21 @@ +//===-- Implementation header for dl_iterate_phdr ---------------*- 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_LINK_DL_ITERATE_PHDR_H +#define LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H + +#include "include/llvm-libc-types/__dl_iterate_phdr_callback_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int dl_iterate_phdr(__dl_iterate_phdr_callback_t callback, void *data); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STRING_MEMCHR_H diff --git a/libc/src/link/linux/CMakeLists.txt b/libc/src/link/linux/CMakeLists.txt new file mode 100644 index 0000000000000..295981b2cb244 --- /dev/null +++ b/libc/src/link/linux/CMakeLists.txt @@ -0,0 +1,11 @@ +add_entrypoint_object( + dl_iterate_phdr + SRCS + dl_iterate_phdr.cpp + HDRS + ../dl_iterate_phdr.h + DEPENDS + libc.include.llvm-libc-types.__dl_iterate_phdr_callback_t + libc.include.llvm-libc-types.struct_dl_phdr_info + libc.include.llvm-libc-types.size_t +) diff --git a/libc/src/link/linux/dl_iterate_phdr.cpp b/libc/src/link/linux/dl_iterate_phdr.cpp new file mode 100644 index 0000000000000..26cf2a8a4a94f --- /dev/null +++ b/libc/src/link/linux/dl_iterate_phdr.cpp @@ -0,0 +1,59 @@ +//===-- Implementation of dl_iterate_phdr ---------------------------------===// +// +// 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/link/dl_iterate_phdr.h" +#include "config/linux/app.h" +#include "include/llvm-libc-macros/sys-auxv-macros.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +[[gnu::weak, + gnu::visibility("hidden")]] extern const ElfW(Dyn) _DYNAMIC[]; // NOLINT + +#define AUX_CNT 38 + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, dl_iterate_phdr, + (__dl_iterate_phdr_callback_t callback, void *data)) { + // dl_iterate_phdr implementation based on Musl source + // "src/ldso/dl_iterate_phdr.c" + size_t *auxv_ptr = reinterpret_cast(app.auxv_ptr); + size_t aux[AUX_CNT] = {0}; + + for (size_t i = 0; auxv_ptr[i]; i += 2) { + if (auxv_ptr[i] < AUX_CNT) { + aux[auxv_ptr[i]] = auxv_ptr[i + 1]; + } + } + + void *p; + size_t n; + size_t base = 0; + for (p = (void *)aux[AT_PHDR], n = aux[AT_PHNUM]; n; + n--, p = reinterpret_cast((uintptr_t)p + aux[AT_PHENT])) { + ElfW(Phdr) *phdr = (ElfW(Phdr) *)p; + if (phdr->p_type == PT_PHDR) + base = aux[AT_PHDR] - phdr->p_vaddr; + if (phdr->p_type == PT_DYNAMIC && _DYNAMIC) + base = (size_t)_DYNAMIC - phdr->p_vaddr; + } + + struct dl_phdr_info info; + info.dlpi_addr = base; + info.dlpi_name = "/proc/self/exe"; + info.dlpi_phdr = (const ElfW(Phdr) *)aux[AT_PHDR]; + info.dlpi_phnum = (ElfW(Half))aux[AT_PHNUM]; + info.dlpi_adds = 0; + info.dlpi_subs = 0; + info.dlpi_tls_modid = 0; + info.dlpi_tls_data = 0; + return callback(&info, sizeof(struct dl_phdr_info), data); +} + +} // namespace LIBC_NAMESPACE_DECL