From b58a631942341b6ccb62ab400e862f404e22dbbf Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Tue, 1 Oct 2002 05:30:25 +0000 Subject: This commit contains a patch from Stefan Allius to change how uClibc handles _init and _fini, allowing shared lib constructors and destructors to initialize things in the correct sequence. Stefan ported the SH architecture. I then ported x86, arm, and mips. x86 and arm are working fine, but I don't think I quite got things correct for mips. --- ldso/ldso/arm/elfinterp.c | 3 +-- ldso/ldso/dl-elf.c | 33 +++++++++++++++++---------------- ldso/ldso/i386/elfinterp.c | 3 +-- ldso/ldso/ldso.c | 38 ++++++++++++++++++++++++++++++-------- ldso/ldso/readelflib1.c | 33 +++++++++++++++++---------------- ldso/ldso/sh/boot1_arch.h | 11 +++++------ ldso/ldso/sh/dl-startup.h | 11 +++++------ ldso/ldso/sh/dl-sysdep.h | 7 ++++--- ldso/ldso/sh/elfinterp.c | 11 +++++------ ldso/ldso/sh/ld_sysdep.h | 7 ++++--- ldso/ldso/sh/resolve.S | 29 ++++++++++++++++++++++------- 11 files changed, 111 insertions(+), 75 deletions(-) (limited to 'ldso') diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index 4f7e6bd3f..84b94550b 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/ldso/ldso/arm/elfinterp.c @@ -236,8 +236,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } else if (res >0) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_dprintf(2, "can't resolve symbol\n"); goof += res; } } diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 4259a4292..199726ff3 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -318,16 +318,13 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, Elf32_Dyn *dpnt; struct elf_resolve *tpnt; elf_phdr *ppnt; - int piclib; char *status; - int flags; char header[4096]; unsigned long dynamic_info[24]; unsigned long *lpnt; unsigned long libaddr; unsigned long minvma = 0xffffffff, maxvma = 0; - int i; - int infile; + int i, flags, piclib, infile; /* If this file is already loaded, skip this step */ tpnt = _dl_check_hashed_files(libname); @@ -544,28 +541,32 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, #if defined(__mips__) { - int i = 1; + int indx = 1; Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr; while(dpnt->d_tag) { dpnt++; - i++; + indx++; } - dynamic_size = i; + dynamic_size = indx; } #endif - for (i = 0; i < dynamic_size; i++) { - if (dpnt->d_tag > DT_JMPREL) { + unsigned long indx; + + for (indx = 0; indx < dynamic_size; indx++) + { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + dynamic_info[DT_TEXTREL] = 1; dpnt++; - continue; - } - dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) - dynamic_info[DT_TEXTREL] = 1; - dpnt++; - }; + }; + } /* If the TEXTREL is set, this means that we need to make the pages writable before we perform relocations. Do this now. They get set diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index 2caaa2413..2d08bf406 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/ldso/ldso/i386/elfinterp.c @@ -230,8 +230,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } else if (res >0) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_dprintf(2, "can't resolve symbol\n"); goof += res; } } diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index ff13675aa..b81c84092 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -303,12 +303,12 @@ LD_BOOT(unsigned long args) __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got)); #elif defined(__sh__) __asm__( -" mov.l 1f, %0" -" mova 1f, r0" -" bra 2f" -" add r0, %0" -" .balign 4" -"1: .long _GLOBAL_OFFSET_TABLE_" +" mov.l 1f, %0\n" +" mova 1f, r0\n" +" bra 2f\n" +" add r0, %0\n" +" .balign 4\n" +"1: .long _GLOBAL_OFFSET_TABLE_\n" "2:" : "=r" (got) : : "r0"); #elif defined(__cris__) __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got)); @@ -629,6 +629,13 @@ LD_BOOT(unsigned long args) START(); } +#if defined (SUPPORT_LD_DEBUG) +static void debug_fini (int status, void *arg) +{ + (void)status; + _dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg); +} +#endif static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt, unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1], @@ -642,7 +649,9 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a struct elf_resolve *tpnt1; unsigned long brk_addr, *lpnt; int (*_dl_atexit) (void *); - +#if defined (SUPPORT_LD_DEBUG) + int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*); +#endif /* Now we have done the mandatory linking of some things. We are now free to start using global variables, since these things have all been @@ -1196,6 +1205,10 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } #endif _dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, NULL, symbolrel); +#if defined (SUPPORT_LD_DEBUG) + _dl_on_exit = (int (*)(void (*)(int, void *),void*)) + (intptr_t) _dl_find_hash("on_exit", NULL, NULL, symbolrel); +#endif /* * OK, fix one more thing - set up the debug_addr structure to point @@ -1246,6 +1259,12 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) { (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug && _dl_on_exit) + { + (*_dl_on_exit)(debug_fini, tpnt->libname); + } +#endif } #ifdef LD_DEBUG else { @@ -1318,7 +1337,10 @@ int _dl_fixup(struct elf_resolve *tpnt) tpnt->dynamic_info[DT_PLTRELSZ], 0); } #if defined (SUPPORT_LD_DEBUG) - if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s; finished\n\n", tpnt->libname); + if(_dl_debug) { + _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname); + _dl_dprintf(_dl_debug_file,"; finished\n\n"); + } #endif return goof; } diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c index 4259a4292..199726ff3 100644 --- a/ldso/ldso/readelflib1.c +++ b/ldso/ldso/readelflib1.c @@ -318,16 +318,13 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, Elf32_Dyn *dpnt; struct elf_resolve *tpnt; elf_phdr *ppnt; - int piclib; char *status; - int flags; char header[4096]; unsigned long dynamic_info[24]; unsigned long *lpnt; unsigned long libaddr; unsigned long minvma = 0xffffffff, maxvma = 0; - int i; - int infile; + int i, flags, piclib, infile; /* If this file is already loaded, skip this step */ tpnt = _dl_check_hashed_files(libname); @@ -544,28 +541,32 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, #if defined(__mips__) { - int i = 1; + int indx = 1; Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr; while(dpnt->d_tag) { dpnt++; - i++; + indx++; } - dynamic_size = i; + dynamic_size = indx; } #endif - for (i = 0; i < dynamic_size; i++) { - if (dpnt->d_tag > DT_JMPREL) { + unsigned long indx; + + for (indx = 0; indx < dynamic_size; indx++) + { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + dynamic_info[DT_TEXTREL] = 1; dpnt++; - continue; - } - dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) - dynamic_info[DT_TEXTREL] = 1; - dpnt++; - }; + }; + } /* If the TEXTREL is set, this means that we need to make the pages writable before we perform relocations. Do this now. They get set diff --git a/ldso/ldso/sh/boot1_arch.h b/ldso/ldso/sh/boot1_arch.h index 798121dc0..40d6a0dd4 100644 --- a/ldso/ldso/sh/boot1_arch.h +++ b/ldso/ldso/sh/boot1_arch.h @@ -7,15 +7,14 @@ asm("\ .globl _dl_boot _dl_boot: mov r15, r4 - mov.l .L_dl_boot2, r1 - mova .L_dl_boot2, r0 - add r1, r0 - jsr @r0 - add #4, r4 + mov.l .L_dl_boot2, r0 + bsrf r0 + add #4, r4 +.jmp_loc: jmp @r0 mov #0, r4 /* call _start with arg == 0 */ .L_dl_boot2:\n\ - .long _dl_boot2-.\n\ + .long _dl_boot2-.jmp_loc\n\ .previous\n\ "); diff --git a/ldso/ldso/sh/dl-startup.h b/ldso/ldso/sh/dl-startup.h index 798121dc0..40d6a0dd4 100644 --- a/ldso/ldso/sh/dl-startup.h +++ b/ldso/ldso/sh/dl-startup.h @@ -7,15 +7,14 @@ asm("\ .globl _dl_boot _dl_boot: mov r15, r4 - mov.l .L_dl_boot2, r1 - mova .L_dl_boot2, r0 - add r1, r0 - jsr @r0 - add #4, r4 + mov.l .L_dl_boot2, r0 + bsrf r0 + add #4, r4 +.jmp_loc: jmp @r0 mov #0, r4 /* call _start with arg == 0 */ .L_dl_boot2:\n\ - .long _dl_boot2-.\n\ + .long _dl_boot2-.jmp_loc\n\ .previous\n\ "); diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h index a0ff05fdb..cf8820e4e 100644 --- a/ldso/ldso/sh/dl-sysdep.h +++ b/ldso/ldso/sh/dl-sysdep.h @@ -34,13 +34,14 @@ #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ switch(ELF32_R_TYPE((RELP)->r_info)){ \ case R_SH_REL32: \ - *(REL) += (RELP)->r_addend - (LOAD); \ + *(REL) = (SYMBOL) + (RELP)->r_addend \ + - (unsigned long)(REL); \ break; \ case R_SH_DIR32: \ - *(REL) += (SYMBOL) + (RELP)->r_addend; \ + *(REL) = (SYMBOL) + (RELP)->r_addend; \ break; \ case R_SH_RELATIVE: \ - *(REL) += (LOAD); \ + *(REL) = (LOAD) + (RELP)->r_addend; \ break; \ case R_SH_NONE: \ break; \ diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c index 3e0bb87be..d94389ef7 100644 --- a/ldso/ldso/sh/elfinterp.c +++ b/ldso/ldso/sh/elfinterp.c @@ -236,8 +236,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } else if (res >0) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_dprintf(2, "can't resolve symbol\n"); goof += res; } } @@ -289,17 +288,17 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, /* handled later on */ break; case R_SH_DIR32: - *reloc_addr += symbol_addr + rpnt->r_addend; + *reloc_addr = symbol_addr + rpnt->r_addend; break; case R_SH_JMP_SLOT: *reloc_addr = symbol_addr + rpnt->r_addend; break; case R_SH_REL32: - *reloc_addr += rpnt->r_addend - - (unsigned long) tpnt->loadaddr; + *reloc_addr = symbol_addr + rpnt->r_addend - + (unsigned long) reloc_addr; break; case R_SH_RELATIVE: - *reloc_addr += (unsigned long) tpnt->loadaddr; + *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend; break; default: return -1; /*call _dl_exit(1) */ diff --git a/ldso/ldso/sh/ld_sysdep.h b/ldso/ldso/sh/ld_sysdep.h index a0ff05fdb..cf8820e4e 100644 --- a/ldso/ldso/sh/ld_sysdep.h +++ b/ldso/ldso/sh/ld_sysdep.h @@ -34,13 +34,14 @@ #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ switch(ELF32_R_TYPE((RELP)->r_info)){ \ case R_SH_REL32: \ - *(REL) += (RELP)->r_addend - (LOAD); \ + *(REL) = (SYMBOL) + (RELP)->r_addend \ + - (unsigned long)(REL); \ break; \ case R_SH_DIR32: \ - *(REL) += (SYMBOL) + (RELP)->r_addend; \ + *(REL) = (SYMBOL) + (RELP)->r_addend; \ break; \ case R_SH_RELATIVE: \ - *(REL) += (LOAD); \ + *(REL) = (LOAD) + (RELP)->r_addend; \ break; \ case R_SH_NONE: \ break; \ diff --git a/ldso/ldso/sh/resolve.S b/ldso/ldso/sh/resolve.S index 4d8eee6c2..7fef6d77f 100644 --- a/ldso/ldso/sh/resolve.S +++ b/ldso/ldso/sh/resolve.S @@ -3,6 +3,7 @@ */ .text + .globl _dl_linux_resolver .globl _dl_linux_resolve .type _dl_linux_resolve, @function .balign 16 @@ -31,13 +32,27 @@ _dl_linux_resolve: fmov.s fr4, @-r15 #endif sts.l pr, @-r15 +/* Note - The PLT entries have been "optimised" not to use r2. r2 is used by + GCC to return the address of large structures, so it should not be + corrupted here. This does mean however, that those PLTs does not conform + to the SH PIC ABI. That spec says that r0 contains the type of the PLT + and r2 contains the GOT id. The GNU Plt version stores the GOT id in r0 and + ignores the type. We can easily detect this difference however, + since the type will always be 0 or 8, and the GOT ids will always be + greater than or equal to 12. - mov r2, r4 ! link map address - - mov.l 3f, r0 - jsr @r0 ! Call resolver - mov r1, r5 ! Reloc offset - + Found in binutils/bfd/elf32-sh.c by Stefan Allius + */ + mov #8 ,r5 + cmp/gt r5, r0 + bt 1f + mov r2, r0 ! link map address in r2 (SH PIC ABI) +1: + mov r0, r4 ! link map address in r0 (GNUs PLT) + mov.l 3f, r5 + bsrf r5 + mov r1, r5 ! Reloc offset +.jmp_loc: lds.l @r15+, pr ! Get register content back #ifdef HAVE_FPU @@ -64,6 +79,6 @@ _dl_linux_resolve: .balign 4 3: - .long _dl_linux_resolver + .long _dl_linux_resolver - .jmp_loc .size _dl_linux_resolve, . - _dl_linux_resolve -- cgit v1.2.3