Unified · Split
| @@ -468,7 +468,9 @@ struct SymAttr { · 467 unmodified lines | ||
| 468 | 468 | dllexport : 1, |
| 469 | 469 | nodecorate : 1, |
| 470 | 470 | dllimport : 1, |
| 471 | − unused : 4; | |
| 471 | + constructor : 1, | |
| 472 | + destructor : 1, | |
| 473 | + unused : 2; | |
| 472 | 474 | }; |
| 473 | 475 | |
| 474 | 476 | /* function attributes or temporary attributes for parsing */ |
| @@ -1443,6 +1445,9 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type); · 968 unmodified lines | ||
| 1443 | 1445 | #endif |
| 1444 | 1446 | ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); |
| 1445 | 1447 | |
| 1448 | +ST_FUNC void add_init_array (TCCState *s1, Sym *sym); | |
| 1449 | +ST_FUNC void add_fini_array (TCCState *s1, Sym *sym); | |
| 1450 | + | |
| 1446 | 1451 | ST_FUNC int put_elf_str(Section *s, const char *sym); |
| 1447 | 1452 | ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); |
| 1448 | 1453 | ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); |
| @@ -339,9 +339,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size) · 338 unmodified lines | ||
| 339 | 339 | sec->data_offset = size; |
| 340 | 340 | } |
| 341 | 341 | |
| 342 | −/* return a reference to a section, and create it if it does not | |
| 343 | − exists */ | |
| 344 | −ST_FUNC Section *find_section(TCCState *s1, const char *name) | |
| 342 | +static Section *find_section_create (TCCState *s1, const char *name, int create) | |
| 345 | 343 | { |
| 346 | 344 | Section *sec; |
| 347 | 345 | int i; |
| @@ -351,7 +349,14 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name) · 3 unmodified lines | ||
| 351 | 349 | return sec; |
| 352 | 350 | } |
| 353 | 351 | /* sections are created as PROGBITS */ |
| 354 | − return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); | |
| 352 | + return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL; | |
| 353 | +} | |
| 354 | + | |
| 355 | +/* return a reference to a section, and create it if it does not | |
| 356 | + exists */ | |
| 357 | +ST_FUNC Section *find_section(TCCState *s1, const char *name) | |
| 358 | +{ | |
| 359 | + return find_section_create (s1, name, 1); | |
| 355 | 360 | } |
| 356 | 361 | |
| 357 | 362 | /* ------------------------------------------------------------------------- */ |
| @@ -1436,6 +1441,30 @@ static int tcc_add_support(TCCState *s1, const char *filename) · 1078 unmodified lines | ||
| 1436 | 1441 | } |
| 1437 | 1442 | #endif |
| 1438 | 1443 | |
| 1444 | +static void add_array (const char *section, TCCState *s1, Sym *sym) | |
| 1445 | +{ | |
| 1446 | + Section *s; | |
| 1447 | + unsigned char *ptr; | |
| 1448 | + | |
| 1449 | + s = find_section(s1, section); | |
| 1450 | + if (s) { | |
| 1451 | + s->sh_flags |= SHF_WRITE; | |
| 1452 | + ptr = section_ptr_add(s, PTR_SIZE); | |
| 1453 | + memset (ptr, 0, PTR_SIZE); | |
| 1454 | + put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c); | |
| 1455 | + } | |
| 1456 | +} | |
| 1457 | + | |
| 1458 | +ST_FUNC void add_init_array (TCCState *s1, Sym *sym) | |
| 1459 | +{ | |
| 1460 | + add_array (".init_array", s1, sym); | |
| 1461 | +} | |
| 1462 | + | |
| 1463 | +ST_FUNC void add_fini_array (TCCState *s1, Sym *sym) | |
| 1464 | +{ | |
| 1465 | + add_array (".fini_array", s1, sym); | |
| 1466 | +} | |
| 1467 | + | |
| 1439 | 1468 | ST_FUNC void tcc_add_bcheck(TCCState *s1) |
| 1440 | 1469 | { |
| 1441 | 1470 | #ifdef CONFIG_TCC_BCHECK |
| @@ -2081,6 +2110,7 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, · 639 unmodified lines | ||
| 2081 | 2110 | static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) |
| 2082 | 2111 | { |
| 2083 | 2112 | Section *dynamic = dyninf->dynamic; |
| 2113 | + Section *s; | |
| 2084 | 2114 | |
| 2085 | 2115 | /* put dynamic section entries */ |
| 2086 | 2116 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
| @@ -2109,6 +2139,29 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 22 unmodified lines | ||
| 2109 | 2139 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); |
| 2110 | 2140 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); |
| 2111 | 2141 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); |
| 2142 | + s = find_section_create (s1, ".preinit_array", 0); | |
| 2143 | + if (s && s->data_offset) { | |
| 2144 | + put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); | |
| 2145 | + put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); | |
| 2146 | + } | |
| 2147 | + s = find_section_create (s1, ".init_array", 0); | |
| 2148 | + if (s && s->data_offset) { | |
| 2149 | + put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); | |
| 2150 | + put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); | |
| 2151 | + } | |
| 2152 | + s = find_section_create (s1, ".fini_array", 0); | |
| 2153 | + if (s && s->data_offset) { | |
| 2154 | + put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); | |
| 2155 | + put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); | |
| 2156 | + } | |
| 2157 | + s = find_section_create (s1, ".init", 0); | |
| 2158 | + if (s && s->data_offset) { | |
| 2159 | + put_dt(dynamic, DT_INIT, s->sh_addr); | |
| 2160 | + } | |
| 2161 | + s = find_section_create (s1, ".fini", 0); | |
| 2162 | + if (s && s->data_offset) { | |
| 2163 | + put_dt(dynamic, DT_FINI, s->sh_addr); | |
| 2164 | + } | |
| 2112 | 2165 | if (s1->do_debug) |
| 2113 | 2166 | put_dt(dynamic, DT_DEBUG, 0); |
| 2114 | 2167 | put_dt(dynamic, DT_NULL, 0); |
| @@ -3578,6 +3578,14 @@ redo: · 3577 unmodified lines | ||
| 3578 | 3578 | skip(')'); |
| 3579 | 3579 | break; |
| 3580 | 3580 | } |
| 3581 | + case TOK_CONSTRUCTOR1: | |
| 3582 | + case TOK_CONSTRUCTOR2: | |
| 3583 | + ad->a.constructor = 1; | |
| 3584 | + break; | |
| 3585 | + case TOK_DESTRUCTOR1: | |
| 3586 | + case TOK_DESTRUCTOR2: | |
| 3587 | + ad->a.destructor = 1; | |
| 3588 | + break; | |
| 3581 | 3589 | case TOK_SECTION1: |
| 3582 | 3590 | case TOK_SECTION2: |
| 3583 | 3591 | skip('('); |
| @@ -7560,7 +7568,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 3976 unmodified lines | ||
| 7560 | 7568 | |
| 7561 | 7569 | /* parse a function defined by symbol 'sym' and generate its code in |
| 7562 | 7570 | 'cur_text_section' */ |
| 7563 | −static void gen_function(Sym *sym) | |
| 7571 | +static void gen_function(Sym *sym, AttributeDef *ad) | |
| 7564 | 7572 | { |
| 7565 | 7573 | /* Initialize VLA state */ |
| 7566 | 7574 | struct scope f = { 0 }; |
| @@ -7576,6 +7584,13 @@ static void gen_function(Sym *sym) · 9 unmodified lines | ||
| 7576 | 7584 | /* NOTE: we patch the symbol size later */ |
| 7577 | 7585 | put_extern_sym(sym, cur_text_section, ind, 0); |
| 7578 | 7586 | |
| 7587 | + if (ad && ad->a.constructor) { | |
| 7588 | + add_init_array (tcc_state, sym); | |
| 7589 | + } | |
| 7590 | + if (ad && ad->a.destructor) { | |
| 7591 | + add_fini_array (tcc_state, sym); | |
| 7592 | + } | |
| 7593 | + | |
| 7579 | 7594 | funcname = get_tok_str(sym->v, NULL); |
| 7580 | 7595 | func_ind = ind; |
| 7581 | 7596 | |
| @@ -7634,7 +7649,7 @@ static void gen_inline_functions(TCCState *s) · 52 unmodified lines | ||
| 7634 | 7649 | begin_macro(fn->func_str, 1); |
| 7635 | 7650 | next(); |
| 7636 | 7651 | cur_text_section = text_section; |
| 7637 | − gen_function(sym); | |
| 7652 | + gen_function(sym, NULL); | |
| 7638 | 7653 | end_macro(); |
| 7639 | 7654 | |
| 7640 | 7655 | inline_generated = 1; |
| @@ -7814,7 +7829,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 173 unmodified lines | ||
| 7814 | 7829 | cur_text_section = ad.section; |
| 7815 | 7830 | if (!cur_text_section) |
| 7816 | 7831 | cur_text_section = text_section; |
| 7817 | − gen_function(sym); | |
| 7832 | + gen_function(sym, &ad); | |
| 7818 | 7833 | } |
| 7819 | 7834 | break; |
| 7820 | 7835 | } else { |
| @@ -127,6 +127,10 @@ · 126 unmodified lines | ||
| 127 | 127 | DEF(TOK_REGPARM2, "__regparm__") |
| 128 | 128 | DEF(TOK_CLEANUP1, "cleanup") |
| 129 | 129 | DEF(TOK_CLEANUP2, "__cleanup__") |
| 130 | + DEF(TOK_CONSTRUCTOR1, "constructor") | |
| 131 | + DEF(TOK_CONSTRUCTOR2, "__constructor__") | |
| 132 | + DEF(TOK_DESTRUCTOR1, "destructor") | |
| 133 | + DEF(TOK_DESTRUCTOR2, "__destructor__") | |
| 130 | 134 | |
| 131 | 135 | DEF(TOK_MODE, "__mode__") |
| 132 | 136 | DEF(TOK_MODE_QI, "__QI__") |
| @@ -0,0 +1,20 @@ | ||
| 1 | +extern int write (int fd, void *buf, int len); | |
| 2 | + | |
| 3 | +static void __attribute__ ((constructor)) | |
| 4 | +testc (void) | |
| 5 | +{ | |
| 6 | + write (1, "constructor\n", 12); | |
| 7 | +} | |
| 8 | + | |
| 9 | +static void __attribute__ ((destructor)) | |
| 10 | +testd (void) | |
| 11 | +{ | |
| 12 | + write (1, "destructor\n", 11); | |
| 13 | +} | |
| 14 | + | |
| 15 | +int | |
| 16 | +main (void) | |
| 17 | +{ | |
| 18 | + write (1, "main\n", 5); | |
| 19 | + return 0; | |
| 20 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +constructor | |
| 2 | +main | |
| 3 | +destructor | |
| @@ -33,6 +33,7 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) · 32 unmodified lines | ||
| 33 | 33 | endif |
| 34 | 34 | ifneq (-$(CONFIG_WIN32)$(CONFIG_WIN64)-,--) |
| 35 | 35 | SKIP += 106_pthread.test # No pthread support |
| 36 | + SKIP += 108_constructor.test # No contructor/destructor support | |
| 36 | 37 | endif |
| 37 | 38 | |
| 38 | 39 | # Some tests might need arguments |
| @@ -67,6 +68,9 @@ GEN-ALWAYS = · 28 unmodified lines | ||
| 67 | 68 | 106_pthread.test: FLAGS += -pthread |
| 68 | 69 | 106_pthread.test: NORUN = true |
| 69 | 70 | |
| 71 | +# constructor/destructor | |
| 72 | +108_constructor.test: NORUN = true | |
| 73 | + | |
| 70 | 74 | # Filter source directory in warnings/errors (out-of-tree builds) |
| 71 | 75 | FILTER = 2>&1 | sed 's,$(SRC)/,,g' |
| 72 | 76 | # Filter some always-warning |