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 += 127_asm_goto.test # hardcodes x86 asm
|
||||
endif
|
||||
ifeq (,$(filter x86_64,$(ARCH)))
|
||||
SKIP += 144_tls.test # TLS only implemented on x86_64 so far
|
||||
endif
|
||||
ifeq ($(CONFIG_backtrace),no)
|
||||
SKIP += 113_btdll.test
|
||||
CONFIG_bcheck = no
|
||||
@ -107,6 +110,10 @@ GEN-ALWAYS =
|
||||
# constructor/destructor
|
||||
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 113_btdll.test 126_bound_global.test: FILTER += \
|
||||
-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
|
||||
/* we use indirect access via got */
|
||||
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 */
|
||||
int tr = r | TREG_MEM;
|
||||
if (is_float(ft)) {
|
||||
@ -385,6 +386,19 @@ void load(int r, SValue *sv)
|
||||
v = fr & VT_VALMASK;
|
||||
if (fr & VT_LVAL) {
|
||||
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) {
|
||||
v1.type.t = VT_PTR;
|
||||
v1.r = VT_LOCAL | VT_LVAL;
|
||||
@ -572,6 +586,20 @@ void store(int r, SValue *v)
|
||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||
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
|
||||
/* we need to access the variable via got */
|
||||
if (fr == VT_CONST
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#define R_NUM R_X86_64_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x400000
|
||||
#define ELF_PAGE_SIZE 0x200000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_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_TLSLD:
|
||||
case R_X86_64_DTPOFF32:
|
||||
case R_X86_64_TPOFF32:
|
||||
case R_X86_64_DTPOFF64:
|
||||
case R_X86_64_TPOFF64:
|
||||
case R_X86_64_REX_GOTPCRELX:
|
||||
case R_X86_64_PLT32:
|
||||
case R_X86_64_PLTOFF64:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
|
||||
case R_X86_64_TPOFF32:
|
||||
case R_X86_64_TPOFF64:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -372,10 +374,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
ElfW(Sym) *sym;
|
||||
Section *sec;
|
||||
int32_t x;
|
||||
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||
int i;
|
||||
|
||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
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);
|
||||
}
|
||||
break;
|
||||
@ -385,10 +407,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
ElfW(Sym) *sym;
|
||||
Section *sec;
|
||||
int32_t x;
|
||||
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||
int i;
|
||||
|
||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user