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.
This commit is contained in:
grischka 2021-01-12 15:13:30 +01:00
parent c74c6ed61a
commit 62c0c4c77a
4 changed files with 156 additions and 145 deletions

View file

@ -62,10 +62,6 @@ else
endif endif
export MACOSX_DEPLOYMENT_TARGET := 10.6 export MACOSX_DEPLOYMENT_TARGET := 10.6
endif endif
# Unclear why the following ifdef was defined. Build fails on all *BSD
# ifdef CONFIG_BSD
# NATIVE_TARGET = $(ARCH)-$(TARGETOS)
# endif
endif endif
# run local version of tcc with local libraries and includes # run local version of tcc with local libraries and includes

View file

@ -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 */ /* OpenBSD only has suffixed .so files; e.g., libc.so.96.0 */
/* So we must process that */ /* So we must process that */
#if defined TARGETOS_OpenBSD #if defined TARGETOS_OpenBSD && !defined _WIN32/* no dirent */
#include <dirent.h> #include <dirent.h>
ST_FUNC char *tcc_openbsd_library_soversion(TCCState *s, const char *libraryname) 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 #elif defined TCC_TARGET_MACHO
const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL }; const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL };
const char **pp = s->static_link ? libs + 1 : libs; 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 const char *libs[] = { s->static_link
? NULL ? NULL
/* find exact versionned .so.x.y name as no /* 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; s->filetype |= AFF_WHOLE_ARCHIVE;
else else
s->filetype &= ~AFF_WHOLE_ARCHIVE; s->filetype &= ~AFF_WHOLE_ARCHIVE;
} else if (ret = link_option(option, "z=", &p), ret) { } else if (link_option(option, "z=", &p)) {
if (!strcmp(p, "notext")) ignoring = 1;
; /* ignore */
else
goto err;
} else if (p) { } else if (p) {
return 0; return 0;
} else { } else {

284
tccelf.c
View file

@ -1071,11 +1071,6 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
break; break;
} }
} }
if (count) {
/* allocate the section */
sr->sh_flags |= SHF_ALLOC;
sr->sh_size = count * sizeof(ElfW_Rel);
}
#endif #endif
return count; return count;
} }
@ -1566,29 +1561,8 @@ ST_FUNC void resolve_common_syms(TCCState *s1)
tcc_add_linker_symbols(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;i<s1->nb_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 #ifndef ELF_OBJ_ONLY
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
{ {
int sym_index = ELFW(R_SYM) (rel->r_info); 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 /* decide if an unallocated section should be output. */
should be output. static int set_sec_sizes(TCCState *s1)
NOTE: the strsec section comes last, so its size is also correct ! */
static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
{ {
int i; int i;
Section *s; Section *s;
int textrel = 0; int textrel = 0;
int file_type = s1->output_type;
/* Allocate strings for section names */ /* Allocate strings for section names */
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
/* when generating a DLL, we include relocations but we may if (s->sh_type == SHT_RELX && !(s->sh_flags & SHF_ALLOC)) {
patch them */ /* when generating a DLL, we include relocations but
#ifndef ELF_OBJ_ONLY we may patch them */
if (file_type == TCC_OUTPUT_DLL && if (file_type == TCC_OUTPUT_DLL
s->sh_type == SHT_RELX && && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) {
!(s->sh_flags & SHF_ALLOC) && int count = prepare_dynamic_rel(s1, s);
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && if (count) {
prepare_dynamic_rel(s1, s)) { /* allocate the section */
if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) s->sh_flags |= SHF_ALLOC;
textrel = 1; s->sh_size = count * sizeof(ElfW_Rel);
} else if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
#endif textrel = 1;
if ((s1->do_debug && s->sh_type != SHT_RELX) || }
file_type == TCC_OUTPUT_OBJ || }
(s->sh_flags & SHF_ALLOC) || } else if ((s->sh_flags & SHF_ALLOC)
i == (s1->nb_sections - 1)
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
|| s->sh_type == SHT_ARM_ATTRIBUTES || s->sh_type == SHT_ARM_ATTRIBUTES
#endif #endif
) { || s1->do_debug) {
/* we output all sections if debug or object file */
s->sh_size = s->data_offset; s->sh_size = s->data_offset;
} }
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
/* XXX: Suppress stack unwinding section. */ /* XXX: Suppress stack unwinding section. */
if (s->sh_type == SHT_ARM_EXIDX) { 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; s->sh_size = 0;
} }
#endif #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; return textrel;
} }
/* Info to be copied in dynamic section */ /* Info to be copied in dynamic section */
struct dyn_inf { struct dyn_inf {
Section *dynamic; Section *dynamic;
@ -1858,23 +1828,29 @@ struct ro_inf {
addr_t sh_size; 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 /* Assign sections to segments and decide how are sections laid out when loaded
in memory. This function also fills corresponding program headers. */ in memory. This function also fills corresponding program headers. */
static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
int phnum, int phfill, int phnum, int phfill,
Section *interp, Section* strsec, Section *interp,
struct ro_inf *roinf, int *sec_order) struct ro_inf *roinf, int *sec_order)
{ {
int i, sh_order_index, file_offset; int i, file_offset;
Section *s; Section *s;
sh_order_index = 1;
file_offset = 0; file_offset = 0;
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) if (s1->output_format == TCC_OUTPUT_FORMAT_ELF)
file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); 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; unsigned long s_align;
long long tmp; long long tmp;
addr_t addr; addr_t addr;
@ -1979,7 +1955,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
if (k != 5) if (k != 5)
continue; continue;
} }
sec_order[sh_order_index++] = i; *sec_order++ = i;
/* section matches: we align it and add its size */ /* section matches: we align it and add its size */
tmp = addr; tmp = addr;
@ -2039,26 +2015,11 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
} }
} }
} }
#endif /* ELF_OBJ_ONLY */
/* all other sections come after */ /* all other sections come after */
for(i = 1; i < s1->nb_sections; i++) { return layout_any_sections(s1, file_offset, sec_order, 0);
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;
} }
#ifndef ELF_OBJ_ONLY
/* put dynamic tag */ /* put dynamic tag */
static void put_dt(Section *dynamic, int dt, addr_t val) 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. /* Create an ELF file on disk.
This function handle ELF specific layout requirements */ 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;i<s1->nb_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 */ /* Write an elf, coff or "binary" file */
static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
ElfW(Phdr) *phdr, int file_offset, int *sec_order) 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; s1->nb_sections = nnew;
tcc_free(backmap); tcc_free(backmap);
} }
#endif
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
static void create_arm_attribute_section(TCCState *s1) 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 dyn_inf dyninf = {0};
struct ro_inf roinf; struct ro_inf roinf;
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
Section *strsec, *interp, *dynamic, *dynstr, *note = NULL; Section *interp, *dynamic, *dynstr, *note;
//#ifndef ELF_OBJ_ONLY
struct ro_inf *roinf_use = NULL; struct ro_inf *roinf_use = NULL;
//#endif int textrel;
file_type = s1->output_type; 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; s1->nb_errors = 0;
ret = -1; ret = -1;
phdr = NULL; phdr = NULL;
sec_order = NULL; sec_order = NULL;
interp = dynamic = dynstr = NULL; /* avoid warning */ interp = dynamic = dynstr = note = NULL;
#ifndef ELF_OBJ_ONLY #ifdef TCC_TARGET_ARM
if (file_type != TCC_OUTPUT_OBJ) { 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.) */ /* if linking, also link in runtime libraries (libc, libgcc, etc.) */
tcc_add_runtime(s1); tcc_add_runtime(s1);
resolve_common_syms(s1); resolve_common_syms(s1);
@ -2612,17 +2592,11 @@ static int elf_output_file(TCCState *s1, const char *filename)
build_got_entries(s1); build_got_entries(s1);
version_add (s1); version_add (s1);
} }
#endif
/* we add a section for symbols */ textrel = set_sec_sizes(s1);
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); alloc_sec_names(s1, 0);
put_elf_str(strsec, "");
/* Allocate strings for section names */ if (!s1->static_link) {
ret = alloc_sec_names(s1, file_type, strsec);
#ifndef ELF_OBJ_ONLY
if (dynamic) {
int i; int i;
/* add a list of needed dlls */ /* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) { 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)); put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
/* XXX: currently, since we do not handle PIC code, we /* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */ must relocate the readonly segments */
if (ret) if (textrel)
put_dt(dynamic, DT_TEXTREL, 0); 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; dynamic->sh_size = dynamic->data_offset;
dynstr->sh_size = dynstr->data_offset; dynstr->sh_size = dynstr->data_offset;
} }
#endif
for (i = 1; i < s1->nb_sections && for (i = 1; i < s1->nb_sections &&
!(s1->sections[i]->sh_flags & SHF_TLS); i++); !(s1->sections[i]->sh_flags & SHF_TLS); i++);
phfill = 2 + (i < s1->nb_sections); phfill = 2 + (i < s1->nb_sections);
/* compute number of program headers */ /* compute number of program headers */
if (file_type == TCC_OUTPUT_OBJ) if (file_type == TCC_OUTPUT_DLL)
phnum = phfill = 0;
else if (file_type == TCC_OUTPUT_DLL)
phnum = 3; phnum = 3;
else if (s1->static_link) else if (s1->static_link)
phnum = 3; phnum = 3;
@ -2673,31 +2644,25 @@ static int elf_output_file(TCCState *s1, const char *filename)
} }
phnum += note != NULL; phnum += note != NULL;
#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD
#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32)
/* GNU_RELRO */ /* GNU_RELRO */
if (file_type != TCC_OUTPUT_OBJ) phnum++, roinf_use = &roinf;
phnum++, roinf_use = &roinf;
#endif #endif
/* allocate program segment headers */ /* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
/* compute number of sections */ /* compute number of sections */
shnum = s1->nb_sections; shnum = s1->nb_sections;
/* this array is used to reorder sections in the output file */ /* this array is used to reorder sections in the output file */
sec_order = tcc_malloc(sizeof(int) * shnum); sec_order = tcc_malloc(sizeof(int) * shnum);
sec_order[0] = 0; sec_order[0] = 0;
/* compute section to program header mapping */ /* compute section to program header mapping */
file_offset = layout_sections(s1, phdr, phnum, phfill, interp, strsec, file_offset = layout_sections(s1, phdr, phnum, phfill, interp, &roinf, sec_order + 1);
&roinf, sec_order);
#ifndef ELF_OBJ_ONLY
/* Fill remaining program header and finalize relocation related to dynamic /* Fill remaining program header and finalize relocation related to dynamic
linking. */ linking. */
if (file_type != TCC_OUTPUT_OBJ) { {
fill_unloadable_phdr(phdr, phnum, interp, dynamic, note, roinf_use); fill_unloadable_phdr(phdr, phnum, interp, dynamic, note, roinf_use);
if (dynamic) { if (dynamic) {
ElfW(Sym) *sym; ElfW(Sym) *sym;
@ -2735,32 +2700,85 @@ static int elf_output_file(TCCState *s1, const char *filename)
else if (s1->got) else if (s1->got)
fill_local_got_entries(s1); fill_local_got_entries(s1);
} }
#endif
/* Create the ELF file with name 'filename' */ /* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
s1->nb_sections = shnum; s1->nb_sections = shnum;
goto the_end;
the_end: the_end:
tcc_free(sec_order); tcc_free(sec_order);
tcc_free(phdr); tcc_free(phdr);
return ret; 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) 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 #ifdef TCC_TARGET_PE
if (s->output_type != TCC_OUTPUT_OBJ) { return pe_output_file(s, filename);
ret = pe_output_file(s, filename);
} else
#elif TCC_TARGET_MACHO #elif TCC_TARGET_MACHO
if (s->output_type != TCC_OUTPUT_OBJ) { return macho_output_file(s, filename);
ret = macho_output_file(s, filename); #else
} else return elf_output_file(s, filename);
#endif #endif
ret = elf_output_file(s, filename);
return ret;
} }
ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) { ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) {

View file

@ -53,7 +53,7 @@ ifeq ($(ARCH),arm)
# of functions via bit masking comes out as 1. Just disable thumb. # of functions via bit masking comes out as 1. Just disable thumb.
test.ref: CFLAGS+=-marm test.ref: CFLAGS+=-marm
endif endif
ifeq ($(ARCH),i386) ifeq ($(ARCH)$(CONFIG_WIN32),i386)
# tcctest.c:get_asm_string uses a construct that is checked too strictly # tcctest.c:get_asm_string uses a construct that is checked too strictly
# by GCC in 32bit mode when PIC is enabled. # by GCC in 32bit mode when PIC is enabled.
test.ref: CFLAGS+=-fno-PIC -fno-PIE -Wl,-z,notext test.ref: CFLAGS+=-fno-PIC -fno-PIE -Wl,-z,notext