git: 42ceab3ea1a9 - main - libc.a: implement _rtld_addr_phdr()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 25 Jun 2023 18:28:06 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=42ceab3ea1a997db93b65404be0ee4b17b5382d7

commit 42ceab3ea1a997db93b65404be0ee4b17b5382d7
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-06-24 10:59:56 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-06-25 18:27:25 +0000

    libc.a: implement _rtld_addr_phdr()
    
    to make __cxa_thread_call_dtors() operational for statically linked
    binaries.
    
    Noted by:       andrew
    Reviewed by:    emaste, dim
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D40748
---
 lib/libc/gen/dlfcn.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index 4478b41cfe98..61984e2fe86c 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <dlfcn.h>
 #include <link.h>
 #include <stddef.h>
+#include <string.h>
 #include "namespace.h"
 #include <pthread.h>
 #include "un-namespace.h"
@@ -248,13 +249,48 @@ _rtld_atfork_post(int *locks __unused)
 {
 }
 
+#ifndef IN_LIBDL
+struct _rtld_addr_phdr_cb_data {
+	const void *addr;
+	struct dl_phdr_info *dli;
+};
+
+static int
+_rtld_addr_phdr_cb(struct dl_phdr_info *dli, size_t sz, void *arg)
+{
+	struct _rtld_addr_phdr_cb_data *rd;
+	const Elf_Phdr *ph;
+	unsigned i;
+
+	rd = arg;
+	for (i = 0; i < dli->dlpi_phnum; i++) {
+		ph = &dli->dlpi_phdr[i];
+		if (ph->p_type == PT_LOAD &&
+		    dli->dlpi_addr + ph->p_vaddr <= (uintptr_t)rd->addr &&
+		    (uintptr_t)rd->addr < dli->dlpi_addr + ph->p_vaddr +
+		    ph->p_memsz) {
+			memcpy(rd->dli, dli, sz);
+			return (1);
+		}
+	}
+	return (0);
+}
+#endif
+
 #pragma weak _rtld_addr_phdr
 int
 _rtld_addr_phdr(const void *addr __unused,
     struct dl_phdr_info *phdr_info_a __unused)
 {
+#ifndef IN_LIBDL
+	struct _rtld_addr_phdr_cb_data rd;
 
+	rd.addr = addr;
+	rd.dli = phdr_info_a;
+	return (dl_iterate_phdr(_rtld_addr_phdr_cb, &rd));
+#else
 	return (0);
+#endif
 }
 
 #pragma weak _rtld_get_stack_prot