From 64552b3faa39ee7948a9ea21bfcc11045b90c70d Mon Sep 17 00:00:00 2001 From: grischka Date: Mon, 3 Aug 2026 19:02:10 +0200 Subject: [PATCH] tccelf: rework linker_sym (_end/end) logic - tcc_add_linker_symbols(): don't add for dlls - bind_exe_dynsym(): update _end symbol when done allow data definition in the .so override a bss symbol in the exe. For example exe: int x; .so: int x = 123; - set_elf_sym(): cannot compare section numbers with symbols from dlls tcc_load_obj(): return -1 from symbol conflict errors tests/tests2/148_linker_symbols: - use only one file - make it print useful output rather than just "2 errors." In general, the tests2 setup with .expect files is meant to compare text output. For example: printf("val = %d\n", val); .expect file can be generated or refreshed using make tests2.nnn+ or in order to force generation with tcc itself make tests2.nnn+ GEN-CC='$(GEN-TCC)' tccgen.c: - __attribute__((section(...))) : set section type/flags according to first usage - fix bcheck bounds for -fcommon --- Makefile | 2 +- tcc.h | 1 + tccelf.c | 180 +++++++-------------- tccgen.c | 43 +++-- tests/tests2/114_bound_signal.c | 16 +- tests/tests2/124_atomic_counter.c | 2 +- tests/tests2/146+_tls_extern.c | 2 - tests/tests2/146_tls_extern.c | 8 +- tests/tests2/148+_linker_symbols.c | 13 -- tests/tests2/148+override_linker_symbols.c | 13 -- tests/tests2/148_linker_symbols.c | 152 ++++++++++++++++- tests/tests2/148_linker_symbols.expect | 44 ++++- tests/tests2/149+_end_copy_reloc.c | 1 - tests/tests2/149+override_end_copy_reloc.c | 18 --- tests/tests2/149_end_copy_reloc.c | 18 --- tests/tests2/149_end_copy_reloc.expect | 2 - tests/tests2/150+_linker_boundaries.c | 14 -- tests/tests2/150_linker_boundaries.c | 31 ---- tests/tests2/150_linker_boundaries.expect | 1 - tests/tests2/151+_dso_linker_symbol.c | 6 - tests/tests2/151_dso_linker_symbol.c | 12 -- tests/tests2/151_dso_linker_symbol.expect | 1 - tests/tests2/152_arm64_addend.c | 17 -- tests/tests2/152_arm64_addend.expect | 1 - tests/tests2/Makefile | 103 ++++-------- 25 files changed, 336 insertions(+), 365 deletions(-) delete mode 100644 tests/tests2/146+_tls_extern.c delete mode 100644 tests/tests2/148+_linker_symbols.c delete mode 100644 tests/tests2/148+override_linker_symbols.c delete mode 100644 tests/tests2/149+_end_copy_reloc.c delete mode 100644 tests/tests2/149+override_end_copy_reloc.c delete mode 100644 tests/tests2/149_end_copy_reloc.c delete mode 100644 tests/tests2/149_end_copy_reloc.expect delete mode 100644 tests/tests2/150+_linker_boundaries.c delete mode 100644 tests/tests2/150_linker_boundaries.c delete mode 100644 tests/tests2/150_linker_boundaries.expect delete mode 100644 tests/tests2/151+_dso_linker_symbol.c delete mode 100644 tests/tests2/151_dso_linker_symbol.c delete mode 100644 tests/tests2/151_dso_linker_symbol.expect delete mode 100644 tests/tests2/152_arm64_addend.c delete mode 100644 tests/tests2/152_arm64_addend.expect diff --git a/Makefile b/Makefile index 9976cfed..fc1e31b2 100644 --- a/Makefile +++ b/Makefile @@ -336,7 +336,7 @@ FORCE: # some versions of gnu-make do not recognize 'command' as a shell builtin WHICH = sh -c 'command -v $1' -run-if = $(if $(shell $(call WHICH,$1)),$S $1 $2,echo "(skipping $@ - no $1)") +run-if = $(if $(shell $(call WHICH,$1)),$S $1 $2,@echo "(skipping $@ - no $1)") S = $(if $(findstring yes,$(SILENT)),@$(info * $@)) # -------------------------------------------------------------------------- diff --git a/tcc.h b/tcc.h index abffcbfe..ce9b5189 100644 --- a/tcc.h +++ b/tcc.h @@ -675,6 +675,7 @@ typedef struct AttributeDef { int alias_target; /* token */ int asm_label; /* associated asm label */ char attr_mode; /* __attribute__((__mode__(...))) */ + char new_section; /* section is new */ } AttributeDef; /* inline functions */ diff --git a/tccelf.c b/tccelf.c index 7e96f7c4..f2c67142 100644 --- a/tccelf.c +++ b/tccelf.c @@ -742,6 +742,8 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, /* keep first-found weak definition, ignore subsequents */ } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { /* ignore hidden symbols after */ + } else if (s->sh_flags & SHF_DYNSYM) { + /* we accept that two DLL define the same symbol */ } else if ((esym->st_shndx == SHN_COMMON || esym->st_shndx == bss_section->sh_num) && (shndx < SHN_LORESERVE @@ -750,8 +752,6 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, goto do_patch; } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) { /* data symbol keeps precedence over common/bss */ - } else if (s->sh_flags & SHF_DYNSYM) { - /* we accept that two DLL define the same symbol */ } else if (esym->st_other & ST_ASM_SET) { /* If the existing symbol came from an asm .set we can override. */ @@ -761,7 +761,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); #endif - tcc_error_noabort("'%s' defined twice", name); + tcc_error_noabort("link symbol '%s' defined twice", name); } } else { esym->st_other = other; @@ -1560,94 +1560,6 @@ ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); } -#ifndef ELF_OBJ_ONLY -static int set_linker_sym(TCCState *s1, const char *name, - Section *sec, addr_t offs) -{ - int sym_index = find_elf_sym(symtab_section, name); - ElfW(Sym) *sym = sym_index - ? &((ElfW(Sym) *)symtab_section->data)[sym_index] : NULL; - /* Mirror the set_elf_sym cases where the new definition wins. */ - int is_linker_sym = !sym || sym->st_shndx == SHN_UNDEF - || ELFW(ST_BIND)(sym->st_info) == STB_WEAK - || (sec && sec != bss_section - && ((sym->st_other & ST_ASM_SET) - || sym->st_shndx == SHN_COMMON - || sym->st_shndx == bss_section->sh_num)); - - sym_index = set_global_sym(s1, name, sec, offs); - if (is_linker_sym) - get_sym_attr(s1, sym_index, 1)->linker_sym = 1; - return sym_index; -} - -static void provide_linker_sym(TCCState *s1, const char *name, - Section *sec, addr_t offs) -{ - int sym_index = find_elf_sym(symtab_section, name); - - if (sym_index) { - if (((ElfW(Sym) *)symtab_section->data)[sym_index].st_shndx != SHN_UNDEF) - return; - } else if (!s1->dynsymtab_section - || !find_elf_sym(s1->dynsymtab_section, name)) { - return; - } - set_linker_sym(s1, name, sec, offs); -} - -static void update_linker_sym(TCCState *s1, const char *name, - Section *sec, addr_t offs) -{ - int sym_index = find_elf_sym(symtab_section, name); - - if (sym_index && sym_index < s1->nb_sym_attrs - && s1->sym_attrs[sym_index].linker_sym) { - ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - - sym->st_value = offs; - sym->st_shndx = sec->sh_num; - if (s1->dynsym) { - sym_index = find_elf_sym(s1->dynsym, name); - if (sym_index) { - sym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index]; - sym->st_value = offs; - sym->st_shndx = sec->sh_num; - } - } - } -} - -static void finalize_linker_symbols(TCCState *s1, int *sec_order) -{ - Section *etext = text_section; - Section *edata = data_section; - Section *end = bss_section; - Section *s; - int i; - - /* Follow the final loadable-section order rather than assuming that - .text, .data and .bss are the last sections of their regions. */ - for (i = 1; i < s1->nb_sections; ++i) { - s = s1->sections[sec_order[i]]; - if (!(s->sh_flags & SHF_ALLOC)) - continue; - end = s; - if (!(s->sh_flags & SHF_WRITE)) - etext = s; - if (s->sh_type != SHT_NOBITS) - edata = s; - } - - update_linker_sym(s1, "_etext", etext, etext->sh_size); - update_linker_sym(s1, "etext", etext, etext->sh_size); - update_linker_sym(s1, "_edata", edata, edata->sh_size); - update_linker_sym(s1, "edata", edata, edata->sh_size); - update_linker_sym(s1, "_end", end, end->sh_size); - update_linker_sym(s1, "end", end, end->sh_size); -} -#endif - static void add_init_array_defines(TCCState *s1, const char *section_name) { Section *s; @@ -1963,6 +1875,39 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) } #endif /* ndef TCC_TARGET_PE */ +/* set _etext/_edata/_end f=0:set f=1:when_needed f=2,3:just_update */ +static void set_linker_sym(TCCState *s1, const char *name, Section *sec, int f) +{ + int sym_index, esym_index, defined; + ElfW(Sym) *sym, *esym; + sym_index = find_elf_sym(symtab_section, name); + sym = (ElfW(Sym) *)symtab_section->data + sym_index; + esym_index = find_elf_sym(s1->dynsymtab_section, name); + esym = (ElfW(Sym) *)s1->dynsymtab_section->data + esym_index; + defined = sym->st_shndx != SHN_UNDEF + || (esym->st_shndx != SHN_UNDEF && esym->st_size); + switch (f) { + case 1: /* old symbols w/o '_' */ + if (!(sym_index || esym_index) || defined) + break; + case 0: + if (defined) { + tcc_warning("linker symbol '%s' already defined", name); + break; + } + sym_index = set_global_sym(s1, name, sec, -1); + get_sym_attr(s1, sym_index, 1)->linker_sym = 1; + break; + default: /* update (bss only) */ + if (get_sym_attr(s1, sym_index, 0)->linker_sym) + sym->st_value = sec->data_offset; + } +#ifndef ELF_OBJ_ONLY + if (name[0] == '_') + set_linker_sym(s1, name + 1, sec, f + 1); +#endif +} + /* add various standard linker symbols (must be done after the sections are filled (for example after allocating common symbols)) */ @@ -1972,22 +1917,13 @@ static void tcc_add_linker_symbols(TCCState *s1) int i; Section *s; -#ifndef ELF_OBJ_ONLY - set_linker_sym(s1, "_etext", text_section, -1); - set_linker_sym(s1, "_edata", data_section, -1); - set_linker_sym(s1, "_end", bss_section, -1); - /* These conventional ELF symbols have PROVIDE semantics. */ - provide_linker_sym(s1, "etext", text_section, -1); - provide_linker_sym(s1, "edata", data_section, -1); - provide_linker_sym(s1, "end", bss_section, -1); -#else - set_global_sym(s1, "_etext", text_section, -1); - set_global_sym(s1, "_edata", data_section, -1); - set_global_sym(s1, "_end", bss_section, -1); -#endif + set_linker_sym(s1, "_etext", text_section, 0); + set_linker_sym(s1, "_edata", data_section, 0); + set_linker_sym(s1, "_end", bss_section, 0); #if TARGETOS_OpenBSD set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR); #endif + #ifdef TCC_TARGET_RISCV64 /* XXX should be .sdata+0x800, not .data+0x800 */ set_global_sym(s1, "__global_pointer$", data_section, 0x800); @@ -2032,7 +1968,7 @@ ST_FUNC void resolve_common_syms(TCCState *s1) /* Allocate common symbols in BSS. */ for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_COMMON) { + if (sym->st_shndx == SHN_COMMON && sym->st_size) { /* symbol alignment is in st_value for SHN_COMMONs */ sym->st_value = section_add(bss_section, sym->st_size, sym->st_value); @@ -2041,7 +1977,8 @@ ST_FUNC void resolve_common_syms(TCCState *s1) } /* Now assign linker provided symbols their value. */ - tcc_add_linker_symbols(s1); + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_linker_symbols(s1); } #ifndef ELF_OBJ_ONLY @@ -2129,13 +2066,16 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE) - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_UNDEF) { + if (sym->st_shndx == SHN_UNDEF + /* bss symbols may be initialized in the shared library */ + || sym->st_shndx == SHN_COMMON + || sym->st_shndx == bss_section->sh_num) { name = (char *) symtab_section->link->data + sym->st_name; sym_index = find_elf_sym(s1->dynsymtab_section, name); - if (sym_index) { + esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; + if (sym_index && esym->st_shndx != SHN_UNDEF) { if (is_PIE) continue; - esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; type = ELFW(ST_TYPE)(esym->st_info); if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { /* Indirect functions shall have STT_FUNC type in executable @@ -2154,15 +2094,19 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE) } else if (type == STT_OBJECT) { unsigned long offset; ElfW(Sym) *dynsym; - offset = bss_section->data_offset; - /* XXX: which alignment ? */ - offset = (offset + 16 - 1) & -16; + if (sym->st_shndx == bss_section->sh_num) { + offset = sym->st_value; + } else { + offset = bss_section->data_offset; + /* XXX: which alignment ? */ + offset = (offset + 16 - 1) & -16; + bss_section->data_offset = offset + esym->st_size; + } set_elf_sym (s1->symtab, offset, esym->st_size, esym->st_info, 0, bss_section->sh_num, name); index = put_elf_sym(s1->dynsym, offset, esym->st_size, esym->st_info, 0, bss_section->sh_num, name); - /* Ensure R_COPY works for weak symbol aliases */ if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { @@ -2177,13 +2121,10 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE) } } } - put_elf_reloc(s1->dynsym, bss_section, offset, R_COPY, index); - offset += esym->st_size; - bss_section->data_offset = offset; } - } else { + } else if (sym->st_shndx == SHN_UNDEF) { /* STB_WEAK undefined symbols are accepted */ /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || @@ -2194,6 +2135,8 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE) } } } + /* update _end symbol with new bss length */ + set_linker_sym(s1, "_end", bss_section, 2); } /* Bind symbols of libraries: export all non local symbols of executable that @@ -3179,7 +3122,6 @@ static int elf_output_file(TCCState *s1, const char *filename) sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); /* compute section to program header mapping */ layout_sections(s1, sec_order, &dyninf); - finalize_linker_symbols(s1, sec_order); if (dynamic) { /* put in GOT the dynamic section address and relocate PLT */ @@ -3627,7 +3569,7 @@ invalid: } } done: - ret = 0; + ret = !s1->nb_errors - 1; /* errors possibly from set_elf_sym() */ the_end: tcc_free(symtab); tcc_free(strtab); diff --git a/tccgen.c b/tccgen.c index 227ff618..8f4cd13a 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3966,7 +3966,9 @@ redo: case TOK_SECTION2: skip('('); astr = parse_mult_str("section name")->data; + n = tcc_state->nb_sections; ad->section = find_section(tcc_state, astr); + ad->new_section = n < tcc_state->nb_sections; skip(')'); break; case TOK_ALIAS1: @@ -8393,17 +8395,21 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, vset(type, r, addr); } } else { + CType *tp = type; + int is_const; + + while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY)) + tp = &tp->ref->type; + is_const = tp->t & VT_CONSTANT; + /* allocate symbol in corresponding section */ sec = ad->section; if (!sec) { - CType *tp = type; - while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY)) - tp = &tp->ref->type; if (type->t & VT_TLS) { sec = find_section(tcc_state, has_init ? ".tdata" : ".tbss"); sec->sh_flags = SHF_ALLOC | SHF_WRITE | SHF_TLS; sec->sh_type = has_init ? SHT_PROGBITS : SHT_NOBITS; - } else if (tp->t & VT_CONSTANT) { + } else if (is_const) { sec = rodata_section; } else if (has_init) { sec = data_section; @@ -8411,15 +8417,21 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, tcc_warning("rw data: %s", get_tok_str(v, 0));*/ } else if (tcc_state->nocommon) sec = bss_section; + } else if (ad->new_section) { + /* XXX: DWIM logic: set section flags according to first usage */ + if (!is_const) { + sec->sh_flags |= SHF_WRITE; + if (!has_init) + sec->sh_type = SHT_NOBITS; + } } +#ifdef CONFIG_TCC_BCHECK + if (bcheck) + size = size + 1; /* add padding */ +#endif if (sec) { addr = section_add(sec, size, align); -#ifdef CONFIG_TCC_BCHECK - /* add padding if bound check */ - if (bcheck) - section_add(sec, 1, 1); -#endif } else { addr = align; /* SHN_COMMON is special, symbol value is align */ sec = common_section; @@ -8449,7 +8461,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, /* then add global bound info */ bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); bounds_ptr[0] = 0; /* relocated */ - bounds_ptr[1] = size; + bounds_ptr[1] = size - 1; } #endif } @@ -8871,11 +8883,12 @@ static int decl(int l) skip_or_save_block(&fn->func_str); } else { /* compute text section */ - cur_text_section = ad.section; - if (!cur_text_section) - cur_text_section = text_section; - else if (cur_text_section->sh_num > bss_section->sh_num) - cur_text_section->sh_flags = text_section->sh_flags; + cur_text_section = text_section; + if (ad.section) { + cur_text_section = ad.section; + if (ad.new_section) + ad.section->sh_flags = text_section->sh_flags; + } gen_function(sym); } break; diff --git a/tests/tests2/114_bound_signal.c b/tests/tests2/114_bound_signal.c index d11b1461..0eec6895 100644 --- a/tests/tests2/114_bound_signal.c +++ b/tests/tests2/114_bound_signal.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,17 @@ static void child_handler(int sig) sem_post (&sem_child); } +static unsigned getclock_ms(void) +{ +#ifdef _WIN32 + return GetTickCount(); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; +#endif +} + int main (void) { @@ -112,8 +124,8 @@ main (void) #endif /* sleep does not work !!! */ - end = time(NULL) + 2; - while (time(NULL) < end) ; + end = getclock_ms() + 200; + while (getclock_ms() < end) ; run = 0; pthread_join(id1, NULL); diff --git a/tests/tests2/124_atomic_counter.c b/tests/tests2/124_atomic_counter.c index 5017ad50..8eb6ef82 100644 --- a/tests/tests2/124_atomic_counter.c +++ b/tests/tests2/124_atomic_counter.c @@ -6,7 +6,7 @@ #include #define NR_THREADS 16 -#define NR_STEPS ((uint32_t)UINT16_MAX) +#define NR_STEPS 10000 #define BUG_ON(COND) \ do { \ diff --git a/tests/tests2/146+_tls_extern.c b/tests/tests2/146+_tls_extern.c deleted file mode 100644 index eecd69be..00000000 --- a/tests/tests2/146+_tls_extern.c +++ /dev/null @@ -1,2 +0,0 @@ -__thread signed short extern_tls_short = 1234; -__thread float extern_tls_float = 1.5f; diff --git a/tests/tests2/146_tls_extern.c b/tests/tests2/146_tls_extern.c index cfae9fda..c0bb305c 100644 --- a/tests/tests2/146_tls_extern.c +++ b/tests/tests2/146_tls_extern.c @@ -1,7 +1,10 @@ -#include - +#ifdef DEFS +__thread signed short extern_tls_short = 1234; +__thread float extern_tls_float = 1.5f; +#else extern __thread signed short extern_tls_short; extern __thread float extern_tls_float; +int printf(const char *, ...); int main(void) { @@ -20,3 +23,4 @@ int main(void) printf("extern tls errors: %d\n", errors); return errors; } +#endif diff --git a/tests/tests2/148+_linker_symbols.c b/tests/tests2/148+_linker_symbols.c deleted file mode 100644 index bf82d31e..00000000 --- a/tests/tests2/148+_linker_symbols.c +++ /dev/null @@ -1,13 +0,0 @@ -extern char etext[], _etext[]; -extern char edata[], _edata[]; -extern char end[], _end[]; - -int check_linker_symbols(void) -{ - int errors = 0; - - errors += etext != _etext; - errors += edata != _edata; - errors += end != _end; - return errors; -} diff --git a/tests/tests2/148+override_linker_symbols.c b/tests/tests2/148+override_linker_symbols.c deleted file mode 100644 index cd96e74f..00000000 --- a/tests/tests2/148+override_linker_symbols.c +++ /dev/null @@ -1,13 +0,0 @@ -#include - -int etext(void) { return 1; } -int edata(void) { return 2; } -int end(void) { return 3; } - -int main(void) -{ - int errors = etext() + edata() + end() != 6; - - printf("user definitions errors: %d\n", errors); - return errors; -} diff --git a/tests/tests2/148_linker_symbols.c b/tests/tests2/148_linker_symbols.c index 0788f8db..9aca7350 100644 --- a/tests/tests2/148_linker_symbols.c +++ b/tests/tests2/148_linker_symbols.c @@ -1,11 +1,153 @@ -#include +int printf(const char *, ...); +#define assert(x) ((x) \ + ? (printf(" 1 (%s)\n",#x),1) \ + : (printf("%s:%d: error: (%s)\n",__FILE__,__LINE__,#x),0)) + +#define O 100 +#define SO 200 + +/* ------------------------------------------------------ */ +#if TEST-O == 1 +extern char etext[], _etext[]; +extern char edata[], _edata[]; +extern char end[], _end[]; +int check_linker_symbols(void) +{ + int errors = 0; + errors += !assert(etext == _etext); + errors += !assert(edata == _edata); + errors += !assert(end == _end); + return errors; +} + +#elif TEST-MAIN == 1 int check_linker_symbols(void); +int main(void) +{ + printf("linker symbols test\n"); + assert(check_linker_symbols() == 0); +} + +/* ------------------------------------------------------ */ +#elif TEST-SO == 2 +extern char etext[], edata[], end[]; +void get_dso_end(char **p) +{ + p[0] = etext; + p[1] = edata; + p[2] = end; +} + +#elif TEST-MAIN == 2 +extern char _etext[], _edata[], _end[]; +extern void get_dso_end(char **); +static int fill_data = 123; +static int fill_bss; int main(void) { - int errors = check_linker_symbols(); - - printf("linker symbols errors: %d\n", errors); - return errors; + char *p[3]; + printf("DSO linker symbols test\n"); + get_dso_end(p); + assert(p[0] == _etext) || printf("-- %p %p\n", p[0], _etext); + assert(p[1] == _edata) || printf("-- %p %p\n", p[1], _edata); + assert(p[2] == _end) || printf("-- %p %p\n", p[2], _end); } + +/* ------------------------------------------------------ */ +#elif TEST-MAIN == 3 + +int etext(void) { return 1; } +int edata(void) { return 2; } +int end(void) { return 3; } +int main(void) +{ + printf("user definition test\n"); + assert(etext() + edata() + end() == 6); +} + +/* ------------------------------------------------------ */ +#elif TEST-SO == 4 +unsigned char copy_reloc_data[257]; + +#elif TEST-MAIN == 4 +extern unsigned char copy_reloc_data[257]; +extern char end[], _end[]; + +int main(void) +{ + unsigned long data_end; + printf("end copy relocation test\n"); + copy_reloc_data[256] = 42; + data_end = (unsigned long)(copy_reloc_data + sizeof copy_reloc_data); + assert(end == _end); + assert((unsigned long)end >= data_end); + assert(copy_reloc_data[256] == 42); +} + +/* ------------------------------------------------------ */ +#elif TEST-O == 5 +void __attribute__((section(".text.linker_test"), noinline, used)) +linker_test_text(void) +{ +} +__attribute__((section(".bss.linker_test"), used)) +unsigned char linker_test_bss[257]; + +__attribute__((section(".data.linker_test"), used)) +unsigned char linker_test_data[23] = { 1 }; + +#elif TEST-MAIN == 5 +extern void linker_test_text(void); +extern unsigned char linker_test_data[23]; +extern unsigned char linker_test_bss[257]; +extern char etext[], _etext[]; +extern char edata[], _edata[]; +extern char end[], _end[]; + +int main(void) +{ + char* text_addr = (void*)linker_test_text; + char* data_end = linker_test_data + sizeof linker_test_data; + char* bss_end = linker_test_bss + sizeof linker_test_bss; + + printf("linker boundary test\n"); + linker_test_data[22] = 42; + linker_test_bss[256] = 42; + assert(linker_test_bss > linker_test_data); + assert(etext == _etext); + assert(edata == _edata); + assert(end == _end); + assert(etext >= text_addr); + assert(edata >= data_end); + assert(end >= bss_end); + assert(linker_test_data[22] == 42); + assert(linker_test_bss[256] == 42); +} + +/* ------------------------------------------------------ */ +#elif TEST-SO == 6 +int end; +int eight = 8; +int nine; +int dso_add() { return end + eight + nine; } + +#elif TEST-MAIN == 6 +int end = 7; +int eight; +int nine = 9; +int dso_add(); +int main() +{ + int sum; + printf("DSO initialized data test\n"); + sum = dso_add(); + assert(end == 7); + assert(eight == 8); + assert(nine == 9); + assert(sum == 24) || printf("-- %d + %d + %d = %d\n", end, eight, nine, sum); +} + +/* ------------------------------------------------------ */ +#endif diff --git a/tests/tests2/148_linker_symbols.expect b/tests/tests2/148_linker_symbols.expect index ef7716df..8ae23239 100644 --- a/tests/tests2/148_linker_symbols.expect +++ b/tests/tests2/148_linker_symbols.expect @@ -1,2 +1,42 @@ -linker symbols errors: 0 -user definitions errors: 0 + +--- TEST 1 --- +linker symbols test + 1 (etext == _etext) + 1 (edata == _edata) + 1 (end == _end) + 1 (check_linker_symbols() == 0) + +--- TEST 2 --- +DSO linker symbols test + 1 (p[0] == _etext) + 1 (p[1] == _edata) + 1 (p[2] == _end) + +--- TEST 3 --- +user definition test + 1 (etext() + edata() + end() == 6) + +--- TEST 4 --- +end copy relocation test + 1 (end == _end) + 1 ((unsigned long)end >= data_end) + 1 (copy_reloc_data[256] == 42) + +--- TEST 5 --- +linker boundary test + 1 (linker_test_bss > linker_test_data) + 1 (etext == _etext) + 1 (edata == _edata) + 1 (end == _end) + 1 (etext >= text_addr) + 1 (edata >= data_end) + 1 (end >= bss_end) + 1 (linker_test_data[22] == 42) + 1 (linker_test_bss[256] == 42) + +--- TEST 6 --- +DSO initialized data test + 1 (end == 7) + 1 (eight == 8) + 1 (nine == 9) + 1 (sum == 24) diff --git a/tests/tests2/149+_end_copy_reloc.c b/tests/tests2/149+_end_copy_reloc.c deleted file mode 100644 index 9fd6c196..00000000 --- a/tests/tests2/149+_end_copy_reloc.c +++ /dev/null @@ -1 +0,0 @@ -unsigned char copy_reloc_data[257]; diff --git a/tests/tests2/149+override_end_copy_reloc.c b/tests/tests2/149+override_end_copy_reloc.c deleted file mode 100644 index 52560b1f..00000000 --- a/tests/tests2/149+override_end_copy_reloc.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -extern unsigned char copy_reloc_data[257]; - -int end(void) { return 42; } -int _end(void) { return 24; } - -int main(void) -{ - int errors; - - copy_reloc_data[256] = 42; - errors = end() != 42; - errors += _end() != 24; - errors += copy_reloc_data[256] != 42; - printf("user end copy relocation errors: %d\n", errors); - return errors; -} diff --git a/tests/tests2/149_end_copy_reloc.c b/tests/tests2/149_end_copy_reloc.c deleted file mode 100644 index 4981b8ab..00000000 --- a/tests/tests2/149_end_copy_reloc.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -extern unsigned char copy_reloc_data[257]; -extern char end[], _end[]; - -int main(void) -{ - unsigned long data_end; - int errors = 0; - - copy_reloc_data[256] = 42; - data_end = (unsigned long)(copy_reloc_data + sizeof copy_reloc_data); - errors += end != _end; - errors += (unsigned long)end < data_end; - errors += copy_reloc_data[256] != 42; - printf("end copy relocation errors: %d\n", errors); - return errors; -} diff --git a/tests/tests2/149_end_copy_reloc.expect b/tests/tests2/149_end_copy_reloc.expect deleted file mode 100644 index 675c2783..00000000 --- a/tests/tests2/149_end_copy_reloc.expect +++ /dev/null @@ -1,2 +0,0 @@ -end copy relocation errors: 0 -user end copy relocation errors: 0 diff --git a/tests/tests2/150+_linker_boundaries.c b/tests/tests2/150+_linker_boundaries.c deleted file mode 100644 index 1f6beacc..00000000 --- a/tests/tests2/150+_linker_boundaries.c +++ /dev/null @@ -1,14 +0,0 @@ -void __attribute__((section(".text.linker_test"), noinline, used)) -linker_test_text(void) -{ -} - -unsigned char linker_test_data[23] - __attribute__((section(".data.linker_test"), used)) = { 1 }; - -unsigned char linker_test_bss[257] - __attribute__((section(".bss.linker_test"), used)); - -/* set_global_sym replaces BSS/common definitions of these symbols. */ -unsigned char _etext; -unsigned char _edata; diff --git a/tests/tests2/150_linker_boundaries.c b/tests/tests2/150_linker_boundaries.c deleted file mode 100644 index f482f278..00000000 --- a/tests/tests2/150_linker_boundaries.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - -extern void linker_test_text(void); -extern unsigned char linker_test_data[23]; -extern unsigned char linker_test_bss[257]; -extern char etext[], _etext[]; -extern char edata[], _edata[]; -extern char end[], _end[]; - -int main(void) -{ - unsigned long text_addr = (unsigned long)linker_test_text; - unsigned long data_end = (unsigned long)(linker_test_data - + sizeof linker_test_data); - unsigned long bss_end = (unsigned long)(linker_test_bss - + sizeof linker_test_bss); - int errors = 0; - - linker_test_data[22] = 42; - linker_test_bss[256] = 42; - errors += etext != _etext; - errors += edata != _edata; - errors += end != _end; - errors += (unsigned long)etext <= text_addr; - errors += (unsigned long)edata < data_end; - errors += (unsigned long)end < bss_end; - errors += linker_test_data[22] != 42; - errors += linker_test_bss[256] != 42; - printf("linker boundary errors: %d\n", errors); - return errors; -} diff --git a/tests/tests2/150_linker_boundaries.expect b/tests/tests2/150_linker_boundaries.expect deleted file mode 100644 index feb3f6cc..00000000 --- a/tests/tests2/150_linker_boundaries.expect +++ /dev/null @@ -1 +0,0 @@ -linker boundary errors: 0 diff --git a/tests/tests2/151+_dso_linker_symbol.c b/tests/tests2/151+_dso_linker_symbol.c deleted file mode 100644 index b3a9dcf1..00000000 --- a/tests/tests2/151+_dso_linker_symbol.c +++ /dev/null @@ -1,6 +0,0 @@ -char end = 7; - -char *get_dso_end(void) -{ - return &end; -} diff --git a/tests/tests2/151_dso_linker_symbol.c b/tests/tests2/151_dso_linker_symbol.c deleted file mode 100644 index 26e5491c..00000000 --- a/tests/tests2/151_dso_linker_symbol.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -extern char _end[]; -extern char *get_dso_end(void); - -int main(void) -{ - int errors = get_dso_end() != _end; - - printf("DSO linker symbol errors: %d\n", errors); - return errors; -} diff --git a/tests/tests2/151_dso_linker_symbol.expect b/tests/tests2/151_dso_linker_symbol.expect deleted file mode 100644 index 6e81c47a..00000000 --- a/tests/tests2/151_dso_linker_symbol.expect +++ /dev/null @@ -1 +0,0 @@ -DSO linker symbol errors: 0 diff --git a/tests/tests2/152_arm64_addend.c b/tests/tests2/152_arm64_addend.c deleted file mode 100644 index c2f126ba..00000000 --- a/tests/tests2/152_arm64_addend.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include - -static unsigned short data[844]; - -static uint64_t address_for_index(int index) -{ - return (uint64_t)(uintptr_t)data - 845186ULL - + (uint64_t)index * 2; -} - -int main(void) -{ - printf("%d\n", address_for_index(422593) - == (uint64_t)(uintptr_t)data); - return 0; -} diff --git a/tests/tests2/152_arm64_addend.expect b/tests/tests2/152_arm64_addend.expect deleted file mode 100644 index d00491fd..00000000 --- a/tests/tests2/152_arm64_addend.expect +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index dfd0d11a..83933e66 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -35,7 +35,7 @@ ifeq ($(CONFIG_bcheck),no) endif ifeq ($(CONFIG_dll),no) SKIP += 113_btdll.test # no shared lib support yet - SKIP += 149_end_copy_reloc.test 151_dso_linker_symbol.test + SKIP += 148_linker_symbols.test endif ifeq (-$(findstring gcc,$(CC))-,--) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) @@ -47,8 +47,7 @@ ifeq (-$(CONFIG_WIN32)-,-yes-) SKIP += 106_versym.test # No pthread support SKIP += 114_bound_signal.test # No pthread support SKIP += 117_builtins.test # win32 port doesn't define __builtins - SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests - SKIP += 150_linker_boundaries.test 151_dso_linker_symbol.test + SKIP += 148_linker_symbols.test # ELF linker tests endif ifneq (,$(filter OpenBSD FreeBSD NetBSD DragonFly,$(TARGETOS))) SKIP += 106_versym.test # no pthread_condattr_setpshared @@ -58,11 +57,10 @@ ifneq (,$(filter OpenBSD FreeBSD NetBSD DragonFly,$(TARGETOS))) endif ifeq ($(CONFIG_OSX),yes) SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported on Mach-O - SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests - SKIP += 150_linker_boundaries.test 151_dso_linker_symbol.test + SKIP += 148_linker_symbols.test # ELF linker tests endif ifeq ($(CONFIG_pie),yes) - SKIP += 149_end_copy_reloc.test # PIE executables do not use copy relocations + SKIP += 148_linker_symbols.test # PIE executables do not use copy relocations endif ifeq (-$(ARCH)-,-arm-) SKIP += 144_tls.test 146_tls_extern.test # doesn't work currently @@ -124,62 +122,6 @@ GEN-ALWAYS = # constructor/destructor 108_constructor.test: NORUN = true -# TLS needs executable and pthread, not -run -144_tls.test: FLAGS += -pthread -144_tls.test: NORUN = true -# Verify that undefined TLS symbols in TCC objects work with the system linker. -146_tls_extern.test: NORUN = true -146_tls_extern.test: T1 = \ - $(TCC) -c $1 -o 146_tls_extern-main.o && \ - $(TCC) -c $(subst 146,146+,$1) -o 146_tls_extern-def.o && \ - $(CC) -no-pie -Wl,-z,noexecstack 146_tls_extern-main.o \ - 146_tls_extern-def.o -o $(basename $@).exe && \ - ./$(basename $@).exe -ifeq (-$(CONFIG_WIN32)-,-yes-) -146_tls_extern.test : CC=$(TCC) -endif - -# Check optional ELF linker symbols, including references from an archive. -148_linker_symbols.test: NORUN = true -148_linker_symbols.test: T1 = ( \ - $(TCC) -c $(subst 148,148+,$1) -o 148_linker_symbols.o && \ - $(AR) rcs 148_linker_symbols.a 148_linker_symbols.o && \ - $(TCC) $1 148_linker_symbols.a -o $(basename $@).exe && \ - ./$(basename $@).exe && \ - $(TCC) $(subst 148,148+override,$1) -o 148_linker_symbols-override.exe && \ - ./148_linker_symbols-override.exe \ - ) - -# Copy relocations must be included in the final end symbols. -149_end_copy_reloc.test: NORUN = true -149_end_copy_reloc.test: T1 = ( \ - $(TCC) -shared $(subst 149,149+,$1) -o 149_end_copy_reloc$(DLLSUF) && \ - $(TCC) $1 ./149_end_copy_reloc$(DLLSUF) -Wl,-rpath=. \ - -o $(basename $@).exe && \ - ./$(basename $@).exe && \ - $(TCC) $(subst 149,149+override,$1) ./149_end_copy_reloc$(DLLSUF) \ - -Wl,-rpath=. -o 149_end_copy_reloc-override.exe && \ - ./149_end_copy_reloc-override.exe \ - ) - -# Boundary symbols must cover separately named sections from external objects. -150_linker_boundaries.test: NORUN = true -150_linker_boundaries.test: T1 = ( \ - $(CC) -fcommon -fno-pic -fno-pie -c $(subst 150,150+,$1) \ - -o 150_linker_boundaries.o && \ - $(TCC) $1 150_linker_boundaries.o -o $(basename $@).exe && \ - ./$(basename $@).exe \ - ) - -# A linker symbol needed only by a DSO must be provided by the executable. -151_dso_linker_symbol.test: NORUN = true -151_dso_linker_symbol.test: T1 = ( \ - $(TCC) -shared $(subst 151,151+,$1) -o 151_dso_linker_symbol$(DLLSUF) && \ - $(TCC) $1 ./151_dso_linker_symbol$(DLLSUF) -Wl,-rpath=. \ - -o $(basename $@).exe && \ - ./$(basename $@).exe \ - ) - 112_backtrace.test: FLAGS += -dt -b 112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \ -e 's;[0-9A-Fa-fx]\{5,\};........;g' \ @@ -189,9 +131,8 @@ endif 113_btdll.test: T1 = \ $(TCC) -bt $1 -shared -D DLL=1 -o a1$(DLLSUF) && \ $(TCC) -bt $1 -shared -D DLL=2 -o a2$(DLLSUF) && \ - $(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $(basename $@).exe && \ - ./$(basename $@).exe - + $(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $*.exe && \ + ./$*.exe 114_bound_signal.test: FLAGS += -b 114_bound_signal.test: NORUN = true # tcc -run does not support fork and -b and SELINUX @@ -211,6 +152,32 @@ endif 140_arm64_extasm.test: GEN = $(GEN-TCC) 141_riscv_asm.test: GEN = $(GEN-TCC) +# TLS needs executable and pthread, not -run +144_tls.test: FLAGS += -pthread +144_tls.test: NORUN = true + +# Verify that undefined TLS symbols in TCC objects work with the system linker. +# (note: '$*' is '146_tls_extern' here) +146_tls_extern.test: T1 = \ + $(TCC) -c $1 -o $*-main.o && \ + $(TCC) -c $1 -DDEFS -o $*-defs.o && \ + $(CC) -no-pie -Wl,-z,noexecstack $*-main.o $*-defs.o -o $*.exe && \ + ./$*.exe +ifeq (-$(CONFIG_WIN32)-,-yes-) +146_tls_extern.test : CC=$(TCC) +endif + +# Check ELF linker symbols +148_linker_symbols.test: T1 = \ + for T in 1 2 3 4 5 6; do \ + echo; echo "--- TEST $$T ---"; F=$*-$$T; \ + $(TCC) $1 -DTEST=$$T+100 -c -fcommon -o $$F.o && \ + $(TCC) $1 -DTEST=$$T+200 -shared -o $$F.so -fPIC && \ + $(TCC) $1 -DTEST=$$T -Wl,-rpath=. -o $$F.exe $$F.o $$F.so -no-pie && \ + ./$$F.exe; \ + done +148_linker_symbols.test: GEN=$(T1) + # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' @@ -222,7 +189,7 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS)) @$(call T1,$<) $(T3) T1 = $(TCC) $(FLAGS) $(T2) $(ARGS) -T2 = $(if $(NORUN),$1 -o $(basename $@).exe && ./$(basename $@).exe,-run $1) +T2 = $(if $(NORUN),$1 -o $*.exe && ./$*.exe,-run $1) T3 = $(FILTER) >$*.output 2>&1 || true \ && diff -Nbu $(filter %.expect,$^) $*.output \ && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) @@ -250,9 +217,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" # using TCC for .expect if -dt in FLAGS GEN = $(if $(filter -dt -bt -b,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) -GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o $(basename $@).exe && ./$(basename $@).exe $(ARGS) +GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o $*.exe && ./$*.exe $(ARGS) GEN-TCC = $(T1) -GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe +GEN-MSC = $(MS-CC) $1 && ./$*.exe MS-CC = cl # tell make not to delete