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)
This commit is contained in:
grischka 2022-11-25 11:58:29 +01:00
parent 28fa4d3db6
commit 312d28b0a8
2 changed files with 51 additions and 65 deletions

View File

@ -53,7 +53,7 @@
#include <assert.h> #include <assert.h>
ST_DATA const char * const target_machine_defs = ST_DATA const char * const target_machine_defs =
#if defined(__APPLE__) #if defined(TCC_TARGET_MACHO)
"__aarch64__\0" "__aarch64__\0"
"__arm64__\0" "__arm64__\0"
#else #else
@ -829,7 +829,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
else else
size = type_size(type[i], &align); size = type_size(type[i], &align);
#if defined(__APPLE__) #if defined(TCC_TARGET_MACHO)
if (variadic && i == variadic) { if (variadic && i == variadic) {
nx = 8; nx = 8;
nv = 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); 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) { if (variadic) {
use_x8 = 1; use_x8 = 1;
last_int = 4; last_int = 4;
@ -1304,7 +1304,7 @@ ST_FUNC void gen_va_start(void)
o(0x910383be); // add x30,x29,#224 o(0x910383be); // add x30,x29,#224
o(0xf900001e | r << 5); // str x30,[x(r)] 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_gr_offs) {
if (arm64_func_va_list_stack) if (arm64_func_va_list_stack)
o(0x910383be); // add x30,x29,#224 o(0x910383be); // add x30,x29,#224
@ -1345,7 +1345,7 @@ ST_FUNC void gen_va_arg(CType *t)
if (!hfa) { if (!hfa) {
uint32_t n = size > 16 ? 8 : (size + 7) & -8; 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 o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs
if (align == 16) { if (align == 16) {
assert(0); // this path untested but needed for __uint128_t 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(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n) o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
#if !defined(__APPLE__) #if !defined(TCC_TARGET_MACHO)
o(0x14000004); // b .+16 o(0x14000004); // b .+16
o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs 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 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 { else {
uint32_t ssz = (size + 7) & -(uint32_t)8; uint32_t ssz = (size + 7) & -(uint32_t)8;
#if !defined(__APPLE__) #if !defined(TCC_TARGET_MACHO)
uint32_t rsz = hfa << 4; uint32_t rsz = hfa << 4;
uint32_t b1, b2; uint32_t b1, b2;
o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs 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(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
#if !defined(__APPLE__) #if !defined(TCC_TARGET_MACHO)
b2 = ind; o(0x14000000); // b lab2 b2 = ind; o(0x14000000); // b lab2
// lab1: // lab1:
write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3); write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3);

100
tccelf.c
View File

@ -325,7 +325,7 @@ static void section_reserve(Section *sec, unsigned long size)
} }
#endif #endif
static Section *find_section_create (TCCState *s1, const char *name, int create) static Section *have_section(TCCState *s1, const char *name)
{ {
Section *sec; Section *sec;
int i; int i;
@ -334,15 +334,18 @@ static Section *find_section_create (TCCState *s1, const char *name, int create)
if (!strcmp(name, sec->name)) if (!strcmp(name, sec->name))
return sec; return sec;
} }
/* sections are created as PROGBITS */ return NULL;
return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL;
} }
/* return a reference to a section, and create it if it does not /* return a reference to a section, and create it if it does not
exists */ exists */
ST_FUNC Section *find_section(TCCState *s1, const char *name) 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 */ /* 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) { while (*name) {
h = (h << 4) + *name++; h = (h << 4) + *name++;
@ -374,16 +377,6 @@ static unsigned long elf_hash(const unsigned char *name)
return h; 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 */ /* rebuild hash table of section s */
/* NOTE: we do factorize the hash table code to go faster */ /* NOTE: we do factorize the hash table code to go faster */
static void rebuild_hash(Section *s, unsigned int nb_buckets) 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); tcc_free(old_to_new_syms);
} }
#ifndef ELF_OBJ_ONLY
/* See: https://flapenguin.me/elf-dt-gnu-hash */ /* See: https://flapenguin.me/elf-dt-gnu-hash */
#define ELFCLASS_BITS (PTR_SIZE * 8) #define ELFCLASS_BITS (PTR_SIZE * 8)
#ifndef ELF_OBJ_ONLY static Section *create_gnu_hash(TCCState *s1)
static void create_gnu_hash(TCCState *s1)
{ {
int nb_syms, i, ndef, nbuckets, symoffset, bloom_size, bloom_shift; int nb_syms, i, ndef, nbuckets, symoffset, bloom_size, bloom_shift;
ElfW(Sym) *p; ElfW(Sym) *p;
@ -876,9 +868,6 @@ static void create_gnu_hash(TCCState *s1)
Section *dynsym = s1->dynsym; Section *dynsym = s1->dynsym;
Elf32_Word *ptr; Elf32_Word *ptr;
if (dynsym == NULL)
return;
gnu_hash = new_section(s1, ".gnu.hash", SHT_GNU_HASH, SHF_ALLOC); gnu_hash = new_section(s1, ".gnu.hash", SHT_GNU_HASH, SHF_ALLOC);
gnu_hash->link = dynsym->hash->link; gnu_hash->link = dynsym->hash->link;
@ -905,17 +894,26 @@ static void create_gnu_hash(TCCState *s1)
ptr[1] = symoffset; ptr[1] = symoffset;
ptr[2] = bloom_size; ptr[2] = bloom_size;
ptr[3] = bloom_shift; 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; int *old_to_new_syms;
ElfW(Sym) *new_syms; ElfW(Sym) *new_syms;
int nb_syms, i, nbuckets, bloom_size, bloom_shift; int nb_syms, i, nbuckets, bloom_size, bloom_shift;
ElfW(Sym) *p, *q; ElfW(Sym) *p, *q;
Section *vs; Section *vs;
Section *gnu_hash;
Section *dynsym = s1->dynsym; Section *dynsym = s1->dynsym;
Elf32_Word *ptr, *buckets, *chain, *hash; Elf32_Word *ptr, *buckets, *chain, *hash;
unsigned int *nextbuck; unsigned int *nextbuck;
@ -923,13 +921,6 @@ static void update_gnu_hash(TCCState *s1)
unsigned char *strtab; unsigned char *strtab;
struct { int first, last; } *buck; 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; strtab = dynsym->link->data;
nb_syms = dynsym->data_offset / sizeof(ElfW(Sym)); nb_syms = dynsym->data_offset / sizeof(ElfW(Sym));
new_syms = tcc_malloc(nb_syms * 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_reloctions_old_to_new(s1, dynsym, old_to_new_syms);
/* modify the versions */ /* modify the versions */
vs = find_section_create(s1, ".gnu.version", 0); vs = versym_section;
if (vs) { if (vs) {
ElfW(Half) *newver, *versym = (ElfW(Half) *)vs->data; ElfW(Half) *newver, *versym = (ElfW(Half) *)vs->data;
if (versym) { if (1/*versym*/) {
newver = tcc_malloc(nb_syms * sizeof(*newver)); newver = tcc_malloc(nb_syms * sizeof(*newver));
for (i = 0; i < nb_syms; i++) for (i = 0; i < nb_syms; i++)
newver[old_to_new_syms[i]] = versym[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; ptr = (Elf32_Word *) dynsym->hash->data;
rebuild_hash(dynsym, ptr[0]); rebuild_hash(dynsym, ptr[0]);
} }
#endif /* ELF_OBJ_ONLY */
/* relocate symbol table, resolve undefined symbols if do_resolve is /* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */ 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)) { for_each_elem(symtab, 1, sym, ElfW(Sym)) {
sh_num = sym->st_shndx; sh_num = sym->st_shndx;
if (sh_num == SHN_UNDEF) { if (sh_num == SHN_UNDEF) {
if (do_resolve == 2) /* relocating dynsym */
continue;
name = (char *) s1->symtab->link->data + sym->st_name; name = (char *) s1->symtab->link->data + sym->st_name;
/* Use ld.so to resolve symbol for us (for tcc -run) */ /* Use ld.so to resolve symbol for us (for tcc -run) */
if (do_resolve) { if (do_resolve) {
@ -1486,7 +1480,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
Section *s; Section *s;
addr_t end_offset; addr_t end_offset;
char buf[1024]; char buf[1024];
s = find_section_create(s1, section_name, 0); s = have_section(s1, section_name);
if (!s || !(s->sh_flags & SHF_ALLOC)) { if (!s || !(s->sh_flags & SHF_ALLOC)) {
end_offset = 0; end_offset = 0;
s = data_section; s = data_section;
@ -2067,6 +2061,7 @@ struct dyn_inf {
int phnum; int phnum;
Section *interp; Section *interp;
Section *note; Section *note;
Section *gnu_hash;
/* read only segment mapping for GNU_RELRO */ /* read only segment mapping for GNU_RELRO */
Section _roinf, *roinf; Section _roinf, *roinf;
@ -2352,12 +2347,8 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
Section *s; Section *s;
/* put dynamic section entries */ /* put dynamic section entries */
s = find_section_create (s1, ".hash", 0); put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
if (s && s->sh_flags == SHF_ALLOC) put_dt(dynamic, DT_GNU_HASH, dyninf->gnu_hash->sh_addr);
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_STRTAB, dyninf->dynstr->sh_addr); put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); 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_VERNEED, verneed_section->sh_addr);
put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); 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) { if (s && s->data_offset) {
put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr);
put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); 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) { if (s && s->data_offset) {
put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr);
put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); 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) { if (s && s->data_offset) {
put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr);
put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); 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) { if (s && s->data_offset) {
put_dt(dynamic, DT_INIT, s->sh_addr); 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) { if (s && s->data_offset) {
put_dt(dynamic, DT_FINI, s->sh_addr); 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)); offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
sort_syms(s1, symtab_section); sort_syms(s1, symtab_section);
update_gnu_hash(s1);
for(i = 1; i < shnum; i++) { for(i = 1; i < shnum; i++) {
s = s1->sections[sec_order ? sec_order[i] : i]; s = s1->sections[sec_order ? sec_order[i] : i];
if (s->sh_type != SHT_NOBITS) { 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 */ /* shared library case: simply export all global symbols */
export_global_syms(s1); export_global_syms(s1);
} }
create_gnu_hash(s1); dyninf.gnu_hash = create_gnu_hash(s1);
} else { } else {
build_got_entries(s1, 0); 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); file_offset = layout_sections(s1, sec_order, &dyninf);
if (dynamic) { if (dynamic) {
ElfW(Sym) *sym;
/* put in GOT the dynamic section address and relocate PLT */ /* put in GOT the dynamic section address and relocate PLT */
write32le(s1->got->data, dynamic->sh_addr); write32le(s1->got->data, dynamic->sh_addr);
if (file_type == TCC_OUTPUT_EXE if (file_type == TCC_OUTPUT_EXE
|| (RELOCATE_DLLPLT && (file_type & TCC_OUTPUT_DYN))) || (RELOCATE_DLLPLT && (file_type & TCC_OUTPUT_DYN)))
relocate_plt(s1); relocate_plt(s1);
/* relocate symbols in .dynsym now that final addresses are known */ /* relocate symbols in .dynsym now that final addresses are known */
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { relocate_syms(s1, s1->dynsym, 2);
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) {
/* do symbol relocation */
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
}
}
} }
/* if building executable or DLL, then relocate each section /* 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) else if (s1->got)
fill_local_got_entries(s1); fill_local_got_entries(s1);
if (dyninf.gnu_hash)
update_gnu_hash(s1, dyninf.gnu_hash);
/* Create the ELF file with name 'filename' */ /* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order); ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order);
the_end: the_end: