arm: Use proper PLT/GOT for -run.
Same as with x86_64, disable the runtime_plt_and_got hack for -run on arm as well. For that we need to handle several relocations as (potentially) generating PLT slots as well. Tested with mpfr-3.1.2 and gawk (both using --disable-shared), there are two resp. five pre-existing problems, so no regressions. This also works toward enabling real shared libs for arm, but it's not there yet.
This commit is contained in:
parent
9750d0b725
commit
01c0419234
2 changed files with 54 additions and 10 deletions
2
tcc.h
2
tcc.h
|
@ -712,7 +712,7 @@ struct TCCState {
|
||||||
void *write_mem;
|
void *write_mem;
|
||||||
unsigned long mem_size;
|
unsigned long mem_size;
|
||||||
# endif
|
# endif
|
||||||
# if !defined TCC_TARGET_PE && (defined TCC_TARGET_ARM)
|
# if !defined TCC_TARGET_PE && (0)
|
||||||
/* write PLT and GOT here */
|
/* write PLT and GOT here */
|
||||||
char *runtime_plt_and_got;
|
char *runtime_plt_and_got;
|
||||||
unsigned runtime_plt_and_got_offset;
|
unsigned runtime_plt_and_got_offset;
|
||||||
|
|
58
tccelf.c
58
tccelf.c
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
#include "tcc.h"
|
#include "tcc.h"
|
||||||
|
|
||||||
|
/* Define this to get some debug output during relocation processing. */
|
||||||
|
#undef DEBUG_RELOC
|
||||||
|
|
||||||
/* XXX: avoid static variable */
|
/* XXX: avoid static variable */
|
||||||
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
|
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
|
||||||
|
|
||||||
|
@ -438,6 +441,9 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
|
||||||
addr = resolve_sym(s1, name);
|
addr = resolve_sym(s1, name);
|
||||||
if (addr) {
|
if (addr) {
|
||||||
sym->st_value = (addr_t)addr;
|
sym->st_value = (addr_t)addr;
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("relocate_sym: %s -> 0x%x\n", name, sym->st_value);
|
||||||
|
#endif
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -601,6 +607,11 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
{
|
{
|
||||||
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
|
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
|
||||||
x = (*(int *) ptr) & 0xffffff;
|
x = (*(int *) ptr) & 0xffffff;
|
||||||
|
if (sym->st_shndx == SHN_UNDEF)
|
||||||
|
val = s1->plt->sh_addr;
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
|
||||||
|
#endif
|
||||||
(*(int *)ptr) &= 0xff000000;
|
(*(int *)ptr) &= 0xff000000;
|
||||||
if (x & 0x800000)
|
if (x & 0x800000)
|
||||||
x -= 0x1000000;
|
x -= 0x1000000;
|
||||||
|
@ -610,6 +621,10 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
|
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
|
||||||
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
|
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
|
||||||
x += val - addr;
|
x += val - addr;
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf (" newx=0x%x name=%s\n", x,
|
||||||
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
|
#endif
|
||||||
h = x & 2;
|
h = x & 2;
|
||||||
th_ko = (x & 3) && (!blx_avail || !is_call);
|
th_ko = (x & 3) && (!blx_avail || !is_call);
|
||||||
#ifdef TCC_HAS_RUNTIME_PLTGOT
|
#ifdef TCC_HAS_RUNTIME_PLTGOT
|
||||||
|
@ -622,7 +637,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (th_ko || x >= 0x2000000 || x < -0x2000000)
|
if (th_ko || x >= 0x2000000 || x < -0x2000000)
|
||||||
tcc_error("can't relocate value at %x",addr);
|
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||||
x >>= 2;
|
x >>= 2;
|
||||||
x &= 0xffffff;
|
x &= 0xffffff;
|
||||||
/* Only reached if blx is avail and it is a call */
|
/* Only reached if blx is avail and it is a call */
|
||||||
|
@ -686,7 +701,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
- instruction must be a call (bl) or a jump to PLT */
|
- instruction must be a call (bl) or a jump to PLT */
|
||||||
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
|
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
|
||||||
if (to_thumb || (val & 2) || (!is_call && !to_plt))
|
if (to_thumb || (val & 2) || (!is_call && !to_plt))
|
||||||
tcc_error("can't relocate value at %x",addr);
|
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||||
|
|
||||||
/* Compute and store final offset */
|
/* Compute and store final offset */
|
||||||
s = (x >> 24) & 1;
|
s = (x >> 24) & 1;
|
||||||
|
@ -743,7 +758,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
x = (x * 2) / 2;
|
x = (x * 2) / 2;
|
||||||
x += val - addr;
|
x += val - addr;
|
||||||
if((x^(x>>1))&0x40000000)
|
if((x^(x>>1))&0x40000000)
|
||||||
tcc_error("can't relocate value at %x",addr);
|
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||||
(*(int *)ptr) |= x & 0x7fffffff;
|
(*(int *)ptr) |= x & 0x7fffffff;
|
||||||
}
|
}
|
||||||
case R_ARM_ABS32:
|
case R_ARM_ABS32:
|
||||||
|
@ -769,6 +784,10 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
|
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
|
||||||
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
|
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
|
||||||
break;
|
break;
|
||||||
|
case R_ARM_GLOB_DAT:
|
||||||
|
case R_ARM_JUMP_SLOT:
|
||||||
|
*(addr_t *)ptr = val;
|
||||||
|
break;
|
||||||
case R_ARM_NONE:
|
case R_ARM_NONE:
|
||||||
/* Nothing to do. Normally used to indicate a dependency
|
/* Nothing to do. Normally used to indicate a dependency
|
||||||
on a certain symbol (like for exception handling under EABI). */
|
on a certain symbol (like for exception handling under EABI). */
|
||||||
|
@ -1166,7 +1185,7 @@ static unsigned long put_got_entry(TCCState *s1,
|
||||||
|
|
||||||
/* the symbol is modified so that it will be relocated to
|
/* the symbol is modified so that it will be relocated to
|
||||||
the PLT */
|
the PLT */
|
||||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
if (sym->st_shndx == SHN_UNDEF)
|
||||||
offset = plt->data_offset - 16;
|
offset = plt->data_offset - 16;
|
||||||
}
|
}
|
||||||
#elif defined(TCC_TARGET_C67)
|
#elif defined(TCC_TARGET_C67)
|
||||||
|
@ -1240,22 +1259,47 @@ ST_FUNC void build_got_entries(TCCState *s1)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#elif defined(TCC_TARGET_ARM)
|
#elif defined(TCC_TARGET_ARM)
|
||||||
|
case R_ARM_PC24:
|
||||||
|
case R_ARM_CALL:
|
||||||
|
case R_ARM_JUMP24:
|
||||||
case R_ARM_GOT32:
|
case R_ARM_GOT32:
|
||||||
case R_ARM_GOTOFF:
|
case R_ARM_GOTOFF:
|
||||||
case R_ARM_GOTPC:
|
case R_ARM_GOTPC:
|
||||||
case R_ARM_PLT32:
|
case R_ARM_PLT32:
|
||||||
if (!s1->got)
|
if (!s1->got)
|
||||||
build_got(s1);
|
build_got(s1);
|
||||||
if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
|
|
||||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
|
if (type != R_ARM_GOTOFF && type != R_ARM_GOTPC
|
||||||
|
&& sym->st_shndx == SHN_UNDEF) {
|
||||||
|
unsigned long ofs;
|
||||||
/* look at the symbol got offset. If none, then add one */
|
/* look at the symbol got offset. If none, then add one */
|
||||||
if (type == R_ARM_GOT32)
|
if (type == R_ARM_GOT32)
|
||||||
reloc_type = R_ARM_GLOB_DAT;
|
reloc_type = R_ARM_GLOB_DAT;
|
||||||
else
|
else
|
||||||
reloc_type = R_ARM_JUMP_SLOT;
|
reloc_type = R_ARM_JUMP_SLOT;
|
||||||
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
|
ofs = put_got_entry(s1, reloc_type, sym->st_size,
|
||||||
sym_index);
|
sym->st_info, sym_index);
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("maybegot: %s, %d, %d --> ofs=0x%x\n",
|
||||||
|
(char *) symtab_section->link->data + sym->st_name,
|
||||||
|
type, sym->st_shndx, ofs);
|
||||||
|
#endif
|
||||||
|
if (type != R_ARM_GOT32) {
|
||||||
|
addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data
|
||||||
|
+ rel->r_offset);
|
||||||
|
/* x must be signed! */
|
||||||
|
int x = *ptr & 0xffffff;
|
||||||
|
x = (x << 8) >> 8;
|
||||||
|
x <<= 2;
|
||||||
|
x += ofs;
|
||||||
|
x >>= 2;
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr,
|
||||||
|
(*ptr & 0xff000000) | x, x);
|
||||||
|
#endif
|
||||||
|
*ptr = (*ptr & 0xff000000) | x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R_ARM_THM_JUMP24:
|
case R_ARM_THM_JUMP24:
|
||||||
|
|
Loading…
Reference in a new issue