[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Tinycc-devel] TLS/__thread support
From: |
Simon 'corecode' Schubert |
Subject: |
Re: [Tinycc-devel] TLS/__thread support |
Date: |
Mon, 27 Aug 2007 01:34:18 +0200 |
User-agent: |
Thunderbird 2.0.0.4 (X11/20070627) |
Hey,
Okay, here we go. It's a bit hackish, but not more than the rest of tinycc, so
I think that's okay. Currently only the i386 platform is supported and only
the Initial Exec and the Local Exec TLS models are supported.
I didn't change linking yet, because I have some other problems related to
debug sections right now. Binaries linked with gnu ld work as far as I can
tell.
cheers
simon
--
Serve - BSD +++ RENT this banner advert +++ ASCII Ribbon /"\
Work - Mac +++ space for low €€€ NOW!1 +++ Campaign \ /
Party Enjoy Relax | http://dragonflybsd.org Against HTML \
Dude 2c 2 the max ! http://golden-apple.biz Mail + News / \
# HG changeset patch
# User Simon 'corecode' Schubert <address@hidden>
# Date 1188165918 -7200
# Node ID abe9732b8349a02e6a17ba1b9fa270ff10b06089
# Parent 6cd310489cbb841e913d0470ffa48452a54a088e
Add __thread/tls handling.
diff -r 6cd310489cbb -r abe9732b8349 elf.h
--- a/elf.h Sun Aug 26 21:16:37 2007 +0200
+++ b/elf.h Mon Aug 27 00:05:18 2007 +0200
@@ -302,6 +302,7 @@ typedef struct
#define SHF_WRITE (1 << 0) /* Writable */
#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_TLS (1 << 10) /* Thread local storage */
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
/* Symbol table entry. */
@@ -392,6 +393,7 @@ typedef struct
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Symbol's name is file name */
#define STT_NUM 5 /* Number of defined types. */
+#define STT_TLS 6 /* Symbol is a TLS object. */
#define STT_LOOS 11 /* Start of OS-specific */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
@@ -907,8 +909,11 @@ typedef struct
#define R_386_RELATIVE 8 /* Adjust by program base */
#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_TLS_TPOFF 14 /* Negative offset in static
TLS block */
+#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve
static TLS */
+#define R_386_TLS_LE 17 /* Negative offset relative to static
TLS */
/* Keep this the last entry. */
-#define R_386_NUM 11
+#define R_386_NUM 18
/* SUN SPARC specific definitions. */
diff -r 6cd310489cbb -r abe9732b8349 i386/i386-gen.c
--- a/i386/i386-gen.c Sun Aug 26 21:16:37 2007 +0200
+++ b/i386/i386-gen.c Mon Aug 27 00:05:18 2007 +0200
@@ -155,19 +155,33 @@ static int oad(int c, int s)
/* output constant with relocation if 'r & VT_SYM' is true */
static void gen_addr32(int r, Sym *sym, int c)
{
- if (r & VT_SYM)
- greloc(cur_text_section, sym, ind, R_386_32);
+ if (r & VT_SYM) {
+ int reloc = R_386_32;
+
+ if (sym->type.t & VT_TLS) {
+ if (sym->type.t & VT_EXTERN)
+ reloc = R_386_TLS_IE;
+ else
+ reloc = R_386_TLS_LE;
+ }
+ greloc(cur_text_section, sym, ind, reloc);
+ }
gen_le32(c);
}
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
opcode bits */
-static void gen_modrm(int op_reg, int r, Sym *sym, int c)
+static void gen_modrm(int op_reg, int r, Sym *sym, int c, int disp_reg)
{
op_reg = op_reg << 3;
if ((r & VT_VALMASK) == VT_CONST) {
/* constant memory reference */
- o(0x05 | op_reg);
+ if (disp_reg != -1) {
+ /* displacement register */
+ o(0x80 | disp_reg | op_reg);
+ } else {
+ o(0x05 | op_reg);
+ }
gen_addr32(r, sym, c);
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
@@ -189,10 +203,29 @@ void load(int r, SValue *sv)
{
int v, t, ft, fc, fr;
SValue v1;
+ int tls = -1;
fr = sv->r;
ft = sv->type.t;
fc = sv->c.ul;
+
+ /* Thread local storage needs a load of the tls offset */
+ if ((fr & VT_SYM) && (sv->sym->type.t & VT_TLS)) {
+ switch (ft & VT_BTYPE) {
+ default:
+ /* simply use the dest as scratch */
+ tls = r;
+ break;
+ case VT_FLOAT:
+ case VT_DOUBLE:
+ case VT_LDOUBLE:
+ /* have to get a register to do address calc */
+ tls = get_reg(RC_INT);
+ break;
+ }
+ o(0x8b65); /* movl %gs:0x0, tls */
+ gen_modrm(tls, VT_CONST, NULL, 0, -1);
+ }
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
@@ -223,14 +256,19 @@ void load(int r, SValue *sv)
} else {
o(0x8b); /* movl */
}
- gen_modrm(r, fr, sv->sym, fc);
+ gen_modrm(r, fr, sv->sym, fc, tls);
} else {
if (v == VT_CONST) {
- o(0xb8 + r); /* mov $xx, r */
- gen_addr32(fr, sv->sym, fc);
+ if (tls == -1) {
+ o(0xb8 + r); /* mov $xx, r */
+ gen_addr32(fr, sv->sym, fc);
+ } else {
+ o(0x03); /* add xx, r */
+ gen_modrm(tls, fr, sv->sym, fc, -1);
+ }
} else if (v == VT_LOCAL) {
o(0x8d); /* lea xxx(%ebp), r */
- gen_modrm(r, VT_LOCAL, sv->sym, fc);
+ gen_modrm(r, VT_LOCAL, sv->sym, fc, -1);
} else if (v == VT_CMP) {
oad(0xb8 + r, 0); /* mov $0, r */
o(0x0f); /* setxx %br */
@@ -253,11 +291,19 @@ void store(int r, SValue *v)
void store(int r, SValue *v)
{
int fr, bt, ft, fc;
+ int tls = -1;
ft = v->type.t;
fc = v->c.ul;
fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE;
+
+ /* Thread local storage needs a load of the tls offset */
+ if ((v->r & VT_SYM) && (v->sym->type.t & VT_TLS)) {
+ tls = get_reg(RC_INT);
+ o(0x8b65);
+ gen_modrm(tls, VT_CONST, NULL, 0, -1);
+ }
/* XXX: incorrect if float reg to reg */
if (bt == VT_FLOAT) {
o(0xd9); /* fsts */
@@ -280,7 +326,7 @@ void store(int r, SValue *v)
if (fr == VT_CONST ||
fr == VT_LOCAL ||
(v->r & VT_LVAL)) {
- gen_modrm(r, v->r, v->sym, fc);
+ gen_modrm(r, v->r, v->sym, fc, tls);
} else if (fr != r) {
o(0xc0 + fr + r * 8); /* mov r, fr */
}
@@ -460,7 +506,7 @@ void gfunc_prolog(CType *func_type)
/* save FASTCALL register */
loc -= 4;
o(0x89); /* movl */
- gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
+ gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc, -1);
param_addr = loc;
} else {
param_addr = addr;
@@ -852,7 +898,7 @@ void gen_opf(int op)
o(0xdc);
else
o(0xd8);
- gen_modrm(a, r, vtop->sym, fc);
+ gen_modrm(a, r, vtop->sym, fc, -1);
}
vtop--;
}
diff -r 6cd310489cbb -r abe9732b8349 tcc.c
--- a/tcc.c Sun Aug 26 21:16:37 2007 +0200
+++ b/tcc.c Mon Aug 27 00:05:18 2007 +0200
@@ -63,6 +63,7 @@ static int unget_buffer_enabled;
static int unget_buffer_enabled;
static int parse_flags;
static Section *text_section, *data_section, *bss_section; /* predefined
sections */
+static Section *tdata_section, *tbss_section; /* thread local storage sections
*/
#ifdef CONFIG_TCC_ASM
static Section *last_text_section; /* to handle .previous asm directive */
#endif
@@ -416,6 +417,8 @@ static void put_extern_sym2(Sym *sym, Se
if (!sym->c) {
if ((sym->type.t & VT_BTYPE) == VT_FUNC)
sym_type = STT_FUNC;
+ else if (sym->type.t & VT_TLS)
+ sym_type = STT_TLS;
else
sym_type = STT_OBJECT;
if (sym->type.t & VT_STATIC)
@@ -5782,7 +5785,7 @@ static void struct_decl(CType *type, int
if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT)
expect("identifier");
if ((type1.t & VT_BTYPE) == VT_FUNC ||
- (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN |
VT_INLINE)))
+ (type1.t & VT_STORAGE))
error("invalid type for '%s'",
get_tok_str(v, NULL));
}
@@ -6027,6 +6030,10 @@ static int parse_btype(CType *type, Attr
t |= VT_INLINE;
next();
break;
+ case TOK_THREAD:
+ t |= VT_TLS;
+ next();
+ break;
/* GNUC attribute */
case TOK_ATTRIBUTE1:
@@ -8057,10 +8064,14 @@ static void decl_initializer_alloc(CType
/* allocate symbol in corresponding section */
sec = ad->section;
if (!sec) {
- if (has_init)
- sec = data_section;
- else if ((type->t & VT_STATIC) || tcc_state->nocommon)
- sec = bss_section;
+ if (type->t & VT_TLS) {
+ sec = has_init ? tdata_section : tbss_section;
+ } else {
+ if (has_init)
+ sec = data_section;
+ else if ((type->t & VT_STATIC) || tcc_state->nocommon)
+ sec = bss_section;
+ }
}
if (sec) {
data_offset = sec->data_offset;
@@ -8332,6 +8343,10 @@ static void decl(int l)
if (sym->c == FUNC_OLD)
func_decl_list(sym);
}
+
+ /* Functions can't have __thread storage */
+ if ((type.t & VT_FUNC) && (type.t & VT_TLS))
+ error("function declared __thread");
if (tok == '{') {
if (l == VT_LOCAL)
@@ -8442,7 +8457,8 @@ static void decl(int l)
extern */
external_sym(v, &type, r);
} else {
- type.t |= (btype.t & VT_STATIC); // Retain "static".
+ /* Retain "static" and "__thread". */
+ type.t |= (btype.t & (VT_STATIC|VT_TLS));
if (type.t & VT_STATIC)
r |= VT_CONST;
else
@@ -8907,6 +8923,10 @@ TCCState *tcc_new(void)
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC |
SHF_EXECINSTR);
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC |
SHF_WRITE);
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ tdata_section = new_section(s, ".tdata", SHT_PROGBITS, SHF_ALLOC |
SHF_WRITE |
+ SHF_TLS);
+ tbss_section = new_section(s, ".tbss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE |
+ SHF_TLS);
/* symbols are always generated for linking stage */
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
diff -r 6cd310489cbb -r abe9732b8349 tcc.h
--- a/tcc.h Sun Aug 26 21:16:37 2007 +0200
+++ b/tcc.h Mon Aug 27 00:05:18 2007 +0200
@@ -473,11 +473,12 @@ struct TCCState {
#define VT_STATIC 0x00000100 /* static variable */
#define VT_TYPEDEF 0x00000200 /* typedef definition */
#define VT_INLINE 0x00000400 /* inline definition */
+#define VT_TLS 0x00004000 /* thread local storage definition */
#define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */
/* type mask (except storage) */
-#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
+#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_TLS)
#define VT_TYPE (~(VT_STORAGE))
/* token values */
diff -r 6cd310489cbb -r abe9732b8349 tcctok.h
--- a/tcctok.h Sun Aug 26 21:16:37 2007 +0200
+++ b/tcctok.h Mon Aug 27 00:05:18 2007 +0200
@@ -32,6 +32,7 @@
DEF(TOK_INLINE1, "inline")
DEF(TOK_INLINE2, "__inline") /* gcc keyword */
DEF(TOK_INLINE3, "__inline__") /* gcc keyword */
+ DEF(TOK_THREAD, "__thread") /* gcc keyword */
DEF(TOK_RESTRICT1, "restrict")
DEF(TOK_RESTRICT2, "__restrict")
DEF(TOK_RESTRICT3, "__restrict__")
# HG changeset patch
# User Simon 'corecode' Schubert <address@hidden>
# Date 1188168025 -7200
# Node ID d4b10d0be5c3323ac00e089e3107d78ec8214017
# Parent abe9732b8349a02e6a17ba1b9fa270ff10b06089
Generate correct code for VT_EXTERN and local thread symbols.
diff -r abe9732b8349 -r d4b10d0be5c3 i386/i386-gen.c
--- a/i386/i386-gen.c Mon Aug 27 00:05:18 2007 +0200
+++ b/i386/i386-gen.c Mon Aug 27 00:40:25 2007 +0200
@@ -204,6 +204,7 @@ void load(int r, SValue *sv)
int v, t, ft, fc, fr;
SValue v1;
int tls = -1;
+ int ext = 0;
fr = sv->r;
ft = sv->type.t;
@@ -211,20 +212,22 @@ void load(int r, SValue *sv)
/* Thread local storage needs a load of the tls offset */
if ((fr & VT_SYM) && (sv->sym->type.t & VT_TLS)) {
- switch (ft & VT_BTYPE) {
- default:
- /* simply use the dest as scratch */
- tls = r;
- break;
- case VT_FLOAT:
- case VT_DOUBLE:
- case VT_LDOUBLE:
- /* have to get a register to do address calc */
- tls = get_reg(RC_INT);
- break;
+ /* simply use the dest as scratch */
+ tls = r;
+ if (fr & VT_LVAL) {
+ switch (ft & VT_BTYPE) {
+ case VT_FLOAT:
+ case VT_DOUBLE:
+ case VT_LDOUBLE:
+ /* have to get a register to do address calc */
+ tls = get_reg(RC_INT);
+ break;
+ }
}
o(0x8b65); /* movl %gs:0x0, tls */
gen_modrm(tls, VT_CONST, NULL, 0, -1);
+ if (sv->sym->type.t & VT_EXTERN)
+ ext = 1;
}
v = fr & VT_VALMASK;
@@ -235,6 +238,13 @@ void load(int r, SValue *sv)
v1.c.ul = fc;
load(r, &v1);
fr = r;
+ }
+ if (ext) {
+ /* calculate offset */
+ o(0x03); /* add xx, tls */
+ gen_modrm(tls, VT_SYM|VT_CONST, sv->sym, fc, -1);
+ fr = VT_CONST;
+ fc = 0;
}
if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0xd9); /* flds */
@@ -263,8 +273,13 @@ void load(int r, SValue *sv)
o(0xb8 + r); /* mov $xx, r */
gen_addr32(fr, sv->sym, fc);
} else {
- o(0x03); /* add xx, r */
- gen_modrm(tls, fr, sv->sym, fc, -1);
+ if (ext) {
+ o(0x03); /* add xx, r */
+ gen_modrm(r, fr, sv->sym, fc, -1);
+ } else {
+ o(0x8d); /* lea xx, r */
+ gen_modrm(r, fr, sv->sym, fc, r);
+ }
}
} else if (v == VT_LOCAL) {
o(0x8d); /* lea xxx(%ebp), r */
# HG changeset patch
# User Simon 'corecode' Schubert <address@hidden>
# Date 1188168693 -7200
# Node ID 34b0f3475dcecb6392e8fabc406814d1728b8a84
# Parent d4b10d0be5c3323ac00e089e3107d78ec8214017
Produce correct code for VT_EXTERN stores.
diff -r d4b10d0be5c3 -r 34b0f3475dce i386/i386-gen.c
--- a/i386/i386-gen.c Mon Aug 27 00:40:25 2007 +0200
+++ b/i386/i386-gen.c Mon Aug 27 00:51:33 2007 +0200
@@ -243,6 +243,7 @@ void load(int r, SValue *sv)
/* calculate offset */
o(0x03); /* add xx, tls */
gen_modrm(tls, VT_SYM|VT_CONST, sv->sym, fc, -1);
+ /* XXXTLS get rid of the superfluous displacement */
fr = VT_CONST;
fc = 0;
}
@@ -305,19 +306,28 @@ void load(int r, SValue *sv)
/* store register 'r' in lvalue 'v' */
void store(int r, SValue *v)
{
- int fr, bt, ft, fc;
+ int fr, bt, ft, fc, vr;
int tls = -1;
ft = v->type.t;
fc = v->c.ul;
fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE;
+ vr = v->r;
/* Thread local storage needs a load of the tls offset */
if ((v->r & VT_SYM) && (v->sym->type.t & VT_TLS)) {
tls = get_reg(RC_INT);
o(0x8b65);
gen_modrm(tls, VT_CONST, NULL, 0, -1);
+ if (v->sym->type.t & VT_EXTERN) {
+ /* calculate offset */
+ o(0x03); /* add xx, tls */
+ gen_modrm(tls, VT_SYM|VT_CONST, v->sym, fc, -1);
+ /* XXXTLS get rid of the superfluous displacement */
+ vr = VT_CONST;
+ fc = 0;
+ }
}
/* XXX: incorrect if float reg to reg */
if (bt == VT_FLOAT) {
@@ -341,7 +351,7 @@ void store(int r, SValue *v)
if (fr == VT_CONST ||
fr == VT_LOCAL ||
(v->r & VT_LVAL)) {
- gen_modrm(r, v->r, v->sym, fc, tls);
+ gen_modrm(r, vr, v->sym, fc, tls);
} else if (fr != r) {
o(0xc0 + fr + r * 8); /* mov r, fr */
}