summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-10-01 05:30:25 +0000
committerEric Andersen <andersen@codepoet.org>2002-10-01 05:30:25 +0000
commitb58a631942341b6ccb62ab400e862f404e22dbbf (patch)
tree0c6e622729b6c98417a15c0b7c10279c17ca0038 /ldso
parent351c1d9029844a97d2771da883fc2b432d5e1bd4 (diff)
This commit contains a patch from Stefan Allius <allius@atecom.com> 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.
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/arm/elfinterp.c3
-rw-r--r--ldso/ldso/dl-elf.c33
-rw-r--r--ldso/ldso/i386/elfinterp.c3
-rw-r--r--ldso/ldso/ldso.c38
-rw-r--r--ldso/ldso/readelflib1.c33
-rw-r--r--ldso/ldso/sh/boot1_arch.h11
-rw-r--r--ldso/ldso/sh/dl-startup.h11
-rw-r--r--ldso/ldso/sh/dl-sysdep.h7
-rw-r--r--ldso/ldso/sh/elfinterp.c11
-rw-r--r--ldso/ldso/sh/ld_sysdep.h7
-rw-r--r--ldso/ldso/sh/resolve.S29
11 files changed, 111 insertions, 75 deletions
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 <allius@atecom.com>
+ */
+ 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