summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2001-11-12 03:06:38 +0000
committerDavid Schleef <ds@schleef.org>2001-11-12 03:06:38 +0000
commit46db40b0da939fb891d2f599e43d68b6ee4a3f8d (patch)
tree253b23838cb6142a83af0b57d1ac75d79e46c686
parentd94663ec0e6009bc9b541e064c5bae1d5b788a98 (diff)
powerpc/elfinterp.c: Powerpc works now. Major rework; most relocs
should work now. R_PPC_JMP_SLOT correctly being lazily relocated. hash.h: Added a field in elf_resolve to store a ppc-specific address. boot1.c: Added debugging code. Disabled check that fails on powerpc because the string literal requires a reloc that isn't performed. Added check to ignore d_tag if it is out of bounds, as has been observed with powerpc binaries.
-rw-r--r--ldso/ldso/boot1.c35
-rw-r--r--ldso/ldso/hash.h6
-rw-r--r--ldso/ldso/ld_hash.h6
-rw-r--r--ldso/ldso/ldso.c35
-rw-r--r--ldso/ldso/powerpc/boot1_arch.h6
-rw-r--r--ldso/ldso/powerpc/dl-startup.h6
-rw-r--r--ldso/ldso/powerpc/dl-sysdep.h24
-rw-r--r--ldso/ldso/powerpc/elfinterp.c255
-rw-r--r--ldso/ldso/powerpc/ld_sysdep.h24
-rw-r--r--ldso/ldso/powerpc/sysdep.h24
10 files changed, 270 insertions, 151 deletions
diff --git a/ldso/ldso/boot1.c b/ldso/ldso/boot1.c
index 43c89adbc..e61276cce 100644
--- a/ldso/ldso/boot1.c
+++ b/ldso/ldso/boot1.c
@@ -149,6 +149,25 @@ char *_dl_get_last_path_component(char *path);
auxv_t[0...N] Auxiliary Vector Table elements (mixed types)
*/
+#ifdef DL_DEBUG
+/* Debugging is especially tricky on PowerPC, since string literals
+ * require relocations. Thus, you can't use _dl_dprintf() for
+ * anything until the bootstrap relocations are finished. */
+static inline void hexprint(unsigned long x)
+{
+ int i;
+ char c;
+ for(i=0;i<8;i++){
+ c=((x>>28)+'0');
+ if(c>'9')c+='a'-'9'-1;
+ _dl_write(1,&c,1);
+ x<<=4;
+ }
+ c='\n';
+ _dl_write(1,&c,1);
+}
+#endif
+
DL_BOOT(unsigned long args)
{
unsigned int argc;
@@ -220,8 +239,11 @@ DL_BOOT(unsigned long args)
/* Check the ELF header to make sure everything looks ok. */
if (! header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
- header->e_ident[EI_VERSION] != EV_CURRENT ||
- _dl_strncmp((void *)header, ELFMAGIC, SELFMAG) != 0)
+ header->e_ident[EI_VERSION] != EV_CURRENT
+#ifndef __powerpc__
+ || _dl_strncmp((void *)header, ELFMAGIC, SELFMAG) != 0
+#endif
+ )
{
SEND_STDERR("Invalid ELF header\n");
_dl_exit(0);
@@ -328,9 +350,12 @@ found_got:
We are only doing ourself right now - we will have to do the rest later */
while (dpnt->d_tag) {
- tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
- if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
- tpnt->dynamic_info[DT_TEXTREL] = 1;
+ if(dpnt->d_tag<24) {
+ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) {
+ tpnt->dynamic_info[DT_TEXTREL] = 1;
+ }
+ }
dpnt++;
}
diff --git a/ldso/ldso/hash.h b/ldso/ldso/hash.h
index 043b64aca..bb1b51fdc 100644
--- a/ldso/ldso/hash.h
+++ b/ldso/ldso/hash.h
@@ -70,6 +70,12 @@ struct elf_resolve{
unsigned long dynamic_size;
unsigned long n_phent;
Elf32_Phdr * ppnt;
+
+#ifdef __powerpc__
+ /* this is used to store the address of relocation data words, so
+ * we don't have to calculate it every time, which requires a divide */
+ unsigned long data_words;
+#endif
};
#if 0
diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h
index 043b64aca..bb1b51fdc 100644
--- a/ldso/ldso/ld_hash.h
+++ b/ldso/ldso/ld_hash.h
@@ -70,6 +70,12 @@ struct elf_resolve{
unsigned long dynamic_size;
unsigned long n_phent;
Elf32_Phdr * ppnt;
+
+#ifdef __powerpc__
+ /* this is used to store the address of relocation data words, so
+ * we don't have to calculate it every time, which requires a divide */
+ unsigned long data_words;
+#endif
};
#if 0
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 43c89adbc..e61276cce 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -149,6 +149,25 @@ char *_dl_get_last_path_component(char *path);
auxv_t[0...N] Auxiliary Vector Table elements (mixed types)
*/
+#ifdef DL_DEBUG
+/* Debugging is especially tricky on PowerPC, since string literals
+ * require relocations. Thus, you can't use _dl_dprintf() for
+ * anything until the bootstrap relocations are finished. */
+static inline void hexprint(unsigned long x)
+{
+ int i;
+ char c;
+ for(i=0;i<8;i++){
+ c=((x>>28)+'0');
+ if(c>'9')c+='a'-'9'-1;
+ _dl_write(1,&c,1);
+ x<<=4;
+ }
+ c='\n';
+ _dl_write(1,&c,1);
+}
+#endif
+
DL_BOOT(unsigned long args)
{
unsigned int argc;
@@ -220,8 +239,11 @@ DL_BOOT(unsigned long args)
/* Check the ELF header to make sure everything looks ok. */
if (! header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
- header->e_ident[EI_VERSION] != EV_CURRENT ||
- _dl_strncmp((void *)header, ELFMAGIC, SELFMAG) != 0)
+ header->e_ident[EI_VERSION] != EV_CURRENT
+#ifndef __powerpc__
+ || _dl_strncmp((void *)header, ELFMAGIC, SELFMAG) != 0
+#endif
+ )
{
SEND_STDERR("Invalid ELF header\n");
_dl_exit(0);
@@ -328,9 +350,12 @@ found_got:
We are only doing ourself right now - we will have to do the rest later */
while (dpnt->d_tag) {
- tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
- if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
- tpnt->dynamic_info[DT_TEXTREL] = 1;
+ if(dpnt->d_tag<24) {
+ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) {
+ tpnt->dynamic_info[DT_TEXTREL] = 1;
+ }
+ }
dpnt++;
}
diff --git a/ldso/ldso/powerpc/boot1_arch.h b/ldso/ldso/powerpc/boot1_arch.h
index 30fd7542a..0e2e1f055 100644
--- a/ldso/ldso/powerpc/boot1_arch.h
+++ b/ldso/ldso/powerpc/boot1_arch.h
@@ -9,12 +9,10 @@ asm("\
.text
.globl _dl_boot
_dl_boot:
- addi 3,1,4
+ mr 3,1
+ addi 1,1,-16
bl _dl_boot2
-
- li 0,0
- lwz 0,42(0)
.previous\n\
");
diff --git a/ldso/ldso/powerpc/dl-startup.h b/ldso/ldso/powerpc/dl-startup.h
index 30fd7542a..0e2e1f055 100644
--- a/ldso/ldso/powerpc/dl-startup.h
+++ b/ldso/ldso/powerpc/dl-startup.h
@@ -9,12 +9,10 @@ asm("\
.text
.globl _dl_boot
_dl_boot:
- addi 3,1,4
+ mr 3,1
+ addi 1,1,-16
bl _dl_boot2
-
- li 0,0
- lwz 0,42(0)
.previous\n\
");
diff --git a/ldso/ldso/powerpc/dl-sysdep.h b/ldso/ldso/powerpc/dl-sysdep.h
index 9e532b486..3f4db4682 100644
--- a/ldso/ldso/powerpc/dl-sysdep.h
+++ b/ldso/ldso/powerpc/dl-sysdep.h
@@ -13,7 +13,7 @@
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
-#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS)
+#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
/*
* Initialization sequence for a GOT.
@@ -93,31 +93,17 @@
PPC_DCBST(REL); PPC_SYNC; PPC_ICBI(REL); \
}
-#if 0
- case R_386_32: \
- *REL += SYMBOL; \
- break; \
- case R_386_PC32: \
- *REL += SYMBOL - (unsigned long) REL; \
- break; \
- case R_386_GLOB_DAT: \
- case R_386_JMP_SLOT: \
- *REL = SYMBOL; \
- break; \
- case R_386_RELATIVE: \
- *REL += (unsigned long) LOAD; \
- break;
-#endif
-
/*
* Transfer control to the user's application, once the dynamic loader
* is done. This routine has to exit the current function, then
* call the _dl_elf_main function.
*/
#define START() \
- __asm__ volatile ("mtlr %0\n\t" \
+ __asm__ volatile ( \
+ "addi 1,%1,0\n\t" \
+ "mtlr %0\n\t" \
"blrl\n\t" \
- : : "r" (_dl_elf_main))
+ : : "r" (_dl_elf_main), "r" (args))
diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c
index 55de296e6..77efcd12e 100644
--- a/ldso/ldso/powerpc/elfinterp.c
+++ b/ldso/ldso/powerpc/elfinterp.c
@@ -1,4 +1,4 @@
-#define DEBUG
+//#define DEBUG
/* Run an ELF binary on a linux system.
Copyright (C) 1993, Eric Youngdale.
@@ -57,39 +57,50 @@ static char *_dl_reltypes[] =
#include "syscall.h"
#include "string.h"
+#ifdef DEBUG
+static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index);
+static void debug_reloc(ELF_RELOC *rpnt);
+#define DPRINTF(fmt,args...) _dl_dprintf(2,fmt,args)
+#else
+#define debug_sym(a,b,c)
+#define debug_reloc(a)
+#define DPRINTF(fmt,args...)
+#endif
+
extern char *_dl_progname;
extern int _dl_linux_resolve(void);
void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
{
- int i;
unsigned long target_addr = (unsigned long)_dl_linux_resolve;
unsigned int n_plt_entries;
unsigned long *tramp;
unsigned long data_words;
unsigned int rel_offset_words;
- unsigned int offset;
- _dl_dprintf(2,"init_got plt=%x, tpnt=%x\n",
+ DPRINTF("init_got plt=%x, tpnt=%x\n",
(unsigned long)plt,(unsigned long)tpnt);
n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
-_dl_dprintf(2,"n_plt_entries %d\n",n_plt_entries);
+ DPRINTF("n_plt_entries %d\n",n_plt_entries);
-rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
-_dl_dprintf(2,"rel_offset_words %x\n",rel_offset_words);
-data_words = (unsigned long)(plt + rel_offset_words);
-_dl_dprintf(2,"data_words %x\n",data_words);
+ rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
+ DPRINTF("rel_offset_words %x\n",rel_offset_words);
+ data_words = (unsigned long)(plt + rel_offset_words);
+ DPRINTF("data_words %x\n",data_words);
+
+ tpnt->data_words = data_words;
- //lpnt += PLT_INITIAL_ENTRY_WORDS;
-
plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
+ /* [4] */
+ /* [5] */
+
tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
tramp[1] = OPCODE_ADDI(11,11,-data_words);
@@ -102,6 +113,10 @@ _dl_dprintf(2,"data_words %x\n",data_words);
tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
tramp[9] = OPCODE_BCTR();
+ /* [16] unused */
+ /* [17] unused */
+
+ /* instructions were modified */
PPC_DCBST(plt);
PPC_DCBST(plt+4);
PPC_DCBST(plt+8);
@@ -120,11 +135,13 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
Elf32_Sym *symtab;
ELF_RELOC *rel_addr;
int symtab_index;
- char *new_addr;
- char **got_addr;
- unsigned long instr_addr;
+ unsigned long insn_addr;
+ unsigned long *insns;
+ unsigned long targ_addr;
+ int delta;
+
+ //DPRINTF("linux_resolver tpnt=%x reloc_entry=%x\n", tpnt, reloc_entry);
-_dl_dprintf(2,"linux_resolver tpnt=%x reloc_entry=%x\n",tpnt,reloc_entry);
rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
this_reloc = (void *)rel_addr + reloc_entry;
@@ -134,6 +151,7 @@ _dl_dprintf(2,"linux_resolver tpnt=%x reloc_entry=%x\n",tpnt,reloc_entry);
symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+ //debug_reloc(this_reloc);
if (reloc_type != R_PPC_JMP_SLOT) {
_dl_dprintf(2, "%s: Incorrect relocation type [%s] in jump relocations\n",
@@ -143,40 +161,59 @@ _dl_dprintf(2,"linux_resolver tpnt=%x reloc_entry=%x\n",tpnt,reloc_entry);
};
/* Address of dump instruction to fix up */
- instr_addr = ((unsigned long) this_reloc->r_offset +
- (unsigned long) tpnt->loadaddr);
- got_addr = (char **) instr_addr;
+ insn_addr = (unsigned long) tpnt->loadaddr +
+ (unsigned long) this_reloc->r_offset;
-#ifdef DEBUG
- _dl_dprintf(2, "Resolving symbol %s %x --> ",
+ DPRINTF("Resolving symbol %s %x --> ",
strtab + symtab[symtab_index].st_name,
- instr_addr);
-#endif
+ insn_addr);
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope, (unsigned long) got_addr, tpnt, 0);
- if (!new_addr) {
+ targ_addr = (unsigned long) _dl_find_hash(
+ strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, insn_addr, tpnt, 0);
+ if (!targ_addr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
_dl_exit(1);
};
-#ifdef DEBUG
- _dl_dprintf(2, "%x\n", new_addr);
-#endif
-
-/* #define DEBUG_LIBRARY */
-#ifdef DEBUG_LIBRARY
- if ((unsigned long) got_addr < 0x40000000) {
- _dl_dprintf(2, "Calling library function: %s\n",
- strtab + symtab[symtab_index].st_name);
- } else {
- *got_addr = new_addr;
+ DPRINTF("%x\n", targ_addr);
+
+ insns = (unsigned long *)insn_addr;
+ delta = targ_addr - insn_addr;
+
+ if(delta<<6>>6 == delta){
+ insns[0] = OPCODE_B(delta);
+ }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
+ insns[0] = OPCODE_BA (targ_addr);
+ }else{
+ /* Warning: we don't handle double-sized PLT entries */
+ int num_plt_entries;
+ unsigned long plt_addr;
+ unsigned long lbranch_addr;
+ unsigned long *ptr;
+ int index;
+
+ plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
+ (unsigned long)tpnt->loadaddr;
+ lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
+ delta = lbranch_addr - insn_addr;
+ index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/2;
+
+ ptr = (unsigned long *)tpnt->data_words;
+ DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n",
+ plt_addr, delta, index, ptr);
+ ptr[index] = targ_addr;
+ PPC_SYNC;
+ insns[1] = OPCODE_B(delta - 4);
}
-#else
- *got_addr = new_addr;
-#endif
- return (unsigned long) new_addr;
+
+ /* instructions were modified */
+ PPC_DCBST(insn_addr);
+ PPC_SYNC;
+ PPC_ICBI(insn_addr);
+
+ return targ_addr;
}
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
@@ -188,25 +225,25 @@ void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
int symtab_index;
Elf32_Sym *symtab;
ELF_RELOC *rpnt;
- unsigned long *reloc_addr;
+ unsigned long reloc_addr;
+ unsigned long *insns;
unsigned long *plt;
int index;
-#ifdef DEBUG
-_dl_dprintf(2,"_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
+ DPRINTF("_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
tpnt,rel_addr,rel_size,type);
-#endif
+
/* Now parse the relocation information */
rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof(ELF_RELOC);
- symtab =
- (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
for (i = 0; i < rel_size; i++, rpnt++) {
- reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
+ reloc_addr = (unsigned long)tpnt->loadaddr +
+ (unsigned long) rpnt->r_offset;
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
@@ -218,12 +255,9 @@ _dl_dprintf(2,"_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_s
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
-#ifdef DEBUG
-_dl_dprintf(2, "L %x %s %s %x %x\n",
- reloc_addr, _dl_reltypes[reloc_type],
- symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
-#endif
-
+ DPRINTF("L %x %s %s %x %x\n",
+ reloc_addr, _dl_reltypes[reloc_type],
+ symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
switch (reloc_type) {
case R_PPC_NONE:
@@ -233,17 +267,16 @@ _dl_dprintf(2, "L %x %s %s %x %x\n",
int delta;
delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
- - (unsigned long)(reloc_addr+1);
+ - (reloc_addr+4);
- index = ((unsigned long)reloc_addr -
+ index = (reloc_addr -
(unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
/sizeof(unsigned long);
index /= 2;
-#ifdef DEBUG
-_dl_dprintf(2, " index %x delta %x\n",index,delta);
-#endif
- reloc_addr[0] = OPCODE_LI(11,index*4);
- reloc_addr[1] = OPCODE_B(delta);
+ DPRINTF(" index %x delta %x\n",index,delta);
+ insns = (unsigned long *)reloc_addr;
+ insns[0] = OPCODE_LI(11,index*4);
+ insns[1] = OPCODE_B(delta);
break;
}
default:
@@ -279,10 +312,9 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt,
unsigned long addend;
unsigned long *plt;
-#ifdef DEBUG
-_dl_dprintf(2,"_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
+ DPRINTF("_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
tpnt,rel_addr,rel_size,type);
-#endif
+
/* Now parse the relocation information */
rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
@@ -293,6 +325,8 @@ _dl_dprintf(2,"_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%
plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
for (i = 0; i < rel_size; i++, rpnt++) {
+ debug_reloc(rpnt);
+
reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
@@ -324,12 +358,8 @@ _dl_dprintf(2,"_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%
goof++;
}
}
-#ifdef DEBUG
-_dl_dprintf(2, " %x %s %s %x %x\n",
- reloc_addr, _dl_reltypes[reloc_type],
- symtab_index?strtab + symtab[symtab_index].st_name:"",
- symbol_addr, addend);
-#endif
+ debug_sym(symtab,strtab,symtab_index);
+
switch (reloc_type) {
case R_PPC_NONE:
break;
@@ -380,15 +410,19 @@ _dl_dprintf(2, " %x %s %s %x %x\n",
(unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
/sizeof(unsigned long);
index /= 2;
-#ifdef DEBUG
-_dl_dprintf(2, " index %x delta %x\n",index,delta);
-#endif
+ DPRINTF(" index %x delta %x\n",index,delta);
reloc_addr[0] = OPCODE_LI(11,index*4);
reloc_addr[1] = OPCODE_B(delta);
}
}
break;
}
+ case R_PPC_GLOB_DAT:
+ *reloc_addr += symbol_addr;
+ break;
+ case R_PPC_COPY:
+ // handled later
+ break;
default:
_dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
@@ -404,7 +438,7 @@ _dl_dprintf(2, " index %x delta %x\n",index,delta);
PPC_SYNC;
PPC_ICBI(reloc_addr);
-//_dl_dprintf(2,"reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
+ DPRINTF("reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
};
return goof;
}
@@ -433,7 +467,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
struct elf_resolve *tpnt;
int symtab_index;
-_dl_dprintf(2,"parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
+ DPRINTF("parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
(int)xpnt,rel_addr,rel_size,type);
/* Now parse the relocation information */
@@ -449,8 +483,11 @@ _dl_dprintf(2,"parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
for (i = 0; i < rel_size; i++, rpnt++) {
reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
- if (reloc_type != R_386_COPY)
+ if (reloc_type != R_PPC_COPY)
continue;
+
+ debug_reloc(rpnt);
+
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if (!symtab_index && tpnt->libtype == program_interpreter)
@@ -470,10 +507,76 @@ _dl_dprintf(2,"parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
goof++;
};
};
+
+ debug_sym(symtab,strtab,symtab_index);
+
+ DPRINTF("copy: to=%x from=%x size=%x\n",
+ symtab[symtab_index].st_value,
+ symbol_addr, symtab[symtab_index].st_size);
+
if (!goof) {
_dl_memcpy((char *) symtab[symtab_index].st_value,
- (char *) symbol_addr, symtab[symtab_index].st_size);
+ (char *) symbol_addr,
+ symtab[symtab_index].st_size);
}
};
return goof;
}
+
+
+#ifdef unused
+static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr)
+{
+ int delta = targ_addr - reloc_addr;
+ int index;
+
+ if(delta<<6>>6 == delta){
+ *reloc_addr = OPCODE_B(delta);
+ }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
+ *reloc_addr = OPCODE_BA (targ_addr);
+ }else{
+ delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
+ - (unsigned long)(reloc_addr+1);
+
+ index = ((unsigned long)reloc_addr -
+ (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
+ /sizeof(unsigned long);
+ index /= 2;
+
+ DPRINTF(" index %x delta %x\n",index,delta);
+
+ reloc_addr[0] = OPCODE_LI(11,index*4);
+ reloc_addr[1] = OPCODE_B(delta);
+ }
+}
+#endif
+
+
+#ifdef DEBUG
+static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
+{
+ if(symtab_index){
+ _dl_dprintf(2, "sym: name=%s value=%x size=%x info=%x other=%x shndx=%x\n",
+ strtab + symtab[symtab_index].st_name,
+ symtab[symtab_index].st_value,
+ symtab[symtab_index].st_size,
+ symtab[symtab_index].st_info,
+ symtab[symtab_index].st_other,
+ symtab[symtab_index].st_shndx);
+ }else{
+ _dl_dprintf(2, "sym: null\n");
+ }
+}
+
+static void debug_reloc(ELF_RELOC *rpnt)
+{
+ _dl_dprintf(2, "reloc: offset=%x type=%x sym=%x addend=%x\n",
+ rpnt->r_offset,
+ ELF32_R_TYPE(rpnt->r_info),
+ ELF32_R_SYM(rpnt->r_info),
+ rpnt->r_addend);
+}
+
+#endif
+
+
diff --git a/ldso/ldso/powerpc/ld_sysdep.h b/ldso/ldso/powerpc/ld_sysdep.h
index 9e532b486..3f4db4682 100644
--- a/ldso/ldso/powerpc/ld_sysdep.h
+++ b/ldso/ldso/powerpc/ld_sysdep.h
@@ -13,7 +13,7 @@
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
-#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS)
+#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
/*
* Initialization sequence for a GOT.
@@ -93,31 +93,17 @@
PPC_DCBST(REL); PPC_SYNC; PPC_ICBI(REL); \
}
-#if 0
- case R_386_32: \
- *REL += SYMBOL; \
- break; \
- case R_386_PC32: \
- *REL += SYMBOL - (unsigned long) REL; \
- break; \
- case R_386_GLOB_DAT: \
- case R_386_JMP_SLOT: \
- *REL = SYMBOL; \
- break; \
- case R_386_RELATIVE: \
- *REL += (unsigned long) LOAD; \
- break;
-#endif
-
/*
* Transfer control to the user's application, once the dynamic loader
* is done. This routine has to exit the current function, then
* call the _dl_elf_main function.
*/
#define START() \
- __asm__ volatile ("mtlr %0\n\t" \
+ __asm__ volatile ( \
+ "addi 1,%1,0\n\t" \
+ "mtlr %0\n\t" \
"blrl\n\t" \
- : : "r" (_dl_elf_main))
+ : : "r" (_dl_elf_main), "r" (args))
diff --git a/ldso/ldso/powerpc/sysdep.h b/ldso/ldso/powerpc/sysdep.h
index 9e532b486..3f4db4682 100644
--- a/ldso/ldso/powerpc/sysdep.h
+++ b/ldso/ldso/powerpc/sysdep.h
@@ -13,7 +13,7 @@
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
-#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS)
+#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
/*
* Initialization sequence for a GOT.
@@ -93,31 +93,17 @@
PPC_DCBST(REL); PPC_SYNC; PPC_ICBI(REL); \
}
-#if 0
- case R_386_32: \
- *REL += SYMBOL; \
- break; \
- case R_386_PC32: \
- *REL += SYMBOL - (unsigned long) REL; \
- break; \
- case R_386_GLOB_DAT: \
- case R_386_JMP_SLOT: \
- *REL = SYMBOL; \
- break; \
- case R_386_RELATIVE: \
- *REL += (unsigned long) LOAD; \
- break;
-#endif
-
/*
* Transfer control to the user's application, once the dynamic loader
* is done. This routine has to exit the current function, then
* call the _dl_elf_main function.
*/
#define START() \
- __asm__ volatile ("mtlr %0\n\t" \
+ __asm__ volatile ( \
+ "addi 1,%1,0\n\t" \
+ "mtlr %0\n\t" \
"blrl\n\t" \
- : : "r" (_dl_elf_main))
+ : : "r" (_dl_elf_main), "r" (args))