From 312d28b0a8ab206601375606778e221985b130f7 Mon Sep 17 00:00:00 2001 From: grischka Date: Fri, 25 Nov 2022 11:58:29 +0100 Subject: [PATCH] tccelf: avoid find_section() for known section - remove calls to "find_..." for stuff that we know to exist and where. - rename find_section_create(s1,name,0) -> have_section(s1,name) Also: - call update_gnu_hash() from elf_output_file() gnu_hasn() functions could be moved down into an already existing !ELF_OBJ_ONLY clause, but in order to avoid too many diff lines I didn't. - avoid 'long' (elf_hash). sizeof (long) is host-dependent (4 or 8) - remove unnecessary checks (for dynsym, versym). Someone reading "if (dynsym == NULL) ..." must conclude that it actually can happen under certain circumstances, or otherwise, might conclude that the person who wrote that felt unsure what's going on exactly. arm64-gen.c: TCC_TARGET_MACHO instead of __APPLE__ (to support cross-compilers for the apple/M1 target) --- arm64-gen.c | 16 ++++----- tccelf.c | 100 ++++++++++++++++++++++------------------------------ 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/arm64-gen.c b/arm64-gen.c index 55163d8b7..764493375 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -53,7 +53,7 @@ #include ST_DATA const char * const target_machine_defs = -#if defined(__APPLE__) +#if defined(TCC_TARGET_MACHO) "__aarch64__\0" "__arm64__\0" #else @@ -829,7 +829,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l else size = type_size(type[i], &align); -#if defined(__APPLE__) +#if defined(TCC_TARGET_MACHO) if (variadic && i == variadic) { nx = 8; nv = 8; @@ -1202,7 +1202,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0, n - 1, t, a); -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) if (variadic) { use_x8 = 1; last_int = 4; @@ -1304,7 +1304,7 @@ ST_FUNC void gen_va_start(void) o(0x910383be); // add x30,x29,#224 o(0xf900001e | r << 5); // str x30,[x(r)] -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) if (arm64_func_va_list_gr_offs) { if (arm64_func_va_list_stack) o(0x910383be); // add x30,x29,#224 @@ -1345,7 +1345,7 @@ ST_FUNC void gen_va_arg(CType *t) if (!hfa) { uint32_t n = size > 16 ? 8 : (size + 7) & -8; -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs if (align == 16) { assert(0); // this path untested but needed for __uint128_t @@ -1358,7 +1358,7 @@ ST_FUNC void gen_va_arg(CType *t) o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n) o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) o(0x14000004); // b .+16 o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top @@ -1369,7 +1369,7 @@ ST_FUNC void gen_va_arg(CType *t) } else { uint32_t ssz = (size + 7) & -(uint32_t)8; -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) uint32_t rsz = hfa << 4; uint32_t b1, b2; o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs @@ -1383,7 +1383,7 @@ ST_FUNC void gen_va_arg(CType *t) } o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz) o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack -#if !defined(__APPLE__) +#if !defined(TCC_TARGET_MACHO) b2 = ind; o(0x14000000); // b lab2 // lab1: write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3); diff --git a/tccelf.c b/tccelf.c index 8e78763a9..dd3d6be68 100644 --- a/tccelf.c +++ b/tccelf.c @@ -325,7 +325,7 @@ static void section_reserve(Section *sec, unsigned long size) } #endif -static Section *find_section_create (TCCState *s1, const char *name, int create) +static Section *have_section(TCCState *s1, const char *name) { Section *sec; int i; @@ -334,15 +334,18 @@ static Section *find_section_create (TCCState *s1, const char *name, int create) if (!strcmp(name, sec->name)) return sec; } - /* sections are created as PROGBITS */ - return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL; + return NULL; } /* return a reference to a section, and create it if it does not exists */ ST_FUNC Section *find_section(TCCState *s1, const char *name) { - return find_section_create (s1, name, 1); + Section *sec = have_section(s1, name); + if (sec) + return sec; + /* sections are created as PROGBITS */ + return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); } /* ------------------------------------------------------------------------- */ @@ -360,9 +363,9 @@ ST_FUNC int put_elf_str(Section *s, const char *sym) } /* elf symbol hashing function */ -static unsigned long elf_hash(const unsigned char *name) +static ElfW(Word) elf_hash(const unsigned char *name) { - unsigned long h = 0, g; + ElfW(Word) h = 0, g; while (*name) { h = (h << 4) + *name++; @@ -374,16 +377,6 @@ static unsigned long elf_hash(const unsigned char *name) return h; } -static unsigned long elf_gnu_hash (const unsigned char *name) -{ - unsigned long h = 5381; - unsigned char c; - - while ((c = *name++)) - h = h * 33 + c; - return h; -} - /* rebuild hash table of section s */ /* NOTE: we do factorize the hash table code to go faster */ static void rebuild_hash(Section *s, unsigned int nb_buckets) @@ -863,12 +856,11 @@ static void sort_syms(TCCState *s1, Section *s) tcc_free(old_to_new_syms); } +#ifndef ELF_OBJ_ONLY /* See: https://flapenguin.me/elf-dt-gnu-hash */ - #define ELFCLASS_BITS (PTR_SIZE * 8) -#ifndef ELF_OBJ_ONLY -static void create_gnu_hash(TCCState *s1) +static Section *create_gnu_hash(TCCState *s1) { int nb_syms, i, ndef, nbuckets, symoffset, bloom_size, bloom_shift; ElfW(Sym) *p; @@ -876,9 +868,6 @@ static void create_gnu_hash(TCCState *s1) Section *dynsym = s1->dynsym; Elf32_Word *ptr; - if (dynsym == NULL) - return; - gnu_hash = new_section(s1, ".gnu.hash", SHT_GNU_HASH, SHF_ALLOC); gnu_hash->link = dynsym->hash->link; @@ -905,17 +894,26 @@ static void create_gnu_hash(TCCState *s1) ptr[1] = symoffset; ptr[2] = bloom_size; ptr[3] = bloom_shift; + return gnu_hash; } -#endif -static void update_gnu_hash(TCCState *s1) +static Elf32_Word elf_gnu_hash (const unsigned char *name) +{ + Elf32_Word h = 5381; + unsigned char c; + + while ((c = *name++)) + h = h * 33 + c; + return h; +} + +static void update_gnu_hash(TCCState *s1, Section *gnu_hash) { int *old_to_new_syms; ElfW(Sym) *new_syms; int nb_syms, i, nbuckets, bloom_size, bloom_shift; ElfW(Sym) *p, *q; Section *vs; - Section *gnu_hash; Section *dynsym = s1->dynsym; Elf32_Word *ptr, *buckets, *chain, *hash; unsigned int *nextbuck; @@ -923,13 +921,6 @@ static void update_gnu_hash(TCCState *s1) unsigned char *strtab; struct { int first, last; } *buck; - if (dynsym == NULL) - return; - - gnu_hash = find_section_create(s1, ".gnu.hash", 0); - if (gnu_hash == NULL) - return; - strtab = dynsym->link->data; nb_syms = dynsym->data_offset / sizeof(ElfW(Sym)); new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); @@ -1012,11 +1003,11 @@ static void update_gnu_hash(TCCState *s1) modify_reloctions_old_to_new(s1, dynsym, old_to_new_syms); /* modify the versions */ - vs = find_section_create(s1, ".gnu.version", 0); + vs = versym_section; if (vs) { ElfW(Half) *newver, *versym = (ElfW(Half) *)vs->data; - if (versym) { + if (1/*versym*/) { newver = tcc_malloc(nb_syms * sizeof(*newver)); for (i = 0; i < nb_syms; i++) newver[old_to_new_syms[i]] = versym[i]; @@ -1031,6 +1022,7 @@ static void update_gnu_hash(TCCState *s1) ptr = (Elf32_Word *) dynsym->hash->data; rebuild_hash(dynsym, ptr[0]); } +#endif /* ELF_OBJ_ONLY */ /* relocate symbol table, resolve undefined symbols if do_resolve is true and output error if undefined symbol. */ @@ -1043,6 +1035,8 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) for_each_elem(symtab, 1, sym, ElfW(Sym)) { sh_num = sym->st_shndx; if (sh_num == SHN_UNDEF) { + if (do_resolve == 2) /* relocating dynsym */ + continue; name = (char *) s1->symtab->link->data + sym->st_name; /* Use ld.so to resolve symbol for us (for tcc -run) */ if (do_resolve) { @@ -1486,7 +1480,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) Section *s; addr_t end_offset; char buf[1024]; - s = find_section_create(s1, section_name, 0); + s = have_section(s1, section_name); if (!s || !(s->sh_flags & SHF_ALLOC)) { end_offset = 0; s = data_section; @@ -2067,6 +2061,7 @@ struct dyn_inf { int phnum; Section *interp; Section *note; + Section *gnu_hash; /* read only segment mapping for GNU_RELRO */ Section _roinf, *roinf; @@ -2352,12 +2347,8 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) Section *s; /* put dynamic section entries */ - s = find_section_create (s1, ".hash", 0); - if (s && s->sh_flags == SHF_ALLOC) - put_dt(dynamic, DT_HASH, s->sh_addr); - s = find_section_create (s1, ".gnu.hash", 0); - if (s && s->sh_flags == SHF_ALLOC) - put_dt(dynamic, DT_GNU_HASH, s->sh_addr); + put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); + put_dt(dynamic, DT_GNU_HASH, dyninf->gnu_hash->sh_addr); put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); @@ -2391,26 +2382,26 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); } - s = find_section_create (s1, ".preinit_array", 0); + s = have_section(s1, ".preinit_array"); if (s && s->data_offset) { put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); } - s = find_section_create (s1, ".init_array", 0); + s = have_section(s1, ".init_array"); if (s && s->data_offset) { put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); } - s = find_section_create (s1, ".fini_array", 0); + s = have_section(s1, ".fini_array"); if (s && s->data_offset) { put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); } - s = find_section_create (s1, ".init", 0); + s = have_section(s1, ".init"); if (s && s->data_offset) { put_dt(dynamic, DT_INIT, s->sh_addr); } - s = find_section_create (s1, ".fini", 0); + s = have_section(s1, ".fini"); if (s && s->data_offset) { put_dt(dynamic, DT_FINI, s->sh_addr); } @@ -2530,7 +2521,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); sort_syms(s1, symtab_section); - update_gnu_hash(s1); + for(i = 1; i < shnum; i++) { s = s1->sections[sec_order ? sec_order[i] : i]; if (s->sh_type != SHT_NOBITS) { @@ -2811,7 +2802,7 @@ static int elf_output_file(TCCState *s1, const char *filename) /* shared library case: simply export all global symbols */ export_global_syms(s1); } - create_gnu_hash(s1); + dyninf.gnu_hash = create_gnu_hash(s1); } else { build_got_entries(s1, 0); } @@ -2863,21 +2854,13 @@ static int elf_output_file(TCCState *s1, const char *filename) file_offset = layout_sections(s1, sec_order, &dyninf); if (dynamic) { - ElfW(Sym) *sym; - /* put in GOT the dynamic section address and relocate PLT */ write32le(s1->got->data, dynamic->sh_addr); if (file_type == TCC_OUTPUT_EXE || (RELOCATE_DLLPLT && (file_type & TCC_OUTPUT_DYN))) relocate_plt(s1); - /* relocate symbols in .dynsym now that final addresses are known */ - for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) { - /* do symbol relocation */ - sym->st_value += s1->sections[sym->st_shndx]->sh_addr; - } - } + relocate_syms(s1, s1->dynsym, 2); } /* if building executable or DLL, then relocate each section @@ -2897,6 +2880,9 @@ static int elf_output_file(TCCState *s1, const char *filename) else if (s1->got) fill_local_got_entries(s1); + if (dyninf.gnu_hash) + update_gnu_hash(s1, dyninf.gnu_hash); + /* Create the ELF file with name 'filename' */ ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order); the_end: