diff --git a/arm64-gen.c b/arm64-gen.c index ab6a4a6b..d537980f 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -552,6 +552,23 @@ ST_FUNC void load(int r, SValue *sv) } if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { + if (sv->sym->type.t & VT_TLS) { + o(0xd53bd05e); /* mrs x30, tpidr_el0 */ + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_HI12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | + ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0, lsl #12 */ + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_LO12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | + ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0 */ + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, svcoff); + else + arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), + intr(r), 30, svcoff); + return; + } arm64_sym(30, sv->sym, // use x30 for address arm64_check_offset(0, arm64_type_size(svtt), svcoff)); if (IS_FREG(r)) @@ -645,6 +662,22 @@ ST_FUNC void store(int r, SValue *sv) if (svr == (VT_CONST | VT_LVAL)) { uint64_t i = sv->c.i; + if (sv->sym && (sv->sym->type.t & VT_TLS)) { + o(0xd53bd05e); + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_HI12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | + ARM64_RN(30) | ARM64_RD(30)); + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_LO12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | + ARM64_RN(30) | ARM64_RD(30)); + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), 30, i); + else + arm64_strx(arm64_type_size(svtt), intr(r), 30, i); + return; + } if (sv->sym) arm64_sym(30, sv->sym, // use x30 for address arm64_check_offset(0, arm64_type_size(svtt), i)); @@ -668,6 +701,22 @@ ST_FUNC void store(int r, SValue *sv) } if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { + if (sv->sym->type.t & VT_TLS) { + o(0xd53bd05e); /* mrs x30, tpidr_el0 */ + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_HI12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | + ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0, lsl #12 */ + greloca(cur_text_section, sv->sym, ind, + R_AARCH64_TLSLE_ADD_TPREL_LO12, 0); + o(ARM64_ADD_IMM | ARM64_SF(1) | + ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0 */ + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), 30, svcoff); + else + arm64_strx(arm64_type_size(svtt), intr(r), 30, svcoff); + return; + } arm64_sym(30, sv->sym, // use x30 for address arm64_check_offset(0, arm64_type_size(svtt), svcoff)); if (IS_FREG(r)) diff --git a/arm64-link.c b/arm64-link.c index 08f6c6b0..39777def 100644 --- a/arm64-link.c +++ b/arm64-link.c @@ -43,6 +43,8 @@ ST_FUNC int code_reloc (int reloc_type) case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12: case R_AARCH64_GLOB_DAT: case R_AARCH64_COPY: return 0; @@ -80,6 +82,8 @@ ST_FUNC int gotplt_entry_type (int reloc_type) case R_AARCH64_COPY: case R_AARCH64_CONDBR19: case R_AARCH64_TSTBR14: + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12: return NO_GOTPLT_ENTRY; case R_AARCH64_ABS32: @@ -365,6 +369,27 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, #endif write64le(ptr, val - rel->r_addend); return; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12: { + addr_t tls_start = 0; + int i; + 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; + } + } + /* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */ + int64_t tp_offset = val - tls_start + 16; + int64_t imm; + if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12) + imm = (tp_offset >> 12) & 0xfff; + else + imm = tp_offset & 0xfff; + write32le(ptr, ((read32le(ptr) & 0xffc003ff) | (imm << 10))); + return; + } case R_AARCH64_RELATIVE: #ifdef TCC_TARGET_PE add32le(ptr, val - s1->pe_imagebase); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index f00906ac..0b0d7a16 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -19,7 +19,7 @@ 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,$(ARCH))) +ifeq (,$(filter x86_64 riscv64 arm64,$(ARCH))) SKIP += 144_tls.test # TLS only implemented on x86_64 so far endif ifeq ($(CONFIG_backtrace),no)