aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */
}