Add support for a new magic symbol _gp_disp on mips to handle PIC
binaries.
This commit is contained in:
parent
6f4a19f59f
commit
c36c73f681
3 changed files with 26 additions and 10 deletions
|
@ -1,3 +1,8 @@
|
|||
2013-11-22 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Add support for a new magic symbol _gp_disp on mips to handle PIC
|
||||
binaries.
|
||||
|
||||
2013-11-22 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Use $t9 for indirect calls from asm to C as PIC ABI requires.
|
||||
|
|
|
@ -23,7 +23,7 @@ BEGIN {
|
|||
} else if ($1 == "undefined") {
|
||||
if ($3 in symtab)
|
||||
modtab[$2] = modtab[$2] " " symtab[$3];
|
||||
else if ($3 != "__gnu_local_gp") {
|
||||
else if (and ($3 != "__gnu_local_gp", $3 != "_gp_disp")) {
|
||||
printf "%s in %s is not defined\n", $3, $2 >"/dev/stderr";
|
||||
error++;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
/* Dummy __gnu_local_gp. Resolved by linker. */
|
||||
static char __gnu_local_gp_dummy;
|
||||
static char _gp_disp_dummy;
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
grub_err_t
|
||||
|
@ -164,6 +165,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
{
|
||||
grub_uint8_t *addr;
|
||||
Elf_Sym *sym;
|
||||
grub_uint32_t sym_value;
|
||||
|
||||
if (seg->size < rel->r_offset)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
|
@ -172,9 +174,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset);
|
||||
sym = (Elf_Sym *) ((char *) mod->symtab
|
||||
+ entsize * ELF_R_SYM (rel->r_info));
|
||||
if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy)
|
||||
sym->st_value = (grub_addr_t) gp;
|
||||
|
||||
sym_value = sym->st_value;
|
||||
if (sym_value == (grub_addr_t) &__gnu_local_gp_dummy)
|
||||
sym_value = (grub_addr_t) gp;
|
||||
else if (sym_value == (grub_addr_t) &_gp_disp_dummy)
|
||||
{
|
||||
sym_value = (grub_addr_t) gp - (grub_addr_t) addr;
|
||||
if (ELF_R_TYPE (rel->r_info) == R_MIPS_LO16)
|
||||
/* ABI mandates +4 even if partner lui doesn't
|
||||
immediately precede addiu. */
|
||||
sym_value += 4;
|
||||
}
|
||||
switch (ELF_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_MIPS_HI16:
|
||||
|
@ -190,7 +200,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
treated as signed. Hence add 0x8000 to compensate.
|
||||
*/
|
||||
value = (*(grub_uint16_t *) addr << 16)
|
||||
+ sym->st_value + 0x8000;
|
||||
+ sym_value + 0x8000;
|
||||
for (rel2 = rel + 1; rel2 < max; rel2++)
|
||||
if (ELF_R_SYM (rel2->r_info)
|
||||
== ELF_R_SYM (rel->r_info)
|
||||
|
@ -211,13 +221,13 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
addr += 2;
|
||||
#endif
|
||||
*(grub_uint16_t *) addr += (sym->st_value) & 0xffff;
|
||||
*(grub_uint16_t *) addr += sym_value & 0xffff;
|
||||
break;
|
||||
case R_MIPS_32:
|
||||
*(grub_uint32_t *) addr += sym->st_value;
|
||||
*(grub_uint32_t *) addr += sym_value;
|
||||
break;
|
||||
case R_MIPS_GPREL32:
|
||||
*(grub_uint32_t *) addr = sym->st_value
|
||||
*(grub_uint32_t *) addr = sym_value
|
||||
+ *(grub_uint32_t *) addr + gp0 - (grub_uint32_t)gp;
|
||||
break;
|
||||
|
||||
|
@ -227,7 +237,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
grub_uint32_t raw;
|
||||
raw = (*(grub_uint32_t *) addr) & 0x3ffffff;
|
||||
value = raw << 2;
|
||||
value += sym->st_value;
|
||||
value += sym_value;
|
||||
raw = (value >> 2) & 0x3ffffff;
|
||||
|
||||
*(grub_uint32_t *) addr =
|
||||
|
@ -240,7 +250,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
addr += 2;
|
||||
#endif
|
||||
*gpptr = sym->st_value + *(grub_uint16_t *) addr;
|
||||
*gpptr = sym_value + *(grub_uint16_t *) addr;
|
||||
*(grub_uint16_t *) addr
|
||||
= sizeof (grub_uint32_t) * (gpptr - gp);
|
||||
gpptr++;
|
||||
|
@ -266,5 +276,6 @@ void
|
|||
grub_arch_dl_init_linker (void)
|
||||
{
|
||||
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0, 0);
|
||||
grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue