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>
|
2013-11-22 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
Use $t9 for indirect calls from asm to C as PIC ABI requires.
|
Use $t9 for indirect calls from asm to C as PIC ABI requires.
|
||||||
|
|
|
@ -23,7 +23,7 @@ BEGIN {
|
||||||
} else if ($1 == "undefined") {
|
} else if ($1 == "undefined") {
|
||||||
if ($3 in symtab)
|
if ($3 in symtab)
|
||||||
modtab[$2] = modtab[$2] " " symtab[$3];
|
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";
|
printf "%s in %s is not defined\n", $3, $2 >"/dev/stderr";
|
||||||
error++;
|
error++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
/* Dummy __gnu_local_gp. Resolved by linker. */
|
/* Dummy __gnu_local_gp. Resolved by linker. */
|
||||||
static char __gnu_local_gp_dummy;
|
static char __gnu_local_gp_dummy;
|
||||||
|
static char _gp_disp_dummy;
|
||||||
|
|
||||||
/* Check if EHDR is a valid ELF header. */
|
/* Check if EHDR is a valid ELF header. */
|
||||||
grub_err_t
|
grub_err_t
|
||||||
|
@ -164,6 +165,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
{
|
{
|
||||||
grub_uint8_t *addr;
|
grub_uint8_t *addr;
|
||||||
Elf_Sym *sym;
|
Elf_Sym *sym;
|
||||||
|
grub_uint32_t sym_value;
|
||||||
|
|
||||||
if (seg->size < rel->r_offset)
|
if (seg->size < rel->r_offset)
|
||||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
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);
|
addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset);
|
||||||
sym = (Elf_Sym *) ((char *) mod->symtab
|
sym = (Elf_Sym *) ((char *) mod->symtab
|
||||||
+ entsize * ELF_R_SYM (rel->r_info));
|
+ entsize * ELF_R_SYM (rel->r_info));
|
||||||
if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy)
|
sym_value = sym->st_value;
|
||||||
sym->st_value = (grub_addr_t) gp;
|
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))
|
switch (ELF_R_TYPE (rel->r_info))
|
||||||
{
|
{
|
||||||
case R_MIPS_HI16:
|
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.
|
treated as signed. Hence add 0x8000 to compensate.
|
||||||
*/
|
*/
|
||||||
value = (*(grub_uint16_t *) addr << 16)
|
value = (*(grub_uint16_t *) addr << 16)
|
||||||
+ sym->st_value + 0x8000;
|
+ sym_value + 0x8000;
|
||||||
for (rel2 = rel + 1; rel2 < max; rel2++)
|
for (rel2 = rel + 1; rel2 < max; rel2++)
|
||||||
if (ELF_R_SYM (rel2->r_info)
|
if (ELF_R_SYM (rel2->r_info)
|
||||||
== ELF_R_SYM (rel->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
|
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||||
addr += 2;
|
addr += 2;
|
||||||
#endif
|
#endif
|
||||||
*(grub_uint16_t *) addr += (sym->st_value) & 0xffff;
|
*(grub_uint16_t *) addr += sym_value & 0xffff;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_32:
|
case R_MIPS_32:
|
||||||
*(grub_uint32_t *) addr += sym->st_value;
|
*(grub_uint32_t *) addr += sym_value;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_GPREL32:
|
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;
|
+ *(grub_uint32_t *) addr + gp0 - (grub_uint32_t)gp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -227,7 +237,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
grub_uint32_t raw;
|
grub_uint32_t raw;
|
||||||
raw = (*(grub_uint32_t *) addr) & 0x3ffffff;
|
raw = (*(grub_uint32_t *) addr) & 0x3ffffff;
|
||||||
value = raw << 2;
|
value = raw << 2;
|
||||||
value += sym->st_value;
|
value += sym_value;
|
||||||
raw = (value >> 2) & 0x3ffffff;
|
raw = (value >> 2) & 0x3ffffff;
|
||||||
|
|
||||||
*(grub_uint32_t *) addr =
|
*(grub_uint32_t *) addr =
|
||||||
|
@ -240,7 +250,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||||
addr += 2;
|
addr += 2;
|
||||||
#endif
|
#endif
|
||||||
*gpptr = sym->st_value + *(grub_uint16_t *) addr;
|
*gpptr = sym_value + *(grub_uint16_t *) addr;
|
||||||
*(grub_uint16_t *) addr
|
*(grub_uint16_t *) addr
|
||||||
= sizeof (grub_uint32_t) * (gpptr - gp);
|
= sizeof (grub_uint32_t) * (gpptr - gp);
|
||||||
gpptr++;
|
gpptr++;
|
||||||
|
@ -266,5 +276,6 @@ void
|
||||||
grub_arch_dl_init_linker (void)
|
grub_arch_dl_init_linker (void)
|
||||||
{
|
{
|
||||||
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0, 0);
|
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