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

This commit is contained in:
Meng Zhuo 2026-05-13 10:30:10 +08:00
parent 841ce0da03
commit 8502540b4a
3 changed files with 53 additions and 2 deletions

View File

@ -313,6 +313,16 @@ ST_FUNC void load(int r, SValue *sv)
#endif
if (fr & VT_LVAL) {
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
int dst_reg = REG_VALUE(r);
o(0x65); /* gs segment prefix */
o(0x8b); /* mov r/m, r */
o(0x04 | (dst_reg << 3)); /* modrm: [sib] | destreg */
o(0x25); /* sib: disp32 */
greloca(cur_text_section, sv->sym, ind, R_386_TLS_LE, fc);
gen_le32(0);
return;
}
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
@ -429,6 +439,16 @@ ST_FUNC void store(int r, SValue *v)
} else
#endif
if ((fr & VT_SYM) && v->sym->type.t & VT_TLS) {
o(0x65); /* gs segment prefix */
o(opc);
o(0x04 | (REG_VALUE(r) << 3)); /* modrm: [sib] | srcreg */
o(0x25); /* sib: disp32 */
greloca(cur_text_section, v->sym, ind, R_386_TLS_LE, fc);
gen_le32(0);
return;
}
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
gen_modrm(opc, r, v->r, v->sym, fc);
} else if (fr != r) {

View File

@ -305,7 +305,6 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
}
return;
case R_386_TLS_LDO_32:
case R_386_TLS_LE:
{
ElfW(Sym) *sym;
Section *sec;
@ -317,6 +316,38 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
add32le(ptr, x);
}
return;
case R_386_TLS_LE:
{
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) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else {
x = val - sec->sh_addr - sec->data_offset;
}
add32le(ptr, x);
}
return;
case R_386_NONE:
return;
default:

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 riscv64 arm64 arm,$(ARCH)))
ifeq (,$(filter x86_64 riscv64 arm64 arm i386,$(ARCH)))
SKIP += 144_tls.test # TLS only implemented on these architectures so far
endif
ifeq ($(CONFIG_backtrace),no)