From fad68c9163a7c74888f1bd28e3955b78fcb4c6c1 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Sun, 7 Oct 2012 17:48:46 +0200 Subject: [PATCH] Add support for R_ARM_THM_{JUMP24,CALL} relocs Add support for relocations R_ARM_THM_JUMP24 and R_ARM_THM_CALL. These are encountered with gcc when compiling for armv6 or greater with -mthumb flag and a call (conditional or not) is done. --- elf.h | 3 ++- tccelf.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/elf.h b/elf.h index 2d15d31e..a82d8f74 100644 --- a/elf.h +++ b/elf.h @@ -1673,7 +1673,7 @@ typedef Elf32_Addr Elf32_Conflict; #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 /* Direct 8 bit */ #define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 +#define R_ARM_THM_CALL 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 @@ -1690,6 +1690,7 @@ typedef Elf32_Addr Elf32_Conflict; #define R_ARM_PLT32 27 /* 32 bit PLT address */ #define R_ARM_CALL 28 #define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 #define R_ARM_V4BX 40 #define R_ARM_PREL31 42 #define R_ARM_MOVW_ABS_NC 43 diff --git a/tccelf.c b/tccelf.c index f46a7423..e5bb1cb4 100644 --- a/tccelf.c +++ b/tccelf.c @@ -631,6 +631,70 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) (*(int *)ptr) |= x; } break; + /* Since these relocations only concern Thumb-2 and blx instruction was + introduced before Thumb-2, we can assume blx is available and not + guard its use */ + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + { + int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; + int to_thumb, is_call, blx_bit = 1 << 12; + + /* weak reference */ + if (sym->st_shndx == SHN_UNDEF && + ELFW(ST_BIND)(sym->st_info) == STB_WEAK) + break; + + /* Get initial offset */ + hi = (*(uint16_t *)ptr); + lo = (*(uint16_t *)(ptr+2)); + s = (hi >> 10) & 1; + j1 = (lo >> 13) & 1; + j2 = (lo >> 11) & 1; + i1 = (j1 ^ s) ^ 1; + i2 = (j2 ^ s) ^ 1; + imm10 = hi & 0x3ff; + imm11 = lo & 0x7ff; + x = (s << 24) | (i1 << 23) | (i2 << 22) | + (imm10 << 12) | (imm11 << 1); + if (x & 0x01000000) + x -= 0x02000000; + + /* Relocation infos */ + to_thumb = val & 1; + is_call = (type == R_ARM_THM_CALL); + + /* Compute final offset */ + x += val - addr; + if (!to_thumb && is_call) { + blx_bit = 0; /* bl -> blx */ + x = (x + 3) & -4; /* Compute offset from aligned PC */ + } + + /* Check that relocation is possible + * offset must not be out of range + * if target is to be entered in arm mode: + - bit 1 must not set + - instruction must be a call (bl) */ + if (!to_thumb || x >= 0x1000000 || x < -0x1000000) + if (to_thumb || (val & 2) || !is_call) + tcc_error("can't relocate value at %x",addr); + + /* Compute and store final offset */ + s = (x >> 24) & 1; + i1 = (x >> 23) & 1; + i2 = (x >> 22) & 1; + j1 = s ^ (i1 ^ 1); + j2 = s ^ (i2 ^ 1); + imm10 = (x >> 12) & 0x3ff; + imm11 = (x >> 1) & 0x7ff; + (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | + (s << 10) | imm10); + (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | + (j1 << 13) | blx_bit | (j2 << 11) | + imm11); + } + break; case R_ARM_MOVT_ABS: case R_ARM_MOVW_ABS_NC: { -- 2.11.4.GIT