summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoakim Tjernlund <joakim.tjernlund@transmode.se>2005-03-10 16:29:22 +0000
committerJoakim Tjernlund <joakim.tjernlund@transmode.se>2005-03-10 16:29:22 +0000
commitf5794e1a317089f9316dc30f83fce12dccea0342 (patch)
tree8bd00f15e80cccba0eef8937a7d31fa559ffae5b
parent7d6643102b320429402eafe8b47badd4e0651a90 (diff)
Use DT_RELCONT_IDX to optimize the relocation of R_PPC_RELATIVE
relocs. All RELA arches can probably copy this. REL archs will have to delete the "+ rpnt->r_addend" from the loop.
-rw-r--r--ldso/ldso/powerpc/elfinterp.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c
index 8175a0178..d3dd269fe 100644
--- a/ldso/ldso/powerpc/elfinterp.c
+++ b/ldso/ldso/powerpc/elfinterp.c
@@ -421,7 +421,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
{
- unsigned int i;
+ unsigned int i, relative_count;
char *strtab;
Elf32_Sym *symtab;
ELF_RELOC *rpnt;
@@ -433,6 +433,18 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
+ if (relative_count) { /* Optimize the R_PPC_RELATIVE relocations if possible */
+ Elf32_Addr loadaddr = tpnt->loadaddr;
+ rel_size -= relative_count;
+ --rpnt;
+ do { /* PowerPC handles pre increment/decrement better */
+ Elf32_Addr *const reloc_addr = (void *) (loadaddr + (++rpnt)->r_offset);
+
+ *reloc_addr = loadaddr + rpnt->r_addend;
+ } while (--relative_count);
+ }
for (i = 0; i < rel_size; i++, rpnt++) {
int res;