Add constructor/destructor support

This commit is contained in:
herman ten brugge 2019-10-29 07:02:58 +01:00
parent c4c5ea4381
commit 800c3a5e0b
7 changed files with 112 additions and 8 deletions

7
tcc.h
View File

@ -468,7 +468,9 @@ struct SymAttr {
dllexport : 1, dllexport : 1,
nodecorate : 1, nodecorate : 1,
dllimport : 1, dllimport : 1,
unused : 4; constructor : 1,
destructor : 1,
unused : 2;
}; };
/* function attributes or temporary attributes for parsing */ /* function attributes or temporary attributes for parsing */
@ -1443,6 +1445,9 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
#endif #endif
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
ST_FUNC void add_init_array (TCCState *s1, Sym *sym);
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym);
ST_FUNC int put_elf_str(Section *s, const char *sym); ST_FUNC int put_elf_str(Section *s, const char *sym);
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);

View File

@ -339,9 +339,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size)
sec->data_offset = size; sec->data_offset = size;
} }
/* return a reference to a section, and create it if it does not static Section *find_section_create (TCCState *s1, const char *name, int create)
exists */
ST_FUNC Section *find_section(TCCState *s1, const char *name)
{ {
Section *sec; Section *sec;
int i; int i;
@ -351,7 +349,14 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name)
return sec; return sec;
} }
/* sections are created as PROGBITS */ /* sections are created as PROGBITS */
return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL;
}
/* return a reference to a section, and create it if it does not
exists */
ST_FUNC Section *find_section(TCCState *s1, const char *name)
{
return find_section_create (s1, name, 1);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -1436,6 +1441,30 @@ static int tcc_add_support(TCCState *s1, const char *filename)
} }
#endif #endif
static void add_array (const char *section, TCCState *s1, Sym *sym)
{
Section *s;
unsigned char *ptr;
s = find_section(s1, section);
if (s) {
s->sh_flags |= SHF_WRITE;
ptr = section_ptr_add(s, PTR_SIZE);
memset (ptr, 0, PTR_SIZE);
put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
}
}
ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
{
add_array (".init_array", s1, sym);
}
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
{
add_array (".fini_array", s1, sym);
}
ST_FUNC void tcc_add_bcheck(TCCState *s1) ST_FUNC void tcc_add_bcheck(TCCState *s1)
{ {
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
@ -2081,6 +2110,7 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
{ {
Section *dynamic = dyninf->dynamic; Section *dynamic = dyninf->dynamic;
Section *s;
/* put dynamic section entries */ /* put dynamic section entries */
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
@ -2109,6 +2139,29 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
s = find_section_create (s1, ".preinit_array", 0);
if (s && s->data_offset) {
put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr);
put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset);
}
s = find_section_create (s1, ".init_array", 0);
if (s && s->data_offset) {
put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr);
put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset);
}
s = find_section_create (s1, ".fini_array", 0);
if (s && s->data_offset) {
put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr);
put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset);
}
s = find_section_create (s1, ".init", 0);
if (s && s->data_offset) {
put_dt(dynamic, DT_INIT, s->sh_addr);
}
s = find_section_create (s1, ".fini", 0);
if (s && s->data_offset) {
put_dt(dynamic, DT_FINI, s->sh_addr);
}
if (s1->do_debug) if (s1->do_debug)
put_dt(dynamic, DT_DEBUG, 0); put_dt(dynamic, DT_DEBUG, 0);
put_dt(dynamic, DT_NULL, 0); put_dt(dynamic, DT_NULL, 0);

View File

@ -3578,6 +3578,14 @@ redo:
skip(')'); skip(')');
break; break;
} }
case TOK_CONSTRUCTOR1:
case TOK_CONSTRUCTOR2:
ad->a.constructor = 1;
break;
case TOK_DESTRUCTOR1:
case TOK_DESTRUCTOR2:
ad->a.destructor = 1;
break;
case TOK_SECTION1: case TOK_SECTION1:
case TOK_SECTION2: case TOK_SECTION2:
skip('('); skip('(');
@ -7560,7 +7568,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* parse a function defined by symbol 'sym' and generate its code in /* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */ 'cur_text_section' */
static void gen_function(Sym *sym) static void gen_function(Sym *sym, AttributeDef *ad)
{ {
/* Initialize VLA state */ /* Initialize VLA state */
struct scope f = { 0 }; struct scope f = { 0 };
@ -7576,6 +7584,13 @@ static void gen_function(Sym *sym)
/* NOTE: we patch the symbol size later */ /* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0); put_extern_sym(sym, cur_text_section, ind, 0);
if (ad && ad->a.constructor) {
add_init_array (tcc_state, sym);
}
if (ad && ad->a.destructor) {
add_fini_array (tcc_state, sym);
}
funcname = get_tok_str(sym->v, NULL); funcname = get_tok_str(sym->v, NULL);
func_ind = ind; func_ind = ind;
@ -7634,7 +7649,7 @@ static void gen_inline_functions(TCCState *s)
begin_macro(fn->func_str, 1); begin_macro(fn->func_str, 1);
next(); next();
cur_text_section = text_section; cur_text_section = text_section;
gen_function(sym); gen_function(sym, NULL);
end_macro(); end_macro();
inline_generated = 1; inline_generated = 1;
@ -7814,7 +7829,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
cur_text_section = ad.section; cur_text_section = ad.section;
if (!cur_text_section) if (!cur_text_section)
cur_text_section = text_section; cur_text_section = text_section;
gen_function(sym); gen_function(sym, &ad);
} }
break; break;
} else { } else {

View File

@ -127,6 +127,10 @@
DEF(TOK_REGPARM2, "__regparm__") DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_CLEANUP1, "cleanup") DEF(TOK_CLEANUP1, "cleanup")
DEF(TOK_CLEANUP2, "__cleanup__") DEF(TOK_CLEANUP2, "__cleanup__")
DEF(TOK_CONSTRUCTOR1, "constructor")
DEF(TOK_CONSTRUCTOR2, "__constructor__")
DEF(TOK_DESTRUCTOR1, "destructor")
DEF(TOK_DESTRUCTOR2, "__destructor__")
DEF(TOK_MODE, "__mode__") DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__") DEF(TOK_MODE_QI, "__QI__")

View File

@ -0,0 +1,20 @@
extern int write (int fd, void *buf, int len);
static void __attribute__ ((constructor))
testc (void)
{
write (1, "constructor\n", 12);
}
static void __attribute__ ((destructor))
testd (void)
{
write (1, "destructor\n", 11);
}
int
main (void)
{
write (1, "main\n", 5);
return 0;
}

View File

@ -0,0 +1,3 @@
constructor
main
destructor

View File

@ -33,6 +33,7 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
endif endif
ifneq (-$(CONFIG_WIN32)$(CONFIG_WIN64)-,--) ifneq (-$(CONFIG_WIN32)$(CONFIG_WIN64)-,--)
SKIP += 106_pthread.test # No pthread support SKIP += 106_pthread.test # No pthread support
SKIP += 108_constructor.test # No contructor/destructor support
endif endif
# Some tests might need arguments # Some tests might need arguments
@ -67,6 +68,9 @@ GEN-ALWAYS =
106_pthread.test: FLAGS += -pthread 106_pthread.test: FLAGS += -pthread
106_pthread.test: NORUN = true 106_pthread.test: NORUN = true
# constructor/destructor
108_constructor.test: NORUN = true
# Filter source directory in warnings/errors (out-of-tree builds) # Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed 's,$(SRC)/,,g' FILTER = 2>&1 | sed 's,$(SRC)/,,g'
# Filter some always-warning # Filter some always-warning