feat(riscv64): add TLS Local Exec code generation and linker relocations

This commit is contained in:
Meng Zhuo 2026-05-12 19:57:35 +08:00
parent ea26b85ac0
commit 11f5c6e1f9
3 changed files with 45 additions and 1 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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)