From daf75146de07303ea0c5ad700ec5ef703ec114a1 Mon Sep 17 00:00:00 2001 From: Guy Martin Date: Thu, 21 Nov 2013 13:23:16 -0500 Subject: [PATCH] Don't use broken DL_AUTO_FUNCTION_ADDRESS() On hppa and ia64, the macro DL_AUTO_FUNCTION_ADDRESS() uses the variable fptr[2] in it's own scope. The content of fptr[] is thus undefined right after the macro exits. Newer gcc's (>= 4.7) reuse the stack space of this variable triggering a segmentation fault in dl-init.c:69. To fix this we rewrite the macros to make the call directly to init and fini without needing to pass back a constructed function pointer. --- ChangeLog | 9 +++++ elf/dl-close.c | 5 ++- elf/dl-fini.c | 2 +- elf/dl-init.c | 8 +---- ports/ChangeLog.hppa | 9 +++++ ports/ChangeLog.ia64 | 9 +++++ ports/sysdeps/hppa/dl-lookupcfg.h | 56 +++++++++++++++++-------------- ports/sysdeps/hppa/dl-machine.h | 8 +++-- ports/sysdeps/ia64/dl-lookupcfg.h | 40 ++++++++++++---------- ports/sysdeps/ia64/dl-machine.h | 8 +++-- sysdeps/generic/ldsodefs.h | 5 +-- 11 files changed, 98 insertions(+), 61 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1f673d3226..a6a21a2bcf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2013-11-21 Guy Martin + + * sysdeps/generic/ldsodefs.h: Replace DL_DT_INIT_ADDRESS() and + DL_DT_FINI_ADDRESS() macro with DL_CALL_DT_INIT() and + DL_CALL_DT_FINI() that call the functions directly. + * elf/dl-init.c: Use the new DL_CALL_DT_INIT() macro. + * elf/dl-close.c: Use the new DL_CALL_DT_FINI() macro. + * elf/dl-fini.c: Likewise. + 2013-11-20 Ondřej Bílka * malloc/hooks.c (memalign_check): Add alignment rounding. diff --git a/elf/dl-close.c b/elf/dl-close.c index fe3014cca3..407926bade 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -274,9 +274,8 @@ _dl_close_worker (struct link_map *map) /* Next try the old-style destructor. */ if (imap->l_info[DT_FINI] != NULL) - (*(void (*) (void)) DL_DT_FINI_ADDRESS - (imap, ((void *) imap->l_addr - + imap->l_info[DT_FINI]->d_un.d_ptr))) (); + DL_CALL_DT_FINI (imap, ((void *) imap->l_addr + + imap->l_info[DT_FINI]->d_un.d_ptr)); } #ifdef SHARED diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 6b245f0022..db5269c82f 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -254,7 +254,7 @@ _dl_fini (void) /* Next try the old-style destructor. */ if (l->l_info[DT_FINI] != NULL) - ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + DL_CALL_DT_FINI(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); } #ifdef SHARED diff --git a/elf/dl-init.c b/elf/dl-init.c index a657eb6c40..40783684f2 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -61,13 +61,7 @@ call_init (struct link_map *l, int argc, char **argv, char **env) - the others in the DT_INIT_ARRAY. */ if (l->l_info[DT_INIT] != NULL) - { - init_t init = (init_t) DL_DT_INIT_ADDRESS - (l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr); - - /* Call the function. */ - init (argc, argv, env); - } + DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env); /* Next see whether there is an array with initialization functions. */ ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY]; diff --git a/ports/ChangeLog.hppa b/ports/ChangeLog.hppa index b7c82131d9..82df2cec89 100644 --- a/ports/ChangeLog.hppa +++ b/ports/ChangeLog.hppa @@ -1,3 +1,12 @@ +2013-11-21 Guy Martin + + * sysdeps/hppa/dl-lookupcfg.h: Remove obsolete + DL_DT_INIT_ADDRESS() and DL_DT_FINI_ADDRESS() macro and implement + DL_CALL_DT_INIT() as well as DL_CALL_DT_FINI(). + Define DL_DT_FUNCTION_ADDRESS(). + * sysdeps/hppa/dl-machine.h: Update ELF_MACHINE_START_ADDRESS() + to use DL_DT_FUNCTION_ADDRESS(). + 2013-10-30 Mike Frysinger * sysdeps/hppa/configure.in: Moved to ... diff --git a/ports/ChangeLog.ia64 b/ports/ChangeLog.ia64 index 1eb0f389c2..89133295e1 100644 --- a/ports/ChangeLog.ia64 +++ b/ports/ChangeLog.ia64 @@ -1,3 +1,12 @@ +2013-11-21 Guy Martin + + * sysdeps/ia64/dl-lookupcfg.h: Remove obsolete + DL_DT_INIT_ADDRESS() and DL_DT_FINI_ADDRESS() macro and implement + DL_CALL_DT_INIT() as well as DL_CALL_DT_FINI(). + Define DL_DT_FUNCTION_ADDRESS(). + * sysdeps/ia64/dl-machine.h: Update ELF_MACHINE_START_ADDRESS() + to use DL_DT_FUNCTION_ADDRESS(). + 2013-10-30 Mike Frysinger * sysdeps/ia64/configure.in: Moved to ... diff --git a/ports/sysdeps/hppa/dl-lookupcfg.h b/ports/sysdeps/hppa/dl-lookupcfg.h index f3125e5ec6..feea320789 100644 --- a/ports/sysdeps/hppa/dl-lookupcfg.h +++ b/ports/sysdeps/hppa/dl-lookupcfg.h @@ -38,32 +38,36 @@ void _dl_unmap (struct link_map *map); #define DL_UNMAP(map) _dl_unmap (map) -#define DL_AUTO_FUNCTION_ADDRESS(map, addr) \ -({ \ - unsigned int fptr[2]; \ - fptr[0] = (unsigned int) (addr); \ - fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ - /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */ \ - (ElfW(Addr))((unsigned int)fptr | 2); \ -}) - -#define DL_STATIC_FUNCTION_ADDRESS(map, addr) \ -({ \ - static unsigned int fptr[2]; \ - fptr[0] = (unsigned int) (addr); \ - fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ - /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */ \ - (ElfW(Addr))((unsigned int)fptr | 2); \ -}) - - -/* The test for "addr & 2" below is to accommodate old binaries which - violated the ELF ABI by pointing DT_INIT and DT_FINI at a function - descriptor. */ -#define DL_DT_INIT_ADDRESS(map, addr) \ - ((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr)) -#define DL_DT_FINI_ADDRESS(map, addr) \ - ((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr)) +#define DL_DT_FUNCTION_ADDRESS(map, start, attr, addr) \ + attr volatile unsigned int fptr[2]; \ + /* The test for "start & 2" below is to accommodate old binaries which \ + violated the ELF ABI by pointing DT_INIT and DT_FINI at a function \ + descriptor. */ \ + if ((ElfW(Addr)) (start) & 2) \ + addr = (ElfW(Addr)) start; \ + else \ + { \ + fptr[0] = (unsigned int) (start); \ + fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ + /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */ \ + addr = (ElfW(Addr))((unsigned int)fptr | 2); \ + } \ + +#define DL_CALL_DT_INIT(map, start, argc, argv, env) \ +{ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, , addr) \ + init_t init = (init_t) addr; \ + init (argc, argv, env); \ +} + +#define DL_CALL_DT_FINI(map, start) \ +{ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, , addr) \ + fini_t fini = (fini_t) addr; \ + fini (); \ +} /* The type of the return value of fixup/profile_fixup */ #define DL_FIXUP_VALUE_TYPE struct fdesc diff --git a/ports/sysdeps/hppa/dl-machine.h b/ports/sysdeps/hppa/dl-machine.h index d2411a654a..e47e9473e1 100644 --- a/ports/sysdeps/hppa/dl-machine.h +++ b/ports/sysdeps/hppa/dl-machine.h @@ -490,8 +490,12 @@ asm ( \ #define ELF_MACHINE_NO_REL 1 /* Return the address of the entry point. */ -#define ELF_MACHINE_START_ADDRESS(map, start) \ - DL_STATIC_FUNCTION_ADDRESS (map, start) +#define ELF_MACHINE_START_ADDRESS(map, start) \ +({ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \ + addr; \ +}) /* We define an initialization functions. This is called very early in * _dl_sysdep_start. */ diff --git a/ports/sysdeps/ia64/dl-lookupcfg.h b/ports/sysdeps/ia64/dl-lookupcfg.h index 4da12635c8..cfaa2520b3 100644 --- a/ports/sysdeps/ia64/dl-lookupcfg.h +++ b/ports/sysdeps/ia64/dl-lookupcfg.h @@ -39,24 +39,28 @@ extern void _dl_unmap (struct link_map *map); #define DL_UNMAP(map) _dl_unmap (map) -#define DL_AUTO_FUNCTION_ADDRESS(map, addr) \ -({ \ - unsigned long int fptr[2]; \ - fptr[0] = (unsigned long int) (addr); \ - fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ - (Elf64_Addr) fptr; \ -}) - -#define DL_STATIC_FUNCTION_ADDRESS(map, addr) \ -({ \ - static unsigned long int fptr[2]; \ - fptr[0] = (unsigned long int) (addr); \ - fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ - (Elf64_Addr) fptr; \ -}) - -#define DL_DT_INIT_ADDRESS(map, addr) DL_AUTO_FUNCTION_ADDRESS (map, addr) -#define DL_DT_FINI_ADDRESS(map, addr) DL_AUTO_FUNCTION_ADDRESS (map, addr) +#define DL_DT_FUNCTION_ADDRESS(map, start, attr, addr) \ + attr volatile unsigned long int fptr[2]; \ + fptr[0] = (unsigned long int) (start); \ + fptr[1] = (map)->l_info[DT_PLTGOT]->d_un.d_ptr; \ + addr = (ElfW(Addr)) fptr; \ + +#define DL_CALL_DT_INIT(map, start, argc, argv, env) \ +{ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, , addr) \ + init_t init = (init_t) addr; \ + init (argc, argv, env); \ +} + +#define DL_CALL_DT_FINI(map, start) \ +{ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, , addr) \ + fini_t fini = (fini_t) addr; \ + fini (); \ +} + /* The type of the return value of fixup/profile_fixup. */ #define DL_FIXUP_VALUE_TYPE struct fdesc /* Construct a value of type DL_FIXUP_VALUE_TYPE from a code address diff --git a/ports/sysdeps/ia64/dl-machine.h b/ports/sysdeps/ia64/dl-machine.h index dd469d7a73..61236378fe 100644 --- a/ports/sysdeps/ia64/dl-machine.h +++ b/ports/sysdeps/ia64/dl-machine.h @@ -322,8 +322,12 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) #define ELF_MACHINE_NO_REL 1 /* Return the address of the entry point. */ -#define ELF_MACHINE_START_ADDRESS(map, start) \ - DL_STATIC_FUNCTION_ADDRESS (map, start) +#define ELF_MACHINE_START_ADDRESS(map, start) \ +({ \ + ElfW(Addr) addr; \ + DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \ + addr; \ +}) /* Fixup a PLT entry to bounce directly to the function at VALUE. */ static inline struct fdesc __attribute__ ((always_inline)) diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index e7b0516aaf..146aca4dfb 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -76,8 +76,9 @@ typedef struct link_map *lookup_t; # define DL_SYMBOL_ADDRESS(map, ref) \ (void *) (LOOKUP_VALUE_ADDRESS (map) + ref->st_value) # define DL_LOOKUP_ADDRESS(addr) ((ElfW(Addr)) (addr)) -# define DL_DT_INIT_ADDRESS(map, start) (start) -# define DL_DT_FINI_ADDRESS(map, start) (start) +# define DL_CALL_DT_INIT(map, start, argc, argv, env) \ + ((init_t) (start)) (argc, argv, env) +# define DL_CALL_DT_FINI(map, start) ((fini_t) (start)) () #endif /* On some architectures dladdr can't use st_size of all symbols this way. */ -- 2.43.5