From 8443e25bf542821a5e2cc84dbbd6b85474b274c9 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Tue, 12 May 2026 19:57:26 +0800 Subject: [PATCH] feat: implement Thread Local Storage frontend support --- tcc.h | 8 ++++++-- tccelf.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- tccgen.c | 16 ++++++++++++++-- tcctok.h | 1 + 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/tcc.h b/tcc.h index 6f2865aa..63881991 100644 --- a/tcc.h +++ b/tcc.h @@ -889,6 +889,7 @@ struct TCCState { /* predefined sections */ Section *text_section, *data_section, *rodata_section, *bss_section; + Section *tdata_section, *tbss_section; Section *common_section; Section *cur_text_section; /* current section where function code is generated */ #ifdef CONFIG_TCC_BCHECK @@ -1063,7 +1064,8 @@ struct filespec { #define VT_STATIC 0x00002000 /* static variable */ #define VT_TYPEDEF 0x00004000 /* typedef definition */ #define VT_INLINE 0x00008000 /* inline definition */ -/* currently unused: 0x000[1248]0000 */ +#define VT_TLS 0x00010000 /* thread-local storage */ +/* currently unused: 0x000[248]0000 */ #define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ #define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) @@ -1081,7 +1083,7 @@ struct filespec { #define VT_ATOMIC VT_VOLATILE /* type mask (except storage) */ -#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) +#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_TLS) #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) /* symbol was created by tccasm.c first */ @@ -1970,6 +1972,8 @@ static inline void post_sem(TCCSem *p) { #define data_section TCC_STATE_VAR(data_section) #define rodata_section TCC_STATE_VAR(rodata_section) #define bss_section TCC_STATE_VAR(bss_section) +#define tdata_section TCC_STATE_VAR(tdata_section) +#define tbss_section TCC_STATE_VAR(tbss_section) #define common_section TCC_STATE_VAR(common_section) #define cur_text_section TCC_STATE_VAR(cur_text_section) #define bounds_section TCC_STATE_VAR(bounds_section) diff --git a/tccelf.c b/tccelf.c index 0ecac996..6d3700a2 100644 --- a/tccelf.c +++ b/tccelf.c @@ -70,6 +70,8 @@ ST_FUNC void tccelf_new(TCCState *s) /* create ro data section (make ro after relocation done with GNU_RELRO) */ rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO); bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + tdata_section = new_section(s, ".tdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS); + tbss_section = new_section(s, ".tbss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS); common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); common_section->sh_num = SHN_COMMON; @@ -2294,7 +2296,7 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) if (k < 0x900) ++d->shnum; if (k < 0x700) { - f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS); + f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR); #if TARGETOS_NetBSD /* NetBSD only supports 2 PT_LOAD sections. See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */ @@ -2353,6 +2355,18 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) ++phnum; if (d->roinf) ++phnum; + { + int has_tls = 0; + for (i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_flags & SHF_TLS) { + has_tls = 1; + break; + } + } + if (has_tls) + ++phnum; + } d->phnum = phnum; d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); @@ -2429,10 +2443,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) ph->p_flags |= PF_W; if (f & SHF_EXECINSTR) ph->p_flags |= PF_X; - if (f & SHF_TLS) { - ph->p_type = PT_TLS; - ph->p_align = align + 1; - } ph->p_offset = file_offset; ph->p_vaddr = addr; @@ -2477,6 +2487,34 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section); if (d->roinf) fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W; + { + /* Create PT_TLS segment covering all TLS sections */ + Section *tls_start_sec = NULL; + addr_t tls_start = 0, tls_end = 0; + for (i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_flags & SHF_TLS && s->sh_size) { + if (!tls_start_sec) { + tls_start_sec = s; + tls_start = s->sh_addr; + tls_end = s->sh_addr + s->sh_size; + } else { + if (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 (tls_start_sec) { + ph = fill_phdr(++ph, PT_TLS, tls_start_sec); + ph->p_vaddr = tls_start; + ph->p_paddr = tls_start; + ph->p_filesz = tls_end - tls_start; + ph->p_memsz = ph->p_filesz; + ph->p_align = tls_start_sec->sh_addralign; + } + } if (d->interp) fill_phdr(&d->phdr[1], PT_INTERP, d->interp); if (phfill) { diff --git a/tccgen.c b/tccgen.c index ad63fae2..7d1381f8 100644 --- a/tccgen.c +++ b/tccgen.c @@ -526,6 +526,8 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, sym_type = STT_NOTYPE; if (IS_ASM_FUNC(t)) sym_type = STT_FUNC; + } else if (t & VT_TLS) { + sym_type = STT_TLS; } else { sym_type = STT_OBJECT; } @@ -4931,7 +4933,12 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label) } goto basic_type2; case TOK_THREAD_LOCAL: - tcc_error("_Thread_local is not implemented"); + case TOK___thread: + if (t & VT_TLS) + tcc_error("multiple thread-local storage specifiers"); + t |= VT_TLS; + next(); + break; default: if (typespec_found) goto the_end; @@ -8376,7 +8383,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, CType *tp = type; while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY)) tp = &tp->ref->type; - if (tp->t & VT_CONSTANT) { + if (type->t & VT_TLS) { + if (has_init) + sec = tdata_section; + else + sec = tbss_section; + } else if (tp->t & VT_CONSTANT) { sec = rodata_section; } else if (has_init) { sec = data_section; diff --git a/tcctok.h b/tcctok.h index ec44b244..b4f5ba7c 100644 --- a/tcctok.h +++ b/tcctok.h @@ -39,6 +39,7 @@ DEF(TOK_RESTRICT3, "__restrict__") DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */ DEF(TOK_THREAD_LOCAL, "_Thread_local") /* C11 thread-local storage */ + DEF(TOK___thread, "__thread") /* GCC thread-local storage extension */ DEF(TOK_GENERIC, "_Generic") DEF(TOK_STATIC_ASSERT, "_Static_assert")