aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
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 /tccelf.c
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.
Diffstat (limited to 'tccelf.c')
-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;