From d4cce2160341f99fcf56cb691c56b2475250c044 Mon Sep 17 00:00:00 2001 From: John Marino Date: Sun, 5 Feb 2012 17:21:27 +0100 Subject: [PATCH] Support exception handling on statically-linked binaries The real-time dynamic linker handles exceptions on dynamically-linked binaries through the dl_iterate_phdr function. The RTLD isn't invoked on statically-built executables so thrown exceptions weren't getting handled. There was a dummy dl_iterate_phdr function in libc with a weak symbol that gets looked at when the rtld version isn't present. This function was populated and gets called when the statically-linked executable throws an exception. It requires the GNU_EH_FRAME program header to be present. The base gcc 4.4 spec file was modified to emit this header for statically-built binaries in addition to the dynamically lined ones. --- contrib/gcc-4.4/gcc/config/dragonfly.h | 3 +- lib/libc/gen/dlfcn.c | 60 +++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/contrib/gcc-4.4/gcc/config/dragonfly.h b/contrib/gcc-4.4/gcc/config/dragonfly.h index 891acd0554..d169bb8e50 100644 --- a/contrib/gcc-4.4/gcc/config/dragonfly.h +++ b/contrib/gcc-4.4/gcc/config/dragonfly.h @@ -125,8 +125,7 @@ along with GCC; see the file COPYING3. If not see "/usr/libexec/ld-elf.so.2" #if defined(HAVE_LD_EH_FRAME_HDR) -#define LINK_EH_SPEC \ - "%{!static:--eh-frame-hdr}" +#define LINK_EH_SPEC "--eh-frame-hdr" #endif /* Use --as-needed -lgcc_s for eh support. */ diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c index 29f98d71ca..07237fdd3a 100644 --- a/lib/libc/gen/dlfcn.c +++ b/lib/libc/gen/dlfcn.c @@ -30,6 +30,7 @@ #include #include +extern char **environ; void _rtld_error(const char *, ...); static char sorry[] = "Service unavailable"; @@ -114,13 +115,68 @@ dlinfo(void *handle __unused, int request __unused, void *p __unused) return 0; } +__dso_hidden struct dl_phdr_info +build_phdr_info(void) +{ + struct dl_phdr_info phdr_info; + Elf_Addr *sp; + Elf_Auxinfo *aux, *auxp; + size_t phent; + unsigned int i; + + sp = (Elf_Addr *) environ; + while (*sp++ != 0) + ; + aux = (Elf_Auxinfo *) sp; + phent = 0; + memset (&phdr_info, 0, sizeof(phdr_info)); + for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { + switch (auxp->a_type) { + case AT_BASE: + phdr_info.dlpi_addr = (Elf_Addr) auxp->a_un.a_ptr; + break; + + case AT_EXECPATH: + phdr_info.dlpi_name = (const char *) auxp->a_un.a_ptr; + break; + + case AT_PHDR: + phdr_info.dlpi_phdr = (const Elf_Phdr *) auxp->a_un.a_ptr; + break; + + case AT_PHENT: + phent = auxp->a_un.a_val; + break; + + case AT_PHNUM: + phdr_info.dlpi_phnum = (Elf_Half) auxp->a_un.a_val; + break; + } + } + + for (i = 0; i < phdr_info.dlpi_phnum; i++) + if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) { + phdr_info.dlpi_tls_modid = 1; + phdr_info.dlpi_tls_data = + (void*) phdr_info.dlpi_phdr[i].p_vaddr; + } + + return (phdr_info); +} + #pragma weak dl_iterate_phdr int dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data) { - _rtld_error(sorry); - return 0; + static seen = 0; + static struct dl_phdr_info phdr_info; + if (!seen) { + seen = 1; + phdr_info = build_phdr_info(); + } + + return callback(&phdr_info, sizeof(phdr_info), data); } #pragma weak _rtld_addr_phdr -- 2.41.0