From 1c4afd13501f07a673aed5f130166f2ee0f30927 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Tue, 29 Oct 2013 22:10:02 +0800 Subject: [PATCH] Add support for thread-local storage variables --- elf.h | 4 +++- libtcc.c | 5 ++++- tccelf.c | 29 +++++++++++++++++++++-------- tccgen.c | 29 +++++++++++++++++++++++++---- tcctok.h | 1 + 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/elf.h b/elf.h index 2983c757..039a697c 100644 --- a/elf.h +++ b/elf.h @@ -447,6 +447,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 thread-local data object */ #define STT_GNU_IFUNC 10 /* Symbol is a indirect code object */ #define STT_LOOS 11 /* Start of OS-specific */ #define STT_HIOS 12 /* End of OS-specific */ @@ -555,7 +556,8 @@ typedef struct #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ -#define PT_NUM 7 /* Number of defined types. */ +#define PT_TLS 7 /* Thread-local program segment */ +#define PT_NUM 8 /* Number of defined types. */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ diff --git a/libtcc.c b/libtcc.c index f841eb03..fbea50bd 100644 --- a/libtcc.c +++ b/libtcc.c @@ -444,7 +444,10 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, } else if ((sym->type.t & VT_BTYPE) == VT_VOID) { sym_type = STT_NOTYPE; } else { - sym_type = STT_OBJECT; + if (section && section->sh_flags & SHF_TLS) + sym_type = STT_TLS; + else + sym_type = STT_OBJECT; } if (sym->type.t & VT_STATIC) diff --git a/tccelf.c b/tccelf.c index 8af4bb63..4602ce8c 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1543,6 +1543,7 @@ static int elf_output_file(TCCState *s1, const char *filename) int fd, mode, ret; int *section_order; int shnum, i, phnum, file_offset, offset, size, j, sh_order_index, k; + int have_tls_section = 0; long long tmp; addr_t addr; Section *strsec, *s; @@ -1861,6 +1862,11 @@ static int elf_output_file(TCCState *s1, const char *filename) /* we output all sections if debug or object file */ s->sh_size = s->data_offset; } + /* if tls section we'll need to add one segment */ + if (s->sh_flags & SHF_TLS) { + have_tls_section = 1; + phnum++; + } } /* allocate program segment headers */ @@ -1904,12 +1910,16 @@ static int elf_output_file(TCCState *s1, const char *filename) if (interp) ph += 1 + HAVE_PHDR; - for(j = 0; j < 2; j++) { - ph->p_type = PT_LOAD; - if (j == 0) - ph->p_flags = PF_R | PF_X; + for(j = 0; j < 2 + have_tls_section; j++) { + if (j != 2) + ph->p_type = PT_LOAD; else - ph->p_flags = PF_R | PF_W; + ph->p_type = PT_TLS; + ph->p_flags = PF_R; + if (j == 0) + ph->p_flags |= PF_X; + else if (j == 1) + ph->p_flags |= PF_W; ph->p_align = s1->section_align; /* we do the following ordering: interp, symbol tables, @@ -1920,13 +1930,16 @@ static int elf_output_file(TCCState *s1, const char *filename) s = s1->sections[i]; /* compute if section should be included */ if (j == 0) { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != SHF_ALLOC) continue; - } else { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + } else if (j == 1) { + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != (SHF_ALLOC | SHF_WRITE)) continue; + } else { + if ((s->sh_flags & SHF_TLS) != SHF_TLS) + continue; } if (s == interp) { if (k != 0) diff --git a/tccgen.c b/tccgen.c index bab4f7c5..bfe461f5 100644 --- a/tccgen.c +++ b/tccgen.c @@ -31,6 +31,7 @@ ST_DATA int rsym, anon_sym, ind, loc; ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ +ST_DATA Section *tdata_section, *tbss_section; /* thread-local storage sections */ ST_DATA Section *cur_text_section; /* current section where function code is generated */ #ifdef CONFIG_TCC_ASM ST_DATA Section *last_text_section; /* to handle .previous asm directive */ @@ -3092,6 +3093,10 @@ static int parse_btype(CType *type, AttributeDef *ad) t |= VT_INLINE; next(); break; + case TOK_THREAD: + t |= VT_TLS; + next(); + break; /* GNUC attribute */ case TOK_ATTRIBUTE1: @@ -5495,10 +5500,26 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, /* allocate symbol in corresponding section */ sec = ad->section; if (!sec) { - if (has_init) - sec = data_section; - else if (tcc_state->nocommon) - sec = bss_section; + if (has_init) { + if (type->t & VT_TLS) { + if (!tdata_section) + tdata_section = new_section(tcc_state, ".tdata", + SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE | SHF_TLS); + sec = tdata_section; + } else + sec = data_section; + } + else if (tcc_state->nocommon) { + if (type->t & VT_TLS) { + if (!tbss_section) + tbss_section = new_section(tcc_state, ".tbss", + SHT_NOBITS, + SHF_ALLOC | SHF_WRITE | SHF_TLS); + sec = tbss_section; + } else + sec = bss_section; + } } if (sec) { data_offset = sec->data_offset; diff --git a/tcctok.h b/tcctok.h index 9b47a601..d55c9d78 100644 --- a/tcctok.h +++ b/tcctok.h @@ -10,6 +10,7 @@ DEF(TOK_FOR, "for") DEF(TOK_EXTERN, "extern") DEF(TOK_STATIC, "static") + DEF(TOK_THREAD, "__thread") DEF(TOK_UNSIGNED, "unsigned") DEF(TOK_GOTO, "goto") DEF(TOK_DO, "do") -- 2.11.4.GIT