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

This commit is contained in:
Meng Zhuo 2026-05-13 10:29:44 +08:00
parent 8abaf10ab5
commit 841ce0da03
3 changed files with 54 additions and 6 deletions

View File

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

View File

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

View File

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