From 11f5c6e1f9e35dbe44982a35ec5f4c7f3b8387c3 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Tue, 12 May 2026 19:57:35 +0800 Subject: [PATCH] feat(riscv64): add TLS Local Exec code generation and linker relocations --- riscv64-gen.c | 13 +++++++++++++ riscv64-link.c | 31 +++++++++++++++++++++++++++++++ tests/tests2/Makefile | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/riscv64-gen.c b/riscv64-gen.c index 6ded4c52..8084c6b6 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -179,6 +179,19 @@ static int load_symofs(int r, SValue *sv, int forstore, int *new_fc) if (sv->r & VT_SYM) { Sym label = {0}; assert(v == VT_CONST); + if (sv->sym->type.t & VT_TLS) { + /* TLS Local Exec model: lui + addi + add tp */ + rr = is_ireg(r) ? ireg(r) : 5; + greloca(cur_text_section, sv->sym, ind, + R_RISCV_TPREL_HI20, sv->c.i); + o(0x37 | (rr << 7)); // lui RR, 0 %tprel_hi(sym) + greloca(cur_text_section, sv->sym, ind, + R_RISCV_TPREL_LO12_I, 0); + EI(0x13, 0, rr, rr, 0); // addi RR, RR, 0 %tprel_lo(sym) + ER(0x33, 0, rr, rr, 4, 0); // add RR, RR, tp + *new_fc = 0; + return rr; + } if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax greloca(cur_text_section, sv->sym, ind, R_RISCV_PCREL_HI20, sv->c.i); diff --git a/riscv64-link.c b/riscv64-link.c index 0d2ad2a4..625cccfd 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -53,6 +53,8 @@ ST_FUNC int code_reloc (int reloc_type) case R_RISCV_64: case R_RISCV_SET_ULEB128: case R_RISCV_SUB_ULEB128: + case R_RISCV_TPREL_HI20: + case R_RISCV_TPREL_LO12_I: return 0; case R_RISCV_CALL_PLT: @@ -101,6 +103,10 @@ ST_FUNC int gotplt_entry_type (int reloc_type) case R_RISCV_GOT_HI20: return ALWAYS_GOTPLT_ENTRY; + + case R_RISCV_TPREL_HI20: + case R_RISCV_TPREL_LO12_I: + return NO_GOTPLT_ENTRY; } return -1; } @@ -399,6 +405,31 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, RELATIVE relocations from object files. */ return; + case R_RISCV_TPREL_HI20: + case R_RISCV_TPREL_LO12_I: { + 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; + } + } + int64_t tp_offset = val - tls_start; + if (type == R_RISCV_TPREL_HI20) { + off64 = (int64_t)(tp_offset + 0x800) >> 12; + if ((off64 + ((uint64_t)1 << 20)) >> 21) + tcc_error_noabort("R_RISCV_TPREL_HI20 relocation failed"); + write32le(ptr, (read32le(ptr) & 0xfff) + | ((off64 & 0xfffff) << 12)); + } else { + write32le(ptr, (read32le(ptr) & 0xfffff) + | (((tp_offset) & 0xfff) << 20)); + } + return; + } + default: fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", type, (unsigned)addr, ptr, (unsigned)val); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 0fd98687..f00906ac 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,$(ARCH))) +ifeq (,$(filter x86_64 riscv64,$(ARCH))) SKIP += 144_tls.test # TLS only implemented on x86_64 so far endif ifeq ($(CONFIG_backtrace),no)