Unified · Split
| @@ -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 | +} | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +42 | |
| 2 | +0 | |
| 3 | +42 | |
| 4 | +0 | |
| 5 | +100 | |
| 6 | +200 | |
| 7 | +42 | |
| 8 | +0 | |
| @@ -19,6 +19,9 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) · 18 unmodified lines | ||
| 19 | 19 | SKIP += 85_asm-outside-function.test # x86 asm |
| 20 | 20 | SKIP += 127_asm_goto.test # hardcodes x86 asm |
| 21 | 21 | endif |
| 22 | +ifeq (,$(filter x86_64,$(ARCH))) | |
| 23 | + SKIP += 144_tls.test # TLS only implemented on x86_64 so far | |
| 24 | +endif | |
| 22 | 25 | ifeq ($(CONFIG_backtrace),no) |
| 23 | 26 | SKIP += 113_btdll.test |
| 24 | 27 | CONFIG_bcheck = no |
| @@ -107,6 +110,10 @@ GEN-ALWAYS = · 82 unmodified lines | ||
| 107 | 110 | # constructor/destructor |
| 108 | 111 | 108_constructor.test: NORUN = true |
| 109 | 112 | |
| 113 | +# TLS needs executable and pthread, not -run | |
| 114 | +144_tls.test: FLAGS += -pthread | |
| 115 | +144_tls.test: NORUN = true | |
| 116 | + | |
| 110 | 117 | 112_backtrace.test: FLAGS += -dt -b |
| 111 | 118 | 112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \ |
| 112 | 119 | -e 's;[0-9A-Fa-fx]\{5,\};........;g' \ |
| @@ -368,7 +368,8 @@ void load(int r, SValue *sv) · 367 unmodified lines | ||
| 368 | 368 | #ifndef TCC_TARGET_PE |
| 369 | 369 | /* we use indirect access via got */ |
| 370 | 370 | 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)) { | |
| 372 | 373 | /* use the result register as a temporal register */ |
| 373 | 374 | int tr = r | TREG_MEM; |
| 374 | 375 | if (is_float(ft)) { |
| @@ -385,6 +386,19 @@ void load(int r, SValue *sv) · 10 unmodified lines | ||
| 385 | 386 | v = fr & VT_VALMASK; |
| 386 | 387 | if (fr & VT_LVAL) { |
| 387 | 388 | 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 | + } | |
| 388 | 402 | if (v == VT_LLOCAL) { |
| 389 | 403 | v1.type.t = VT_PTR; |
| 390 | 404 | v1.r = VT_LOCAL | VT_LVAL; |
| @@ -572,6 +586,20 @@ void store(int r, SValue *v) · 181 unmodified lines | ||
| 572 | 586 | ft &= ~(VT_VOLATILE | VT_CONSTANT); |
| 573 | 587 | bt = ft & VT_BTYPE; |
| 574 | 588 | |
| 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 | + | |
| 575 | 603 | #ifndef TCC_TARGET_PE |
| 576 | 604 | /* we need to access the variable via got */ |
| 577 | 605 | if (fr == VT_CONST |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #define R_NUM R_X86_64_NUM |
| 14 | 14 | |
| 15 | 15 | #define ELF_START_ADDR 0x400000 |
| 16 | −#define ELF_PAGE_SIZE 0x200000 | |
| 16 | +#define ELF_PAGE_SIZE 0x1000 | |
| 17 | 17 | |
| 18 | 18 | #define PCRELATIVE_DLLPLT 1 |
| 19 | 19 | #define RELOCATE_DLLPLT 1 |
| @@ -96,13 +96,15 @@ ST_FUNC int gotplt_entry_type (int reloc_type) · 76 unmodified lines | ||
| 96 | 96 | case R_X86_64_TLSGD: |
| 97 | 97 | case R_X86_64_TLSLD: |
| 98 | 98 | case R_X86_64_DTPOFF32: |
| 99 | − case R_X86_64_TPOFF32: | |
| 100 | 99 | case R_X86_64_DTPOFF64: |
| 101 | − case R_X86_64_TPOFF64: | |
| 102 | 100 | case R_X86_64_REX_GOTPCRELX: |
| 103 | 101 | case R_X86_64_PLT32: |
| 104 | 102 | case R_X86_64_PLTOFF64: |
| 105 | 103 | return ALWAYS_GOTPLT_ENTRY; |
| 104 | + | |
| 105 | + case R_X86_64_TPOFF32: | |
| 106 | + case R_X86_64_TPOFF64: | |
| 107 | + return NO_GOTPLT_ENTRY; | |
| 106 | 108 | } |
| 107 | 109 | |
| 108 | 110 | return -1; |
| @@ -372,10 +374,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, · 263 unmodified lines | ||
| 372 | 374 | ElfW(Sym) *sym; |
| 373 | 375 | Section *sec; |
| 374 | 376 | int32_t x; |
| 377 | + addr_t tls_start = 0, tls_end = 0, tls_align = 1; | |
| 378 | + int i; | |
| 375 | 379 | |
| 376 | 380 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 377 | 381 | 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 | + } | |
| 379 | 401 | add32le(ptr, x); |
| 380 | 402 | } |
| 381 | 403 | break; |
| @@ -385,10 +407,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, · 3 unmodified lines | ||
| 385 | 407 | ElfW(Sym) *sym; |
| 386 | 408 | Section *sec; |
| 387 | 409 | int32_t x; |
| 410 | + addr_t tls_start = 0, tls_end = 0, tls_align = 1; | |
| 411 | + int i; | |
| 388 | 412 | |
| 389 | 413 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 390 | 414 | 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 | + } | |
| 392 | 434 | add64le(ptr, x); |
| 393 | 435 | } |
| 394 | 436 | break; |