mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
feat(x86_64): add TLS Local Exec support with tests
This commit is contained in:
parent
8443e25bf5
commit
ea26b85ac0
50
tests/tests2/144_tls.c
Normal file
50
tests/tests2/144_tls.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
__thread int tls_init = 42;
|
||||||
|
__thread int tls_zero;
|
||||||
|
|
||||||
|
static void *thread_func(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
printf("%d\n", tls_init);
|
||||||
|
if (tls_init != 42) return (void *)1;
|
||||||
|
|
||||||
|
printf("%d\n", tls_zero);
|
||||||
|
if (tls_zero != 0) return (void *)1;
|
||||||
|
|
||||||
|
tls_init = 100;
|
||||||
|
tls_zero = 200;
|
||||||
|
|
||||||
|
printf("%d\n", tls_init);
|
||||||
|
printf("%d\n", tls_zero);
|
||||||
|
|
||||||
|
return (void *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
pthread_t t;
|
||||||
|
void *ret;
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
printf("%d\n", tls_init);
|
||||||
|
if (tls_init != 42) errors = 1;
|
||||||
|
|
||||||
|
printf("%d\n", tls_zero);
|
||||||
|
if (tls_zero != 0) errors = 1;
|
||||||
|
|
||||||
|
pthread_create(&t, NULL, thread_func, NULL);
|
||||||
|
pthread_join(t, &ret);
|
||||||
|
|
||||||
|
if (ret) errors = 1;
|
||||||
|
|
||||||
|
printf("%d\n", tls_init);
|
||||||
|
if (tls_init != 42) errors = 1;
|
||||||
|
|
||||||
|
printf("%d\n", tls_zero);
|
||||||
|
if (tls_zero != 0) errors = 1;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
8
tests/tests2/144_tls.expect
Normal file
8
tests/tests2/144_tls.expect
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
42
|
||||||
|
0
|
||||||
|
42
|
||||||
|
0
|
||||||
|
100
|
||||||
|
200
|
||||||
|
42
|
||||||
|
0
|
||||||
@ -19,6 +19,9 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
|
|||||||
SKIP += 85_asm-outside-function.test # x86 asm
|
SKIP += 85_asm-outside-function.test # x86 asm
|
||||||
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
||||||
endif
|
endif
|
||||||
|
ifeq (,$(filter x86_64,$(ARCH)))
|
||||||
|
SKIP += 144_tls.test # TLS only implemented on x86_64 so far
|
||||||
|
endif
|
||||||
ifeq ($(CONFIG_backtrace),no)
|
ifeq ($(CONFIG_backtrace),no)
|
||||||
SKIP += 113_btdll.test
|
SKIP += 113_btdll.test
|
||||||
CONFIG_bcheck = no
|
CONFIG_bcheck = no
|
||||||
@ -107,6 +110,10 @@ GEN-ALWAYS =
|
|||||||
# constructor/destructor
|
# constructor/destructor
|
||||||
108_constructor.test: NORUN = true
|
108_constructor.test: NORUN = true
|
||||||
|
|
||||||
|
# TLS needs executable and pthread, not -run
|
||||||
|
144_tls.test: FLAGS += -pthread
|
||||||
|
144_tls.test: NORUN = true
|
||||||
|
|
||||||
112_backtrace.test: FLAGS += -dt -b
|
112_backtrace.test: FLAGS += -dt -b
|
||||||
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
||||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||||
|
|||||||
30
x86_64-gen.c
30
x86_64-gen.c
@ -368,7 +368,8 @@ void load(int r, SValue *sv)
|
|||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
/* we use indirect access via got */
|
/* we use indirect access via got */
|
||||||
if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
|
if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
|
||||||
(fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) {
|
(fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)
|
||||||
|
&& !(sv->sym->type.t & VT_TLS)) {
|
||||||
/* use the result register as a temporal register */
|
/* use the result register as a temporal register */
|
||||||
int tr = r | TREG_MEM;
|
int tr = r | TREG_MEM;
|
||||||
if (is_float(ft)) {
|
if (is_float(ft)) {
|
||||||
@ -385,6 +386,19 @@ void load(int r, SValue *sv)
|
|||||||
v = fr & VT_VALMASK;
|
v = fr & VT_VALMASK;
|
||||||
if (fr & VT_LVAL) {
|
if (fr & VT_LVAL) {
|
||||||
int b, ll;
|
int b, ll;
|
||||||
|
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
|
||||||
|
int dst_reg = REG_VALUE(r);
|
||||||
|
int is64 = is64_type(ft);
|
||||||
|
o(0x64); /* fs segment prefix */
|
||||||
|
if (is64 || REX_BASE(r))
|
||||||
|
o(0x40 | (REX_BASE(r) << 0) | (is64 << 3)); /* rex.w/rex.r */
|
||||||
|
o(0x8b); /* mov r/m, r */
|
||||||
|
o(0x04 | (dst_reg << 3)); /* modrm: [sib] | destreg */
|
||||||
|
o(0x25); /* sib: disp32 */
|
||||||
|
greloca(cur_text_section, sv->sym, ind, R_X86_64_TPOFF32, fc);
|
||||||
|
gen_le32(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (v == VT_LLOCAL) {
|
if (v == VT_LLOCAL) {
|
||||||
v1.type.t = VT_PTR;
|
v1.type.t = VT_PTR;
|
||||||
v1.r = VT_LOCAL | VT_LVAL;
|
v1.r = VT_LOCAL | VT_LVAL;
|
||||||
@ -572,6 +586,20 @@ void store(int r, SValue *v)
|
|||||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||||
bt = ft & VT_BTYPE;
|
bt = ft & VT_BTYPE;
|
||||||
|
|
||||||
|
if ((v->r & VT_SYM) && v->sym->type.t & VT_TLS) {
|
||||||
|
int src_reg = REG_VALUE(r);
|
||||||
|
int is64 = is64_type(bt);
|
||||||
|
o(0x64);
|
||||||
|
if (is64 || REX_BASE(r))
|
||||||
|
o(0x40 | (REX_BASE(r) << 0) | (is64 << 3));
|
||||||
|
o(0x89);
|
||||||
|
o(0x04 | (src_reg << 3));
|
||||||
|
o(0x25);
|
||||||
|
greloca(cur_text_section, v->sym, ind, R_X86_64_TPOFF32, fc);
|
||||||
|
gen_le32(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
/* we need to access the variable via got */
|
/* we need to access the variable via got */
|
||||||
if (fr == VT_CONST
|
if (fr == VT_CONST
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#define R_NUM R_X86_64_NUM
|
#define R_NUM R_X86_64_NUM
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x400000
|
#define ELF_START_ADDR 0x400000
|
||||||
#define ELF_PAGE_SIZE 0x200000
|
#define ELF_PAGE_SIZE 0x1000
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
#define PCRELATIVE_DLLPLT 1
|
||||||
#define RELOCATE_DLLPLT 1
|
#define RELOCATE_DLLPLT 1
|
||||||
@ -96,13 +96,15 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
|
|||||||
case R_X86_64_TLSGD:
|
case R_X86_64_TLSGD:
|
||||||
case R_X86_64_TLSLD:
|
case R_X86_64_TLSLD:
|
||||||
case R_X86_64_DTPOFF32:
|
case R_X86_64_DTPOFF32:
|
||||||
case R_X86_64_TPOFF32:
|
|
||||||
case R_X86_64_DTPOFF64:
|
case R_X86_64_DTPOFF64:
|
||||||
case R_X86_64_TPOFF64:
|
|
||||||
case R_X86_64_REX_GOTPCRELX:
|
case R_X86_64_REX_GOTPCRELX:
|
||||||
case R_X86_64_PLT32:
|
case R_X86_64_PLT32:
|
||||||
case R_X86_64_PLTOFF64:
|
case R_X86_64_PLTOFF64:
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
return ALWAYS_GOTPLT_ENTRY;
|
||||||
|
|
||||||
|
case R_X86_64_TPOFF32:
|
||||||
|
case R_X86_64_TPOFF64:
|
||||||
|
return NO_GOTPLT_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -372,10 +374,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
sec = s1->sections[sym->st_shndx];
|
sec = s1->sections[sym->st_shndx];
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
|
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) {
|
||||||
|
addr_t tls_size = tls_end - tls_start;
|
||||||
|
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
|
||||||
|
x = val - (tls_start + aligned_size);
|
||||||
|
} else {
|
||||||
|
x = val - sec->sh_addr - sec->data_offset;
|
||||||
|
}
|
||||||
add32le(ptr, x);
|
add32le(ptr, x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -385,10 +407,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
sec = s1->sections[sym->st_shndx];
|
sec = s1->sections[sym->st_shndx];
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
|
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) {
|
||||||
|
addr_t tls_size = tls_end - tls_start;
|
||||||
|
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
|
||||||
|
x = val - (tls_start + aligned_size);
|
||||||
|
} else {
|
||||||
|
x = val - sec->sh_addr - sec->data_offset;
|
||||||
|
}
|
||||||
add64le(ptr, x);
|
add64le(ptr, x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user