diff options
Diffstat (limited to 'sysdeps/mips/dl-machine.h')
-rw-r--r-- | sysdeps/mips/dl-machine.h | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h index 2a19126208..c0ece38719 100644 --- a/sysdeps/mips/dl-machine.h +++ b/sysdeps/mips/dl-machine.h @@ -136,7 +136,11 @@ elf_machine_load_address (void) } /* The MSB of got[1] of a gnu object is set to identify gnu objects. */ -#define ELF_MIPS_GNU_GOT1_MASK 0x80000000 +#define ELF_MIPS_GNU_GOT1_MASK 0x80000000 + +/* GNU Binutils upto 2.10 produce a wrong relocations. Bit 30 of + got[1] marks good objects. */ +#define ELF_MIPS_GNU_GOT1_OK 0x00000001 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope fiddles with global data. */ @@ -149,6 +153,9 @@ do { \ \ got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]); \ \ + if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0) \ + got[1] = (ElfW(Addr)) ELF_MIPS_GNU_GOT1_MASK \ + | (got[1] & ELF_MIPS_GNU_GOT1_OK); \ \ if (__builtin_expect (map->l_addr == 0, 1)) \ goto done; \ @@ -212,8 +219,8 @@ elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc) if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0) { - struct link_map *l = - (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK); + struct link_map *l = (struct link_map *) + (g1 & ~(ELF_MIPS_GNU_GOT1_MASK|ELF_MIPS_GNU_GOT1_OK)); ElfW(Addr) base, limit; const ElfW(Phdr) *p = l->l_phdr; ElfW(Half) this, nent = l->l_phnum; @@ -352,11 +359,12 @@ asm ("\n \ .type _dl_runtime_resolve,@function\n \ .ent _dl_runtime_resolve\n \ _dl_runtime_resolve:\n \ + .frame $29, 40, $31\n \ .set noreorder\n \ - # Save GP.\n \ + # Save GP.\n \ move $3, $28\n \ # Modify t9 ($25) so as to point .cpload instruction.\n \ - addu $25,8\n \ + addu $25, 8\n \ # Compute GP.\n \ .cpload $25\n \ .set reorder\n \ @@ -366,24 +374,20 @@ _dl_runtime_resolve:\n \ subu $29, 40\n \ .cprestore 32\n \ sw $15, 36($29)\n \ - sw $4, 12($29)\n \ - sw $5, 16($29)\n \ - sw $6, 20($29)\n \ - sw $7, 24($29)\n \ - sw $16, 28($29)\n \ - move $16, $29\n \ + sw $4, 16($29)\n \ + sw $5, 20($29)\n \ + sw $6, 24($29)\n \ + sw $7, 28($29)\n \ move $4, $24\n \ move $5, $15\n \ move $6, $3\n \ move $7, $2\n \ jal __dl_runtime_resolve\n \ - move $29, $16\n \ lw $31, 36($29)\n \ - lw $4, 12($29)\n \ - lw $5, 16($29)\n \ - lw $6, 20($29)\n \ - lw $7, 24($29)\n \ - lw $16, 28($29)\n \ + lw $4, 16($29)\n \ + lw $5, 20($29)\n \ + lw $6, 24($29)\n \ + lw $7, 28($29)\n \ addu $29, 40\n \ move $25, $2\n \ jr $25\n \ @@ -580,15 +584,20 @@ elf_machine_got_rel (struct link_map *map, int lazy) got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]); - /* got[0] is reserved. got[1] is also reserved for the dynamic object - generated by gnu ld. Skip these reserved entries from relocation. */ - i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1; n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val; - /* Add the run-time display to all local got entries if needed. */ - if (__builtin_expect (map->l_addr != 0, 0)) + /* The dynamic linker's local got entries have already been relocated. */ + if (map != &_dl_rtld_map) { - while (i < n) - got[i++] += map->l_addr; + /* got[0] is reserved. got[1] is also reserved for the dynamic object + generated by gnu ld. Skip these reserved entries from relocation. */ + i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1; + + /* Add the run-time display to all local got entries if needed. */ + if (__builtin_expect (map->l_addr != 0, 0)) + { + while (i < n) + got[i++] += map->l_addr; + } } /* Handle global got entries. */ @@ -661,7 +670,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) of got[1] of a gnu object is set to identify gnu objects. Where we can store l for non gnu objects? XXX */ if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0) - got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK); + got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK + | (got[1] & ELF_MIPS_GNU_GOT1_OK)); else _dl_mips_gnu_objects = 0; } |