History

feat(x86_64): add TLS Local Exec support with tests

Meng Zhuo committed 6 months ago

Commit ea26b851 parent 8443e255 files · +141 −6Browse files

Unified · Split

5 files
  1. tests/tests2/144_tls.c +50 −0
  2. tests/tests2/144_tls.expect +8 −0
  3. tests/tests2/Makefile +7 −0
  4. x86_64-gen.c +29 −1
  5. x86_64-link.c +47 −5
tests/tests2/144_tls.c+50−0
@@ -0,0 +1,50 @@
1+#include <stdio.h>
2+#include <pthread.h>
3+
4+__thread int tls_init = 42;
5+__thread int tls_zero;
6+
7+static void *thread_func(void *arg)
8+{
9+ (void)arg;
10+
11+ printf("%d\n", tls_init);
12+ if (tls_init != 42) return (void *)1;
13+
14+ printf("%d\n", tls_zero);
15+ if (tls_zero != 0) return (void *)1;
16+
17+ tls_init = 100;
18+ tls_zero = 200;
19+
20+ printf("%d\n", tls_init);
21+ printf("%d\n", tls_zero);
22+
23+ return (void *)0;
24+}
25+
26+int main()
27+{
28+ pthread_t t;
29+ void *ret;
30+ int errors = 0;
31+
32+ printf("%d\n", tls_init);
33+ if (tls_init != 42) errors = 1;
34+
35+ printf("%d\n", tls_zero);
36+ if (tls_zero != 0) errors = 1;
37+
38+ pthread_create(&t, NULL, thread_func, NULL);
39+ pthread_join(t, &ret);
40+
41+ if (ret) errors = 1;
42+
43+ printf("%d\n", tls_init);
44+ if (tls_init != 42) errors = 1;
45+
46+ printf("%d\n", tls_zero);
47+ if (tls_zero != 0) errors = 1;
48+
49+ return errors;
50+}
tests/tests2/144_tls.expect+8−0
@@ -0,0 +1,8 @@
1+42
2+0
3+42
4+0
5+100
6+200
7+42
8+0
tests/tests2/Makefile+7−0
@@ -19,6 +19,9 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) · 18 unmodified lines
1919 SKIP += 85_asm-outside-function.test # x86 asm
2020 SKIP += 127_asm_goto.test # hardcodes x86 asm
2121 endif
22+ifeq (,$(filter x86_64,$(ARCH)))
23+ SKIP += 144_tls.test # TLS only implemented on x86_64 so far
24+endif
2225 ifeq ($(CONFIG_backtrace),no)
2326 SKIP += 113_btdll.test
2427 CONFIG_bcheck = no
@@ -107,6 +110,10 @@ GEN-ALWAYS = · 82 unmodified lines
107110 # constructor/destructor
108111 108_constructor.test: NORUN = true
109112
113+# TLS needs executable and pthread, not -run
114+144_tls.test: FLAGS += -pthread
115+144_tls.test: NORUN = true
116+
110117 112_backtrace.test: FLAGS += -dt -b
111118 112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
112119 -e 's;[0-9A-Fa-fx]\{5,\};........;g' \
x86_64-gen.c+29−1
@@ -368,7 +368,8 @@ void load(int r, SValue *sv) · 367 unmodified lines
368368 #ifndef TCC_TARGET_PE
369369 /* we use indirect access via got */
370370 if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
371− (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) {
371+ (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)
372+ && !(sv->sym->type.t & VT_TLS)) {
372373 /* use the result register as a temporal register */
373374 int tr = r | TREG_MEM;
374375 if (is_float(ft)) {
@@ -385,6 +386,19 @@ void load(int r, SValue *sv) · 10 unmodified lines
385386 v = fr & VT_VALMASK;
386387 if (fr & VT_LVAL) {
387388 int b, ll;
389+ if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
390+ int dst_reg = REG_VALUE(r);
391+ int is64 = is64_type(ft);
392+ o(0x64); /* fs segment prefix */
393+ if (is64 || REX_BASE(r))
394+ o(0x40 | (REX_BASE(r) << 0) | (is64 << 3)); /* rex.w/rex.r */
395+ o(0x8b); /* mov r/m, r */
396+ o(0x04 | (dst_reg << 3)); /* modrm: [sib] | destreg */
397+ o(0x25); /* sib: disp32 */
398+ greloca(cur_text_section, sv->sym, ind, R_X86_64_TPOFF32, fc);
399+ gen_le32(0);
400+ return;
401+ }
388402 if (v == VT_LLOCAL) {
389403 v1.type.t = VT_PTR;
390404 v1.r = VT_LOCAL | VT_LVAL;
@@ -572,6 +586,20 @@ void store(int r, SValue *v) · 181 unmodified lines
572586 ft &= ~(VT_VOLATILE | VT_CONSTANT);
573587 bt = ft & VT_BTYPE;
574588
589+ if ((v->r & VT_SYM) && v->sym->type.t & VT_TLS) {
590+ int src_reg = REG_VALUE(r);
591+ int is64 = is64_type(bt);
592+ o(0x64);
593+ if (is64 || REX_BASE(r))
594+ o(0x40 | (REX_BASE(r) << 0) | (is64 << 3));
595+ o(0x89);
596+ o(0x04 | (src_reg << 3));
597+ o(0x25);
598+ greloca(cur_text_section, v->sym, ind, R_X86_64_TPOFF32, fc);
599+ gen_le32(0);
600+ return;
601+ }
602+
575603 #ifndef TCC_TARGET_PE
576604 /* we need to access the variable via got */
577605 if (fr == VT_CONST
x86_64-link.c+47−5
@@ -13,7 +13,7 @@ · 12 unmodified lines
1313 #define R_NUM R_X86_64_NUM
1414
1515 #define ELF_START_ADDR 0x400000
16−#define ELF_PAGE_SIZE 0x200000
16+#define ELF_PAGE_SIZE 0x1000
1717
1818 #define PCRELATIVE_DLLPLT 1
1919 #define RELOCATE_DLLPLT 1
@@ -96,13 +96,15 @@ ST_FUNC int gotplt_entry_type (int reloc_type) · 76 unmodified lines
9696 case R_X86_64_TLSGD:
9797 case R_X86_64_TLSLD:
9898 case R_X86_64_DTPOFF32:
99− case R_X86_64_TPOFF32:
10099 case R_X86_64_DTPOFF64:
101− case R_X86_64_TPOFF64:
102100 case R_X86_64_REX_GOTPCRELX:
103101 case R_X86_64_PLT32:
104102 case R_X86_64_PLTOFF64:
105103 return ALWAYS_GOTPLT_ENTRY;
104+
105+ case R_X86_64_TPOFF32:
106+ case R_X86_64_TPOFF64:
107+ return NO_GOTPLT_ENTRY;
106108 }
107109
108110 return -1;
@@ -372,10 +374,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, · 263 unmodified lines
372374 ElfW(Sym) *sym;
373375 Section *sec;
374376 int32_t x;
377+ addr_t tls_start = 0, tls_end = 0, tls_align = 1;
378+ int i;
375379
376380 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
377381 sec = s1->sections[sym->st_shndx];
378− x = val - sec->sh_addr - sec->data_offset;
382+
383+ for (i = 1; i < s1->nb_sections; i++) {
384+ Section *s = s1->sections[i];
385+ if (s->sh_flags & SHF_TLS && s->sh_size) {
386+ if (!tls_start || s->sh_addr < tls_start)
387+ tls_start = s->sh_addr;
388+ if (s->sh_addr + s->sh_size > tls_end)
389+ tls_end = s->sh_addr + s->sh_size;
390+ if (s->sh_addralign > tls_align)
391+ tls_align = s->sh_addralign;
392+ }
393+ }
394+ if (tls_end > tls_start) {
395+ addr_t tls_size = tls_end - tls_start;
396+ addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
397+ x = val - (tls_start + aligned_size);
398+ } else {
399+ x = val - sec->sh_addr - sec->data_offset;
400+ }
379401 add32le(ptr, x);
380402 }
381403 break;
@@ -385,10 +407,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, · 3 unmodified lines
385407 ElfW(Sym) *sym;
386408 Section *sec;
387409 int32_t x;
410+ addr_t tls_start = 0, tls_end = 0, tls_align = 1;
411+ int i;
388412
389413 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
390414 sec = s1->sections[sym->st_shndx];
391− x = val - sec->sh_addr - sec->data_offset;
415+
416+ for (i = 1; i < s1->nb_sections; i++) {
417+ Section *s = s1->sections[i];
418+ if (s->sh_flags & SHF_TLS && s->sh_size) {
419+ if (!tls_start || s->sh_addr < tls_start)
420+ tls_start = s->sh_addr;
421+ if (s->sh_addr + s->sh_size > tls_end)
422+ tls_end = s->sh_addr + s->sh_size;
423+ if (s->sh_addralign > tls_align)
424+ tls_align = s->sh_addralign;
425+ }
426+ }
427+ if (tls_end > tls_start) {
428+ addr_t tls_size = tls_end - tls_start;
429+ addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
430+ x = val - (tls_start + aligned_size);
431+ } else {
432+ x = val - sec->sh_addr - sec->data_offset;
433+ }
392434 add64le(ptr, x);
393435 }
394436 break;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t