aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2012-10-16 00:31:56 +0200
committerThomas Preud'homme <robotux@celest.fr>2012-10-16 00:31:56 +0200
commit9966fd4eaea163439a63d63d044d0657df1908ea (patch)
treed9777d4451a99796534fe5b51b2fdc6f0aabaa1b
parentc6630ef92a21ca33af08b1faa03fba578e12315f (diff)
downloadtinycc-9966fd4eaea163439a63d63d044d0657df1908ea.tar.gz
tinycc-9966fd4eaea163439a63d63d044d0657df1908ea.tar.bz2
Only use blx if available
Introduce ARM version for the target architecture in order to determine if blx instruction can be used or not. Availability of blx instruction allows for more scenarii supported in R_ARM_CALL relocation. It should also be useful when introducing support for the R_ARM_THM_CALL relocation.
-rw-r--r--tcc.h8
-rw-r--r--tccelf.c19
2 files changed, 19 insertions, 8 deletions
diff --git a/tcc.h b/tcc.h
index 8bca9ae..4e88782 100644
--- a/tcc.h
+++ b/tcc.h
@@ -105,6 +105,14 @@
#define TCC_TARGET_I386
#endif
+#if defined (TCC_TARGET_ARM) && !defined(TCC_ARM_VERSION)
+ #ifdef TCC_ARM_HARDFLOAT
+ #define TCC_ARM_VERSION 7
+ #else
+ #define TCC_ARM_VERSION 4
+ #endif
+#endif
+
#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
#define CONFIG_TCC_BCHECK /* enable bound checking code */
diff --git a/tccelf.c b/tccelf.c
index 7943763..f46a742 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -601,27 +601,30 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
case R_ARM_JUMP24:
case R_ARM_PLT32:
{
- int x, is_thumb, is_call, h;
+ int x, is_thumb, is_call, h, blx_avail;
x = (*(int *)ptr)&0xffffff;
(*(int *)ptr) &= 0xff000000;
if (x & 0x800000)
x -= 0x1000000;
x <<= 2;
+ blx_avail = (TCC_ARM_VERSION >= 5);
is_thumb = val & 1;
is_call = (type == R_ARM_CALL);
- x += (val & -2) - addr;
+ x += val - 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 */
+ if ((x & 3) || x >= 0x4000000 || x < -0x4000000)
+ if (!(x & 3) || !blx_avail || !is_call)
+ 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)
- if (!(h && is_call && is_thumb))
+ if ((x & 3) || x >= 0x4000000 || x < -0x4000000)
+ if (!(x & 3) || !blx_avail || !is_call)
tcc_error("can't relocate value at %x",addr);
x >>= 2;
x &= 0xffffff;
- if (is_call && is_thumb) {
+ /* Only reached if blx is avail and it is a call */
+ if (is_thumb) {
x |= h << 24;
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */
}