From 62c0c4c77a1ce9ca075bc76b9ced509d6000cab1 Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 12 Jan 2021 15:13:30 +0100 Subject: [PATCH] tccelf.c: factor out elf_output_obj() The small common parts within elf_output_file() aren't worth the many #ifdefs. Also, set section sizes and allocate section names in 2 separate functions. --- Makefile | 4 - libtcc.c | 11 +- tccelf.c | 284 ++++++++++++++++++++++++++----------------------- tests/Makefile | 2 +- 4 files changed, 156 insertions(+), 145 deletions(-) diff --git a/Makefile b/Makefile index fae8e023..21455988 100644 --- a/Makefile +++ b/Makefile @@ -62,10 +62,6 @@ else endif export MACOSX_DEPLOYMENT_TARGET := 10.6 endif - # Unclear why the following ifdef was defined. Build fails on all *BSD - # ifdef CONFIG_BSD - # NATIVE_TARGET = $(ARCH)-$(TARGETOS) - # endif endif # run local version of tcc with local libraries and includes diff --git a/libtcc.c b/libtcc.c index 2f46e0aa..7723b85e 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1105,7 +1105,7 @@ ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename) /* OpenBSD only has suffixed .so files; e.g., libc.so.96.0 */ /* So we must process that */ -#if defined TARGETOS_OpenBSD +#if defined TARGETOS_OpenBSD && !defined _WIN32/* no dirent */ #include ST_FUNC char *tcc_openbsd_library_soversion(TCCState *s, const char *libraryname) { @@ -1185,7 +1185,7 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) #elif defined TCC_TARGET_MACHO const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL }; const char **pp = s->static_link ? libs + 1 : libs; -#elif defined TARGETOS_OpenBSD +#elif defined TARGETOS_OpenBSD && !defined _WIN32 const char *libs[] = { s->static_link ? NULL /* find exact versionned .so.x.y name as no @@ -1479,11 +1479,8 @@ static int tcc_set_linker(TCCState *s, const char *option) s->filetype |= AFF_WHOLE_ARCHIVE; else s->filetype &= ~AFF_WHOLE_ARCHIVE; - } else if (ret = link_option(option, "z=", &p), ret) { - if (!strcmp(p, "notext")) - ; /* ignore */ - else - goto err; + } else if (link_option(option, "z=", &p)) { + ignoring = 1; } else if (p) { return 0; } else { diff --git a/tccelf.c b/tccelf.c index b333c51f..48c9fbe6 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1071,11 +1071,6 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) break; } } - if (count) { - /* allocate the section */ - sr->sh_flags |= SHF_ALLOC; - sr->sh_size = count * sizeof(ElfW_Rel); - } #endif return count; } @@ -1566,29 +1561,8 @@ ST_FUNC void resolve_common_syms(TCCState *s1) tcc_add_linker_symbols(s1); } -static void tcc_output_binary(TCCState *s1, FILE *f, - const int *sec_order) -{ - Section *s; - int i, offset, size; - - offset = 0; - for(i=1;inb_sections;i++) { - s = s1->sections[sec_order[i]]; - if (s->sh_type != SHT_NOBITS && - (s->sh_flags & SHF_ALLOC)) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - fwrite(s->data, 1, size, f); - offset += size; - } - } -} - #ifndef ELF_OBJ_ONLY + ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) { int sym_index = ELFW(R_SYM) (rel->r_info); @@ -1791,43 +1765,40 @@ static void export_global_syms(TCCState *s1) } } } -#endif -/* Allocate strings for section names and decide if an unallocated section - should be output. - NOTE: the strsec section comes last, so its size is also correct ! */ -static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) +/* decide if an unallocated section should be output. */ +static int set_sec_sizes(TCCState *s1) { int i; Section *s; int textrel = 0; + int file_type = s1->output_type; /* Allocate strings for section names */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; - /* when generating a DLL, we include relocations but we may - patch them */ -#ifndef ELF_OBJ_ONLY - if (file_type == TCC_OUTPUT_DLL && - s->sh_type == SHT_RELX && - !(s->sh_flags & SHF_ALLOC) && - (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && - prepare_dynamic_rel(s1, s)) { - if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) - textrel = 1; - } else -#endif - if ((s1->do_debug && s->sh_type != SHT_RELX) || - file_type == TCC_OUTPUT_OBJ || - (s->sh_flags & SHF_ALLOC) || - i == (s1->nb_sections - 1) + if (s->sh_type == SHT_RELX && !(s->sh_flags & SHF_ALLOC)) { + /* when generating a DLL, we include relocations but + we may patch them */ + if (file_type == TCC_OUTPUT_DLL + && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) { + int count = prepare_dynamic_rel(s1, s); + if (count) { + /* allocate the section */ + s->sh_flags |= SHF_ALLOC; + s->sh_size = count * sizeof(ElfW_Rel); + if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) + textrel = 1; + } + } + } else if ((s->sh_flags & SHF_ALLOC) #ifdef TCC_TARGET_ARM - || s->sh_type == SHT_ARM_ATTRIBUTES + || s->sh_type == SHT_ARM_ATTRIBUTES #endif - ) { - /* we output all sections if debug or object file */ + || s1->do_debug) { s->sh_size = s->data_offset; } + #ifdef TCC_TARGET_ARM /* XXX: Suppress stack unwinding section. */ if (s->sh_type == SHT_ARM_EXIDX) { @@ -1835,13 +1806,12 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) s->sh_size = 0; } #endif - if (s->sh_size || (s->sh_flags & SHF_ALLOC)) - s->sh_name = put_elf_str(strsec, s->name); + } - strsec->sh_size = strsec->data_offset; return textrel; } + /* Info to be copied in dynamic section */ struct dyn_inf { Section *dynamic; @@ -1858,23 +1828,29 @@ struct ro_inf { addr_t sh_size; }; +static void alloc_sec_names( + TCCState *s1, int is_obj + ); + +static int layout_any_sections( + TCCState *s1, int file_offset, int *sec_order, int is_obj + ); + /* Assign sections to segments and decide how are sections laid out when loaded in memory. This function also fills corresponding program headers. */ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, int phfill, - Section *interp, Section* strsec, + Section *interp, struct ro_inf *roinf, int *sec_order) { - int i, sh_order_index, file_offset; + int i, file_offset; Section *s; - sh_order_index = 1; file_offset = 0; if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); -#ifndef ELF_OBJ_ONLY - if (phnum > 0) { /* phnum is 0 for TCC_OUTPUT_OBJ */ + { unsigned long s_align; long long tmp; addr_t addr; @@ -1979,7 +1955,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, if (k != 5) continue; } - sec_order[sh_order_index++] = i; + *sec_order++ = i; /* section matches: we align it and add its size */ tmp = addr; @@ -2039,26 +2015,11 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, } } } -#endif /* ELF_OBJ_ONLY */ /* all other sections come after */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) - continue; - sec_order[sh_order_index++] = i; - - file_offset = (file_offset + s->sh_addralign - 1) & - ~(s->sh_addralign - 1); - s->sh_offset = file_offset; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - } - - return file_offset; + return layout_any_sections(s1, file_offset, sec_order, 0); } -#ifndef ELF_OBJ_ONLY /* put dynamic tag */ static void put_dt(Section *dynamic, int dt, addr_t val) { @@ -2269,7 +2230,8 @@ static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf) } } } -#endif + +#endif /* ndef ELF_OBJ_ONLY */ /* Create an ELF file on disk. This function handle ELF specific layout requirements */ @@ -2390,6 +2352,28 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, } } +static void tcc_output_binary(TCCState *s1, FILE *f, + const int *sec_order) +{ + Section *s; + int i, offset, size; + + offset = 0; + for(i=1;inb_sections;i++) { + s = s1->sections[sec_order[i]]; + if (s->sh_type != SHT_NOBITS && + (s->sh_flags & SHF_ALLOC)) { + while (offset < s->sh_offset) { + fputc(0, f); + offset++; + } + size = s->sh_size; + fwrite(s->data, 1, size, f); + offset += size; + } + } +} + /* Write an elf, coff or "binary" file */ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, ElfW(Phdr) *phdr, int file_offset, int *sec_order) @@ -2472,7 +2456,6 @@ static void tidy_section_headers(TCCState *s1, int *sec_order) s1->nb_sections = nnew; tcc_free(backmap); } -#endif #ifdef TCC_TARGET_ARM static void create_arm_attribute_section(TCCState *s1) @@ -2539,33 +2522,30 @@ static int elf_output_file(TCCState *s1, const char *filename) struct dyn_inf dyninf = {0}; struct ro_inf roinf; ElfW(Phdr) *phdr; - Section *strsec, *interp, *dynamic, *dynstr, *note = NULL; -//#ifndef ELF_OBJ_ONLY + Section *interp, *dynamic, *dynstr, *note; struct ro_inf *roinf_use = NULL; -//#endif + int textrel; file_type = s1->output_type; - -#ifdef TCC_TARGET_ARM - create_arm_attribute_section (s1); -#endif -#if TARGETOS_OpenBSD - if (file_type != TCC_OUTPUT_OBJ) - note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); -#endif -#if TARGETOS_NetBSD - if (file_type != TCC_OUTPUT_OBJ) - note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); -#endif - s1->nb_errors = 0; ret = -1; phdr = NULL; sec_order = NULL; - interp = dynamic = dynstr = NULL; /* avoid warning */ + interp = dynamic = dynstr = note = NULL; -#ifndef ELF_OBJ_ONLY - if (file_type != TCC_OUTPUT_OBJ) { +#ifdef TCC_TARGET_ARM + create_arm_attribute_section (s1); +#endif + +#if TARGETOS_OpenBSD + note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); +#endif + +#if TARGETOS_NetBSD + note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); +#endif + + { /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ tcc_add_runtime(s1); resolve_common_syms(s1); @@ -2612,17 +2592,11 @@ static int elf_output_file(TCCState *s1, const char *filename) build_got_entries(s1); version_add (s1); } -#endif - /* we add a section for symbols */ - strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); - put_elf_str(strsec, ""); + textrel = set_sec_sizes(s1); + alloc_sec_names(s1, 0); - /* Allocate strings for section names */ - ret = alloc_sec_names(s1, file_type, strsec); - -#ifndef ELF_OBJ_ONLY - if (dynamic) { + if (!s1->static_link) { int i; /* add a list of needed dlls */ for(i = 0; i < s1->nb_loaded_dlls; i++) { @@ -2640,7 +2614,7 @@ static int elf_output_file(TCCState *s1, const char *filename) put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); /* XXX: currently, since we do not handle PIC code, we must relocate the readonly segments */ - if (ret) + if (textrel) put_dt(dynamic, DT_TEXTREL, 0); } @@ -2655,16 +2629,13 @@ static int elf_output_file(TCCState *s1, const char *filename) dynamic->sh_size = dynamic->data_offset; dynstr->sh_size = dynstr->data_offset; } -#endif for (i = 1; i < s1->nb_sections && !(s1->sections[i]->sh_flags & SHF_TLS); i++); phfill = 2 + (i < s1->nb_sections); /* compute number of program headers */ - if (file_type == TCC_OUTPUT_OBJ) - phnum = phfill = 0; - else if (file_type == TCC_OUTPUT_DLL) + if (file_type == TCC_OUTPUT_DLL) phnum = 3; else if (s1->static_link) phnum = 3; @@ -2673,31 +2644,25 @@ static int elf_output_file(TCCState *s1, const char *filename) } phnum += note != NULL; - -#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32) +#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD /* GNU_RELRO */ - if (file_type != TCC_OUTPUT_OBJ) - phnum++, roinf_use = &roinf; + phnum++, roinf_use = &roinf; #endif /* allocate program segment headers */ phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); - /* compute number of sections */ shnum = s1->nb_sections; - /* this array is used to reorder sections in the output file */ sec_order = tcc_malloc(sizeof(int) * shnum); sec_order[0] = 0; /* compute section to program header mapping */ - file_offset = layout_sections(s1, phdr, phnum, phfill, interp, strsec, - &roinf, sec_order); + file_offset = layout_sections(s1, phdr, phnum, phfill, interp, &roinf, sec_order + 1); -#ifndef ELF_OBJ_ONLY /* Fill remaining program header and finalize relocation related to dynamic linking. */ - if (file_type != TCC_OUTPUT_OBJ) { + { fill_unloadable_phdr(phdr, phnum, interp, dynamic, note, roinf_use); if (dynamic) { ElfW(Sym) *sym; @@ -2735,32 +2700,85 @@ static int elf_output_file(TCCState *s1, const char *filename) else if (s1->got) fill_local_got_entries(s1); } -#endif - /* Create the ELF file with name 'filename' */ ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); s1->nb_sections = shnum; - goto the_end; + the_end: tcc_free(sec_order); tcc_free(phdr); return ret; } +#endif /* ndef ELF_OBJ_ONLY */ + +/* Allocate strings for section names */ +static void alloc_sec_names(TCCState *s1, int is_obj) +{ + int i; + Section *s, *strsec; + + strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); + put_elf_str(strsec, ""); + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (is_obj) + s->sh_size = s->data_offset; + if (s->sh_size || (s->sh_flags & SHF_ALLOC)) + s->sh_name = put_elf_str(strsec, s->name); + } + strsec->sh_size = strsec->data_offset; +} + +static int layout_any_sections(TCCState *s1, int file_offset, int *sec_order, int is_obj) +{ + int i; + Section *s; + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (!is_obj && (s->sh_flags & SHF_ALLOC)) + continue; + *sec_order++ = i; + file_offset = (file_offset + s->sh_addralign - 1) & + ~(s->sh_addralign - 1); + s->sh_offset = file_offset; + if (s->sh_type != SHT_NOBITS) + file_offset += s->sh_size; + } + return file_offset; +} + +/* Output an elf .o file */ +static int elf_output_obj(TCCState *s1, const char *filename) +{ + int ret, file_offset; + int *sec_order; + s1->nb_errors = 0; + + /* Allocate strings for section names */ + alloc_sec_names(s1, 1); + + /* this array is used to reorder sections in the output file */ + sec_order = tcc_malloc(sizeof(int) * s1->nb_sections); + sec_order[0] = 0; + file_offset = layout_any_sections(s1, sizeof (ElfW(Ehdr)), sec_order + 1, 1); + + /* Create the ELF file with name 'filename' */ + ret = tcc_write_elf_file(s1, filename, 0, NULL, file_offset, sec_order); + tcc_free(sec_order); + return ret; +} LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) { - int ret; + if (s->output_type == TCC_OUTPUT_OBJ) + return elf_output_obj(s, filename); #ifdef TCC_TARGET_PE - if (s->output_type != TCC_OUTPUT_OBJ) { - ret = pe_output_file(s, filename); - } else + return pe_output_file(s, filename); #elif TCC_TARGET_MACHO - if (s->output_type != TCC_OUTPUT_OBJ) { - ret = macho_output_file(s, filename); - } else + return macho_output_file(s, filename); +#else + return elf_output_file(s, filename); #endif - ret = elf_output_file(s, filename); - return ret; } ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) { diff --git a/tests/Makefile b/tests/Makefile index 445bfeec..1b0efad7 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -53,7 +53,7 @@ ifeq ($(ARCH),arm) # of functions via bit masking comes out as 1. Just disable thumb. test.ref: CFLAGS+=-marm endif -ifeq ($(ARCH),i386) +ifeq ($(ARCH)$(CONFIG_WIN32),i386) # tcctest.c:get_asm_string uses a construct that is checked too strictly # by GCC in 32bit mode when PIC is enabled. test.ref: CFLAGS+=-fno-PIC -fno-PIE -Wl,-z,notext