diff --git a/arm-gen.c b/arm-gen.c index 972e4228..bba80189 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -572,7 +572,7 @@ static void load_value(SValue *sv, int r) void load(int r, SValue *sv) { int v, ft, fc, fr, sign; - uint32_t op; + uint32_t op, base; SValue v1; fr = sv->r; @@ -588,7 +588,15 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { - uint32_t base = 0xB; // fp + if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) { + uint32_t op; + o(0xee1d0fe0); /* mrc p15, 0, lr, c13, c0, 3 */ + op = 0xe510e000; /* ldr r, [lr, #0] */ + greloca(cur_text_section, sv->sym, ind, R_ARM_TLS_LE32, 0); + o(op | (intr(r) << 12)); + return; + } + base = 0xB; // fp if(v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; @@ -703,7 +711,7 @@ void store(int r, SValue *sv) { SValue v1; int v, ft, fc, fr, sign; - uint32_t op; + uint32_t op, base; fr = sv->r; ft = sv->type.t; @@ -718,7 +726,15 @@ void store(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL || fr == VT_LOCAL) { - uint32_t base = 0xb; /* fp */ + if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) { + uint32_t op; + o(0xee1d0fe0); /* mrc p15, 0, lr, c13, c0, 3 */ + op = 0xe500e000; /* str r, [lr, #0] */ + greloca(cur_text_section, sv->sym, ind, R_ARM_TLS_LE32, 0); + o(op | (intr(r) << 12)); + return; + } + base = 0xb; /* fp */ if(v < VT_CONST) { base=intr(v); v=VT_LOCAL; diff --git a/arm-link.c b/arm-link.c index c642c16d..2f0bf4c7 100644 --- a/arm-link.c +++ b/arm-link.c @@ -44,6 +44,7 @@ ST_FUNC int code_reloc (int reloc_type) case R_ARM_TARGET1: case R_ARM_MOVT_PREL: case R_ARM_MOVW_PREL_NC: + case R_ARM_TLS_LE32: return 0; case R_ARM_PC24: @@ -70,6 +71,7 @@ ST_FUNC int gotplt_entry_type (int reloc_type) case R_ARM_COPY: case R_ARM_GLOB_DAT: case R_ARM_JUMP_SLOT: + case R_ARM_TLS_LE32: return NO_GOTPLT_ENTRY; case R_ARM_PC24: @@ -430,6 +432,36 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, #endif /* do nothing */ return; + case R_ARM_TLS_LE32: + { + ElfW(Sym) *sym; + Section *sec; + int32_t x; + addr_t tls_start = 0, tls_end = 0, tls_align = 1; + int i; + + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + sec = s1->sections[sym->st_shndx]; + + for (i = 1; i < s1->nb_sections; i++) { + Section *s = s1->sections[i]; + if (s->sh_flags & SHF_TLS && s->sh_size) { + if (!tls_start || s->sh_addr < tls_start) + tls_start = s->sh_addr; + if (s->sh_addr + s->sh_size > tls_end) + tls_end = s->sh_addr + s->sh_size; + if (s->sh_addralign > tls_align) + tls_align = s->sh_addralign; + } + } + if (tls_end > tls_start) { + x = val - tls_start + 8; + } else { + x = val - sec->sh_addr - sec->data_offset + 8; + } + add32le(ptr, x); + } + return; default: fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", type, (unsigned)addr, ptr, (unsigned)val); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 0b0d7a16..69e91e33 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -19,8 +19,8 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) SKIP += 85_asm-outside-function.test # x86 asm SKIP += 127_asm_goto.test # hardcodes x86 asm endif -ifeq (,$(filter x86_64 riscv64 arm64,$(ARCH))) - SKIP += 144_tls.test # TLS only implemented on x86_64 so far +ifeq (,$(filter x86_64 riscv64 arm64 arm,$(ARCH))) + SKIP += 144_tls.test # TLS only implemented on these architectures so far endif ifeq ($(CONFIG_backtrace),no) SKIP += 113_btdll.test