aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2012-10-10 00:09:42 +0200
committerThomas Preud'homme <robotux@celest.fr>2012-10-10 00:21:26 +0200
commitc6630ef92a21ca33af08b1faa03fba578e12315f (patch)
tree27bae6f9a927f0297904ee995d018c56e7467e67
parent2fe7fd9e875979d0947c17609b64799219485d2d (diff)
downloadtinycc-c6630ef92a21ca33af08b1faa03fba578e12315f.tar.gz
tinycc-c6630ef92a21ca33af08b1faa03fba578e12315f.tar.bz2
Fix R_ARM_CALL when target fonction is Thumb
With R_ARM_CALL, if target function is to be entered in Thumb mode, the relocation is supposed to transform bl in blx. This is not the case actually so this commit is there to fix it.
-rw-r--r--tccelf.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/tccelf.c b/tccelf.c
index 5e1a64e..7943763 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -601,22 +601,30 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
case R_ARM_JUMP24:
case R_ARM_PLT32:
{
- int x;
+ int x, is_thumb, is_call, h;
x = (*(int *)ptr)&0xffffff;
(*(int *)ptr) &= 0xff000000;
if (x & 0x800000)
x -= 0x1000000;
- x *= 4;
- x += val - addr;
+ x <<= 2;
+ is_thumb = val & 1;
+ is_call = (type == R_ARM_CALL);
+ x += (val & -2) - addr;
+ h = x & 2;
#ifndef TCC_TARGET_PE
if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
if (s1->output_type == TCC_OUTPUT_MEMORY)
x += add_jmp_table(s1, val) - val; /* add veneer */
#endif
if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
- tcc_error("can't relocate value at %x",addr);
+ if (!(h && is_call && is_thumb))
+ tcc_error("can't relocate value at %x",addr);
x >>= 2;
x &= 0xffffff;
+ if (is_call && is_thumb) {
+ x |= h << 24;
+ (*(int *)ptr) = 0xfa << 24; /* bl -> blx */
+ }
(*(int *)ptr) |= x;
}
break;