From 800c3a5e0be06354f4bf232c91c58d97c9145143 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Tue, 29 Oct 2019 07:02:58 +0100 Subject: [PATCH] Add constructor/destructor support --- tcc.h | 7 +++- tccelf.c | 61 +++++++++++++++++++++++++++-- tccgen.c | 21 ++++++++-- tcctok.h | 4 ++ tests/tests2/108_constructor.c | 20 ++++++++++ tests/tests2/108_constructor.expect | 3 ++ tests/tests2/Makefile | 4 ++ 7 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 tests/tests2/108_constructor.c create mode 100644 tests/tests2/108_constructor.expect diff --git a/tcc.h b/tcc.h index c48b45b..6c70f33 100644 --- a/tcc.h +++ b/tcc.h @@ -468,7 +468,9 @@ struct SymAttr { dllexport : 1, nodecorate : 1, dllimport : 1, - unused : 4; + constructor : 1, + destructor : 1, + unused : 2; }; /* 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 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_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); diff --git a/tccelf.c b/tccelf.c index 213ef9c..8644005 100644 --- a/tccelf.c +++ b/tccelf.c @@ -339,9 +339,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size) sec->data_offset = size; } -/* return a reference to a section, and create it if it does not - exists */ -ST_FUNC Section *find_section(TCCState *s1, const char *name) +static Section *find_section_create (TCCState *s1, const char *name, int create) { Section *sec; int i; @@ -351,7 +349,14 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name) return sec; } /* 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 +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) { #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) { Section *dynamic = dyninf->dynamic; + Section *s; /* put dynamic section entries */ 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_VERNEEDNUM, dt_verneednum); 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) put_dt(dynamic, DT_DEBUG, 0); put_dt(dynamic, DT_NULL, 0); diff --git a/tccgen.c b/tccgen.c index 5b56b74..a6181b0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3578,6 +3578,14 @@ redo: skip(')'); 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_SECTION2: 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 'cur_text_section' */ -static void gen_function(Sym *sym) +static void gen_function(Sym *sym, AttributeDef *ad) { /* Initialize VLA state */ struct scope f = { 0 }; @@ -7576,6 +7584,13 @@ static void gen_function(Sym *sym) /* NOTE: we patch the symbol size later */ 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); func_ind = ind; @@ -7634,7 +7649,7 @@ static void gen_inline_functions(TCCState *s) begin_macro(fn->func_str, 1); next(); cur_text_section = text_section; - gen_function(sym); + gen_function(sym, NULL); end_macro(); 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; if (!cur_text_section) cur_text_section = text_section; - gen_function(sym); + gen_function(sym, &ad); } break; } else { diff --git a/tcctok.h b/tcctok.h index 7be0d4f..98683e1 100644 --- a/tcctok.h +++ b/tcctok.h @@ -127,6 +127,10 @@ DEF(TOK_REGPARM2, "__regparm__") DEF(TOK_CLEANUP1, "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_QI, "__QI__") diff --git a/tests/tests2/108_constructor.c b/tests/tests2/108_constructor.c new file mode 100644 index 0000000..145d0da --- /dev/null +++ b/tests/tests2/108_constructor.c @@ -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; +} diff --git a/tests/tests2/108_constructor.expect b/tests/tests2/108_constructor.expect new file mode 100644 index 0000000..167ca51 --- /dev/null +++ b/tests/tests2/108_constructor.expect @@ -0,0 +1,3 @@ +constructor +main +destructor diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index a452d84..e7f2ecb 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -33,6 +33,7 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) endif ifneq (-$(CONFIG_WIN32)$(CONFIG_WIN64)-,--) SKIP += 106_pthread.test # No pthread support + SKIP += 108_constructor.test # No contructor/destructor support endif # Some tests might need arguments @@ -67,6 +68,9 @@ GEN-ALWAYS = 106_pthread.test: FLAGS += -pthread 106_pthread.test: NORUN = true +# constructor/destructor +108_constructor.test: NORUN = true + # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed 's,$(SRC)/,,g' # Filter some always-warning