tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

dl_iterate_phdr support for static applications



Hi all,
attached is a patch to support dl_iterate_phdr for statically linked
applications. This has two direct use cases at the moment:

(1) TLS support (since ld.elf_so can't do it for -static)
(2) libgcc_s's exception handling

The second part is also important for dynamically linked programs, since
it removes the need for the register calls and the associated locking
mess in libgcc_s.

A small program to print the interesting (and used) fields is also
attached, it could be used in combination with readelf -l and -h to
validate the output. Note that the path field for static binaries is
only set if called with an absolute path or via PATH.

Joerg
Index: src/lib/csu/alpha/crt0.c
===================================================================
--- src/lib/csu/alpha/crt0.c
+++ src/lib/csu/alpha/crt0.c
@@ -66,10 +66,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/arm_elf/crt0.c
===================================================================
--- src/lib/csu/arm_elf/crt0.c
+++ src/lib/csu/arm_elf/crt0.c
@@ -90,10 +90,12 @@
 #ifdef DYNAMIC
        /* ld(1) convention: if DYNAMIC = 0 then statically linked */
        if (&rtld_DYNAMIC)
                 _rtld_setup(cleanup, obj);
 #endif /* DYNAMIC */
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif /* MCRT0 */

Index: src/lib/csu/common/crt0-common.c
===================================================================
--- src/lib/csu/common/crt0-common.c
+++ src/lib/csu/common/crt0-common.c
@@ -48,10 +48,11 @@
 
 extern int main(int, char **, char **);
 
 extern void    _init(void);
 extern void    _fini(void);
+extern void    _libc_init(void);
 
 /*
  * Arrange for _DYNAMIC to be weak and undefined (and therefore to show up
  * as being at address zero, unless something else defines it).  That way,
  * if we happen to be compiling without -static but with without any
@@ -112,10 +113,12 @@
                        _FATAL("Corrupt Obj_Entry pointer in GOT\n");
                if (obj->version != RTLD_VERSION)
                        _FATAL("Dynamic linker version mismatch\n");
                atexit(cleanup);
        }
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&__eprol, (u_long)&__etext);
 #endif

Index: src/lib/csu/common_elf/common.h
===================================================================
--- src/lib/csu/common_elf/common.h
+++ src/lib/csu/common_elf/common.h
@@ -69,10 +69,11 @@
 char   *__progname = "";
 struct ps_strings *__ps_strings = 0;
 
 extern void    _init(void);
 extern void    _fini(void);
+extern void    _libc_init(void);
 
 #ifdef DYNAMIC
 void   _rtld_setup(void (*)(void), const Obj_Entry *obj);
 
 /*

Index: src/lib/csu/hppa/crt0.c
===================================================================
--- src/lib/csu/hppa/crt0.c
+++ src/lib/csu/hppa/crt0.c
@@ -90,10 +90,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/ia64/crt0.c
===================================================================
--- src/lib/csu/ia64/crt0.c
+++ src/lib/csu/ia64/crt0.c
@@ -73,10 +73,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/m68k_elf/crt0.c
===================================================================
--- src/lib/csu/m68k_elf/crt0.c
+++ src/lib/csu/m68k_elf/crt0.c
@@ -76,10 +76,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/powerpc/crt0.c
===================================================================
--- src/lib/csu/powerpc/crt0.c
+++ src/lib/csu/powerpc/crt0.c
@@ -89,10 +89,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/powerpc64/crt0.c
===================================================================
--- src/lib/csu/powerpc64/crt0.c
+++ src/lib/csu/powerpc64/crt0.c
@@ -75,10 +75,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/sh3_elf/crt0.c
===================================================================
--- src/lib/csu/sh3_elf/crt0.c
+++ src/lib/csu/sh3_elf/crt0.c
@@ -70,10 +70,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/sparc64/crt0.c
===================================================================
--- src/lib/csu/sparc64/crt0.c
+++ src/lib/csu/sparc64/crt0.c
@@ -95,10 +95,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/sparc_elf/crt0.c
===================================================================
--- src/lib/csu/sparc_elf/crt0.c
+++ src/lib/csu/sparc_elf/crt0.c
@@ -80,10 +80,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/csu/vax_elf/crt0.c
===================================================================
--- src/lib/csu/vax_elf/crt0.c
+++ src/lib/csu/vax_elf/crt0.c
@@ -77,10 +77,12 @@
 
 #ifdef DYNAMIC
        if (&rtld_DYNAMIC != NULL)
                _rtld_setup(cleanup, obj);
 #endif
+
+       _libc_init();
 
 #ifdef MCRT0
        atexit(_mcleanup);
        monstartup((u_long)&_eprol, (u_long)&_etext);
 #endif

Index: src/lib/libc/dlfcn/dlfcn_elf.c
===================================================================
--- src/lib/libc/dlfcn/dlfcn_elf.c
+++ src/lib/libc/dlfcn/dlfcn_elf.c
@@ -28,11 +28,15 @@
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
 __RCSID("$NetBSD: dlfcn_elf.c,v 1.7 2010/10/16 10:27:07 skrll Exp $");
 #endif /* LIBC_SCCS and not lint */
 
+#include "reentrant.h"
 #include "namespace.h"
+#include <elf.h>
+#include <errno.h>
+#include <string.h>
 
 #undef dlopen
 #undef dlclose
 #undef dlsym
 #undef dlerror
@@ -126,13 +130,63 @@
 {
 
        return -1;
 }
 
+static once_t dl_iterate_phdr_once = ONCE_INITIALIZER;
+static const char *dlpi_name;
+static Elf_Addr dlpi_addr;
+static const Elf_Phdr *dlpi_phdr;
+static Elf_Half dlpi_phnum;
+
+/*
+ * Declare as common symbol to allow new libc with older binaries to
+ * not trigger an undefined reference.
+ */
+extern __dso_hidden void *__auxinfo;
+
+static void
+dl_iterate_phdr_setup(void)
+{
+       const AuxInfo *aux;
+
+       if (__auxinfo == NULL)
+               return;
+
+       for (aux = __auxinfo; aux->a_type != AT_NULL; ++aux) {
+               switch (aux->a_type) {
+               case AT_BASE:
+                       dlpi_addr = aux->a_v;
+                       break;
+               case AT_PHDR:
+                       dlpi_phdr = (void *)aux->a_v;
+                       break;
+               case AT_PHNUM:
+                       dlpi_phnum = aux->a_v;
+                       break;
+               case AT_SUN_EXECNAME:
+                       dlpi_name = (void *)aux->a_v;
+                       break;
+               }
+       }
+}
+
 /*ARGSUSED*/
 int
 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
     void *data)
 {
+       struct dl_phdr_info phdr_info;
+
+       if (__auxinfo == NULL)
+               return EOPNOTSUPP;
+
+       thr_once(&dl_iterate_phdr_once, dl_iterate_phdr_setup);
+
+       memset(&phdr_info, 0, sizeof(phdr_info));
+       phdr_info.dlpi_addr = dlpi_addr;
+       phdr_info.dlpi_phdr = dlpi_phdr;
+       phdr_info.dlpi_phnum = dlpi_phnum;
+       phdr_info.dlpi_name = dlpi_name;
 
-       return 0;
+       return callback(&phdr_info, sizeof(phdr_info), data);
 }

Index: src/lib/libc/misc/initfini.c
===================================================================
--- src/lib/libc/misc/initfini.c
+++ src/lib/libc/misc/initfini.c
@@ -34,22 +34,45 @@
 
 #ifdef _LIBC
 #include "namespace.h"
 #endif
 
-void   __libc_init(void) __attribute__((__constructor__, __used__));
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <stdbool.h>
+
+void   _libc_init(void) __attribute__((__constructor__, __used__));
 
 void   __guard_setup(void);
 void   __libc_thr_init(void);
 void   __libc_atomic_init(void);
 void   __libc_atexit_init(void);
 void   __libc_env_init(void);
 
-/* LINTED used */
+static bool libc_initialised;
+
+void _libc_init(void);
+
+__dso_hidden void      *__auxinfo;
+struct ps_strings *__ps_strings;
+
+/*
+ * _libc_init is called twice.  The first time explicitly by crt0.o
+ * (for newer versions) and the second time as indirectly via _init().
+ */
 void
-__libc_init(void)
+_libc_init(void)
 {
+
+       if (libc_initialised)
+               return;
+
+       libc_initialised = 1;
+
+       if (__ps_strings != NULL)
+               __auxinfo = __ps_strings->ps_argvstr +
+                   __ps_strings->ps_nargvstr + __ps_strings->ps_nenvstr + 2;
 
        /* For -fstack-protector */
        __guard_setup();
 
        /* Atomic operations */

Index: src/lib/libc/stdlib/exit.c
===================================================================
--- src/lib/libc/stdlib/exit.c
+++ src/lib/libc/stdlib/exit.c
@@ -41,17 +41,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 #ifdef _LIBC
 #include "reentrant.h"
 #include "atexit.h"
-#endif
-
-#ifdef _LIBC
-extern void __libc_init(void);
-#ifndef __lint
-static void (*force_ref)(void) __used = __libc_init;
-#endif
 #endif
 
 void (*__cleanup) __P((void));
 
 /*

Index: src/sys/compat/netbsd32/netbsd32_exec_elf32.c
===================================================================
--- src/sys/compat/netbsd32/netbsd32_exec_elf32.c
+++ src/sys/compat/netbsd32/netbsd32_exec_elf32.c
@@ -113,11 +113,11 @@
 {
        if (itp && epp->ep_interp == NULL) {
                extern const char machine32[];
                (void)compat_elf_check_interp(epp, itp, machine32);
        }
-       epp->ep_flags |= EXEC_32;
+       epp->ep_flags |= EXEC_32 | EXEC_FORCEAUX;
        epp->ep_vm_minaddr = VM_MIN_ADDRESS;
        epp->ep_vm_maxaddr = USRSTACK32;
 #ifdef ELF_INTERP_NON_RELOCATABLE
        *pos = ELF_LINK_ADDR;
 #endif

Index: src/sys/kern/exec_elf.c
===================================================================
--- src/sys/kern/exec_elf.c
+++ src/sys/kern/exec_elf.c
@@ -934,7 +934,8 @@
        if ((error = ELF_MD_PROBE_FUNC(l, epp, eh, itp, pos)) != 0)
                return error;
 #elif defined(ELF_INTERP_NON_RELOCATABLE)
        *pos = ELF_LINK_ADDR;
 #endif
+       epp->ep_flags |= EXEC_FORCEAUX;
        return 0;
 }

#include <elf.h>
#include <link.h>
#include <stdio.h>

static int
dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t len, void *cookie)
{
        const Elf64_Phdr *phdr = info->dlpi_phdr;
        const Elf64_Phdr *phlimit = phdr + info->dlpi_phnum;
        static int first = 1;

        if (!first)
                puts("");
        first = 0;

        printf("Base: %p\nPath: %s\nHeader address: %p\n"
            "Number of header entries: %u\n",
            (void *)info->dlpi_addr, info->dlpi_name, info->dlpi_phdr,
            (unsigned)info->dlpi_phnum);

        for (; phdr < phlimit; ++phdr)
                printf("%u %p\n", phdr->p_type, (void *)phdr->p_vaddr);

        return 0;
}

int
main(void)
{
        dl_iterate_phdr(dl_iterate_phdr_cb, NULL);
        return 0;
}


Home | Main Index | Thread Index | Old Index