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