From 1a4d4b76e803a32db1168e66ad8f8b26c29c8ea0 Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 12 Dec 2017 17:33:37 +0100 Subject: [PATCH] tccgen_begin/end_file This is supposed to make compilation and linking with multiple source files (tcc f1.c f2.S ...) behave just the same as linking object files. tccgen.c:put_extern_sym2(): - use put_elf_sym to enter new symbols unconditionally tccelf.c: - save section state before compilation - disable symbol hashing during compilation - merge symbols and update relocations after compilation tccpe.c: - re-create s1->uw_sym for each compilation (because it may change) --- libtcc.c | 7 ++-- tcc.h | 4 ++- tccelf.c | 120 +++++++++++++++++++++++++++++++++++---------------------------- tccgen.c | 2 +- tccpe.c | 14 ++++---- tccrun.c | 2 +- 6 files changed, 81 insertions(+), 68 deletions(-) diff --git a/libtcc.c b/libtcc.c index 092c0ba3..1e9dd971 100644 --- a/libtcc.c +++ b/libtcc.c @@ -486,7 +486,7 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", (*pf)->filename, (*pf)->line_num); - if (f->line_num > 0) { + if (s1->error_set_jmp_enabled) { strcat_printf(buf, sizeof(buf), "%s:%d: ", f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL)); } else { @@ -629,6 +629,7 @@ static int tcc_compile(TCCState *s1) define_start = define_stack; filetype = s1->filetype; is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP; + tccelf_begin_file(s1); if (setjmp(s1->error_jmp_buf) == 0) { s1->nb_errors = 0; @@ -655,6 +656,7 @@ static int tcc_compile(TCCState *s1) free_defines(define_start); sym_pop(&global_stack, NULL, 0); sym_pop(&local_stack, NULL, 0); + tccelf_end_file(s1); return s1->nb_errors != 0 ? -1 : 0; } @@ -1016,9 +1018,6 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) obj_type = tcc_object_type(fd, &ehdr); lseek(fd, 0, SEEK_SET); - /* do not display line number if error */ - file->line_num = 0; - #ifdef TCC_TARGET_MACHO if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib")) obj_type = AFF_BINTYPE_DYN; diff --git a/tcc.h b/tcc.h index 926ac5d3..4fc273b8 100644 --- a/tcc.h +++ b/tcc.h @@ -1397,6 +1397,8 @@ ST_DATA Section *stab_section, *stabstr_section; ST_FUNC void tccelf_new(TCCState *s); ST_FUNC void tccelf_delete(TCCState *s); ST_FUNC void tccelf_stab_new(TCCState *s); +ST_FUNC void tccelf_begin_file(TCCState *s1); +ST_FUNC void tccelf_end_file(TCCState *s1); ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); ST_FUNC void section_realloc(Section *sec, unsigned long new_size); @@ -1425,7 +1427,7 @@ ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigne ST_FUNC void put_stabn(int type, int other, int desc, int value); ST_FUNC void put_stabd(int type, int other, int desc); -ST_FUNC void resolve_regular_syms(void); +ST_FUNC void resolve_common_syms(TCCState *s1); ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); ST_FUNC void relocate_section(TCCState *s1, Section *s); diff --git a/tccelf.c b/tccelf.c index 278d586c..080c72bc 100644 --- a/tccelf.c +++ b/tccelf.c @@ -130,6 +130,59 @@ ST_FUNC void tccelf_delete(TCCState *s1) tcc_free(s1->sym_attrs); } +/* save section data state */ +ST_FUNC void tccelf_begin_file(TCCState *s1) +{ + Section *s; int i; + for (i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + s->sh_offset = s->data_offset; + } + /* disable symbol hashing during compilation */ + s = s1->symtab, s->reloc = s->hash, s->hash = NULL; +#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE + s1->uw_sym = 0; +#endif +} + +/* At the end of compilation, convert any UNDEF syms to global, and merge + with previously existing symbols */ +ST_FUNC void tccelf_end_file(TCCState *s1) +{ + Section *s = s1->symtab; + int first_sym, nb_syms, *tr, i; + + first_sym = s->sh_offset / sizeof (ElfSym); + nb_syms = s->data_offset / sizeof (ElfSym) - first_sym; + s->data_offset = s->sh_offset; + s->link->data_offset = s->link->sh_offset; + s->hash = s->reloc, s->reloc = NULL; + tr = tcc_mallocz(nb_syms * sizeof *tr); + + for (i = 0; i < nb_syms; ++i) { + ElfSym *sym = (ElfSym*)s->data + first_sym + i; + if (sym->st_shndx == SHN_UNDEF + && ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) + sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); + tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, + sym->st_other, sym->st_shndx, s->link->data + sym->st_name); + } + /* now update relocations */ + for (i = 1; i < s1->nb_sections; i++) { + Section *sr = s1->sections[i]; + if (sr->sh_type == SHT_RELX && sr->link == s) { + ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset); + ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset); + for (; rel < rel_end; ++rel) { + int n = ELFW(R_SYM)(rel->r_info) - first_sym; + //if (n < 0) tcc_error("internal: invalid symbol index in relocation"); + rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info)); + } + } + } + tcc_free(tr); +} + ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) { Section *sec; @@ -269,7 +322,7 @@ ST_FUNC int put_elf_str(Section *s, const char *sym) len = strlen(sym) + 1; offset = s->data_offset; ptr = section_ptr_add(s, len); - memcpy(ptr, sym, len); + memmove(ptr, sym, len); return offset; } @@ -335,7 +388,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, Section *hs; sym = section_ptr_add(s, sizeof(ElfW(Sym))); - if (name) + if (name && name[0]) name_offset = put_elf_str(s->link, name); else name_offset = 0; @@ -356,7 +409,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, if (ELFW(ST_BIND)(info) != STB_LOCAL) { /* add another hashing entry */ nbuckets = base[0]; - h = elf_hash((unsigned char *) name) % nbuckets; + h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets; *ptr = base[2 + h]; base[2 + h] = sym_index; base[1]++; @@ -373,7 +426,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, return sym_index; } -static int find_elf_sym_1(Section *s, const char *name, int onlydef) +ST_FUNC int find_elf_sym(Section *s, const char *name) { ElfW(Sym) *sym; Section *hs; @@ -389,21 +442,13 @@ static int find_elf_sym_1(Section *s, const char *name, int onlydef) while (sym_index != 0) { sym = &((ElfW(Sym) *)s->data)[sym_index]; name1 = (char *) s->link->data + sym->st_name; - if (!strcmp(name, name1) && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL - && (!onlydef || sym->st_shndx != SHN_UNDEF)) + if (!strcmp(name, name1)) return sym_index; sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; } return 0; } -/* find global ELF symbol 'name' and return its index. Return 0 if not - found. */ -ST_FUNC int find_elf_sym(Section *s, const char *name) -{ - return find_elf_sym_1(s, name, 0); -} - /* return elf symbol value, signal error if 'err' is nonzero */ ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err) { @@ -447,17 +492,15 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, sym_type = ELFW(ST_TYPE)(info); sym_vis = ELFW(ST_VISIBILITY)(other); - sym_index = find_elf_sym(s, name); - esym = &((ElfW(Sym) *)s->data)[sym_index]; - if (sym_index && esym->st_value == value && esym->st_size == size - && esym->st_info == info && esym->st_other == other - && esym->st_shndx == shndx) - return sym_index; - if (sym_bind != STB_LOCAL) { /* we search global or weak symbols */ + sym_index = find_elf_sym(s, name); if (!sym_index) goto do_def; + esym = &((ElfW(Sym) *)s->data)[sym_index]; + if (esym->st_value == value && esym->st_size == size && esym->st_info == info + && esym->st_other == other && esym->st_shndx == shndx) + return sym_index; if (esym->st_shndx != SHN_UNDEF) { esym_bind = ELFW(ST_BIND)(esym->st_info); /* propagate the most constraining visibility */ @@ -1220,11 +1263,8 @@ static void tcc_add_linker_symbols(TCCState *s1) } } -/* Do final regular symbol preparation (for those coming from .c/.o/.s files, - not from shared libs) */ -ST_FUNC void resolve_regular_syms(void) +ST_FUNC void resolve_common_syms(TCCState *s1) { - int rebuild = 0; ElfW(Sym) *sym; /* Allocate common symbols in BSS. */ @@ -1238,27 +1278,7 @@ ST_FUNC void resolve_regular_syms(void) } /* Now assign linker provided symbols their value. */ - tcc_add_linker_symbols(tcc_state); - - /* And finally resolve still UNDEF symbols (for multi-file mode), - and globalize those that are still UNDEF. */ - rebuild_hash(symtab_section, 0); - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_UNDEF) { - const char *name = (char *) symtab_section->link->data + sym->st_name; - int symndx = find_elf_sym_1(symtab_section, name, 1); - if (symndx) { - *sym = ((ElfSym *)symtab_section->data)[symndx]; - rebuild = 1; - } else if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - sym->st_info - = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); - rebuild = 1; - } - } - } - if (rebuild) - rebuild_hash(symtab_section, 0); + tcc_add_linker_symbols(s1); } static void tcc_output_binary(TCCState *s1, FILE *f, @@ -2051,7 +2071,7 @@ static int elf_output_file(TCCState *s1, const char *filename) if (file_type != TCC_OUTPUT_OBJ) { /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ tcc_add_runtime(s1); - resolve_regular_syms(); + resolve_common_syms(s1); if (!s1->static_link) { if (file_type == TCC_OUTPUT_EXE) { @@ -2092,14 +2112,6 @@ static int elf_output_file(TCCState *s1, const char *filename) } } build_got_entries(s1); - } else { - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_UNDEF - && ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - sym->st_info - = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); - } - } } /* we add a section for symbols */ diff --git a/tccgen.c b/tccgen.c index 97ea94cc..7e10c18d 100644 --- a/tccgen.c +++ b/tccgen.c @@ -418,7 +418,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, if (sym->asm_label) name = get_tok_str(sym->asm_label, NULL); info = ELFW(ST_INFO)(sym_bind, sym_type); - sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); + sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); } else { esym = elfsym(sym); esym->st_value = value; diff --git a/tccpe.c b/tccpe.c index af4438d8..7e7150ce 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1633,7 +1633,7 @@ static int pe_load_res(TCCState *s1, int fd) { struct pe_rsrc_header hdr; Section *rsrc_section; - int i, ret = -1; + int i, ret = -1, sym_index; BYTE *ptr; unsigned offs; @@ -1651,8 +1651,8 @@ static int pe_load_res(TCCState *s1, int fd) if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) goto quit; offs = hdr.sectionhdr.PointerToRelocations; - for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) - { + sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc"); + for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) { struct pe_rsrc_reloc rel; if (!read_mem(fd, offs, &rel, sizeof rel)) goto quit; @@ -1660,7 +1660,7 @@ static int pe_load_res(TCCState *s1, int fd) if (rel.type != RSRC_RELTYPE) goto quit; put_elf_reloc(symtab_section, rsrc_section, - rel.offset, R_XXX_RELATIVE, 0); + rel.offset, R_XXX_RELATIVE, sym_index); offs += sizeof rel; } ret = 0; @@ -1779,9 +1779,9 @@ static unsigned pe_add_uwwind_info(TCCState *s1) if (NULL == s1->uw_pdata) { s1->uw_pdata = find_section(tcc_state, ".pdata"); s1->uw_pdata->sh_addralign = 4; - s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); } - + if (0 == s1->uw_sym) + s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base"); if (0 == s1->uw_offs) { /* As our functions all have the same stackframe, we use one entry for all */ static const unsigned char uw_info[] = { @@ -1970,7 +1970,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) tcc_add_bcheck(s1); pe_add_runtime(s1, &pe); - resolve_regular_syms(); + resolve_common_syms(s1); pe_set_options(s1, &pe); ret = pe_check_symbols(&pe); diff --git a/tccrun.c b/tccrun.c index 72b3994d..20d72ce4 100644 --- a/tccrun.c +++ b/tccrun.c @@ -188,7 +188,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff) pe_output_file(s1, NULL); #else tcc_add_runtime(s1); - resolve_regular_syms(); + resolve_common_syms(s1); build_got_entries(s1); #endif if (s1->nb_errors) -- 2.11.4.GIT