aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2014-04-06 01:02:42 +0200
committerMichael Matz <matz@suse.de>2014-04-06 01:50:35 +0200
commit01c041923474750a236da02561f0f8835445848b (patch)
tree057c697fce7a5015a9cc127fa74c765302be39e7
parent9750d0b725d65296364c08451a985c717bf1890d (diff)
downloadtinycc-01c041923474750a236da02561f0f8835445848b.tar.gz
tinycc-01c041923474750a236da02561f0f8835445848b.tar.bz2
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.
-rw-r--r--tcc.h2
-rw-r--r--tccelf.c62
2 files changed, 54 insertions, 10 deletions
diff --git a/tcc.h b/tcc.h
index 76f25bd..5033b19 100644
--- a/tcc.h
+++ b/tcc.h
@@ -712,7 +712,7 @@ struct TCCState {
void *write_mem;
unsigned long mem_size;
# endif
-# if !defined TCC_TARGET_PE && (defined TCC_TARGET_ARM)
+# if !defined TCC_TARGET_PE && (0)
/* write PLT and GOT here */
char *runtime_plt_and_got;
unsigned runtime_plt_and_got_offset;
diff --git a/tccelf.c b/tccelf.c
index 4ed845b..6f63f83 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -20,6 +20,9 @@
#include "tcc.h"
+/* Define this to get some debug output during relocation processing. */
+#undef DEBUG_RELOC
+
/* XXX: avoid static variable */
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);
if (addr) {
sym->st_value = (addr_t)addr;
+#ifdef DEBUG_RELOC
+ printf ("relocate_sym: %s -> 0x%x\n", name, sym->st_value);
+#endif
goto found;
}
#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;
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;
if (x & 0x800000)
x -= 0x1000000;
@@ -610,6 +621,10 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
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;
th_ko = (x & 3) && (!blx_avail || !is_call);
#ifdef TCC_HAS_RUNTIME_PLTGOT
@@ -622,7 +637,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
}
#endif
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 &= 0xffffff;
/* 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 */
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
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 */
s = (x >> 24) & 1;
@@ -743,7 +758,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
x = (x * 2) / 2;
x += val - addr;
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;
}
case R_ARM_ABS32:
@@ -769,6 +784,10 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
break;
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ *(addr_t *)ptr = val;
+ break;
case R_ARM_NONE:
/* Nothing to do. Normally used to indicate a dependency
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 PLT */
- if (s1->output_type == TCC_OUTPUT_EXE)
+ if (sym->st_shndx == SHN_UNDEF)
offset = plt->data_offset - 16;
}
#elif defined(TCC_TARGET_C67)
@@ -1240,22 +1259,47 @@ ST_FUNC void build_got_entries(TCCState *s1)
}
break;
#elif defined(TCC_TARGET_ARM)
+ case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
case R_ARM_GOT32:
case R_ARM_GOTOFF:
case R_ARM_GOTPC:
case R_ARM_PLT32:
if (!s1->got)
build_got(s1);
- if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
- sym_index = ELFW(R_SYM)(rel->r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+ sym_index = ELFW(R_SYM)(rel->r_info);
+ 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 */
if (type == R_ARM_GOT32)
reloc_type = R_ARM_GLOB_DAT;
else
reloc_type = R_ARM_JUMP_SLOT;
- put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
- sym_index);
+ ofs = put_got_entry(s1, reloc_type, sym->st_size,
+ 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;
case R_ARM_THM_JUMP24: