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/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 ++++++++++++++++++++++------- 6 files changed, 45 insertions(+), 31 deletions(-) (limited to 'ldso/ldso/sh') 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