tccelf: avoid lookup of _GLOBAL_OFFSET_TABLE_

Instead, return its symbol index from build_got_entries()
Also, copy dynamic symbols later when size of _GLOBAL_OFFSET_TABLE_
was already set and handle -rdynamic there too.
See commit 4c82b00342

5 insertions(+), 5 deletions(-)
This commit is contained in:
grischka 2022-05-28 20:59:25 +02:00
parent c81519e1c4
commit 7d6979d452
3 changed files with 35 additions and 46 deletions

2
tcc.h
View file

@ -1567,7 +1567,7 @@ enum gotplt_entry {
#if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE #if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr);
ST_FUNC void relocate_plt(TCCState *s1); ST_FUNC void relocate_plt(TCCState *s1);
ST_FUNC void build_got_entries(TCCState *s1); /* in tccelf.c */ ST_FUNC void build_got_entries(TCCState *s1, int got_sym); /* in tccelf.c */
#define NEED_BUILD_GOT #define NEED_BUILD_GOT
#endif #endif

View file

@ -1039,15 +1039,15 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
#endif #endif
#ifdef NEED_BUILD_GOT #ifdef NEED_BUILD_GOT
static void build_got(TCCState *s1) static int build_got(TCCState *s1)
{ {
/* if no got, then create it */ /* if no got, then create it */
s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
s1->got->sh_entsize = 4; s1->got->sh_entsize = 4;
set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_");
/* keep space for _DYNAMIC pointer and two dummy got entries */ /* keep space for _DYNAMIC pointer and two dummy got entries */
section_ptr_add(s1->got, 3 * PTR_SIZE); section_ptr_add(s1->got, 3 * PTR_SIZE);
return set_elf_sym(symtab_section, 0, 0, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_");
} }
/* Create a GOT and (for function call) a PLT entry corresponding to a symbol /* Create a GOT and (for function call) a PLT entry corresponding to a symbol
@ -1152,7 +1152,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
/* build GOT and PLT entries */ /* build GOT and PLT entries */
/* Two passes because R_JMP_SLOT should become first. Some targets /* Two passes because R_JMP_SLOT should become first. Some targets
(arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */ (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */
ST_FUNC void build_got_entries(TCCState *s1) ST_FUNC void build_got_entries(TCCState *s1, int got_sym)
{ {
Section *s; Section *s;
ElfW_Rel *rel; ElfW_Rel *rel;
@ -1160,7 +1160,6 @@ ST_FUNC void build_got_entries(TCCState *s1)
int i, type, gotplt_entry, reloc_type, sym_index; int i, type, gotplt_entry, reloc_type, sym_index;
struct sym_attr *attr; struct sym_attr *attr;
int pass = 0; int pass = 0;
redo: redo:
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
@ -1252,7 +1251,7 @@ redo:
} }
if (!s1->got) if (!s1->got)
build_got(s1); got_sym = build_got(s1);
if (gotplt_entry == BUILD_GOT_ONLY) if (gotplt_entry == BUILD_GOT_ONLY)
continue; continue;
@ -1265,11 +1264,11 @@ redo:
} }
if (++pass < 2) if (++pass < 2)
goto redo; goto redo;
/* .rel.plt refers to .got actually */ /* .rel.plt refers to .got actually */
if (s1->plt && s1->plt->reloc) if (s1->plt && s1->plt->reloc)
s1->plt->reloc->sh_info = s1->got->sh_num; s1->plt->reloc->sh_info = s1->got->sh_num;
if (got_sym) /* set size */
((ElfW(Sym)*)symtab_section->data)[got_sym].st_size = s1->got->data_offset;
} }
#endif /* def NEED_BUILD_GOT */ #endif /* def NEED_BUILD_GOT */
@ -1681,8 +1680,7 @@ static void fill_local_got_entries(TCCState *s1)
} }
/* Bind symbols of executable: resolve undefined symbols from exported symbols /* Bind symbols of executable: resolve undefined symbols from exported symbols
in shared libraries and export non local defined symbols to shared libraries in shared libraries */
if -rdynamic switch was given on command line */
static void bind_exe_dynsyms(TCCState *s1) static void bind_exe_dynsyms(TCCState *s1)
{ {
const char *name; const char *name;
@ -1755,11 +1753,6 @@ static void bind_exe_dynsyms(TCCState *s1)
tcc_error_noabort("undefined symbol '%s'", name); tcc_error_noabort("undefined symbol '%s'", name);
} }
} }
} else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
name = (char *) symtab_section->link->data + sym->st_name;
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
0, sym->st_shndx, name);
} }
} }
} }
@ -1768,25 +1761,28 @@ static void bind_exe_dynsyms(TCCState *s1)
are referenced by shared libraries. The reason is that the dynamic loader are referenced by shared libraries. The reason is that the dynamic loader
search symbol first in executable and then in libraries. Therefore a search symbol first in executable and then in libraries. Therefore a
reference to a symbol already defined by a library can still be resolved by reference to a symbol already defined by a library can still be resolved by
a symbol in the executable. */ a symbol in the executable. With -rdynamic, export all defined symbols */
static void bind_libs_dynsyms(TCCState *s1) static void bind_libs_dynsyms(TCCState *s1)
{ {
const char *name; const char *name;
int sym_index; int dynsym_index;
ElfW(Sym) *sym, *esym; ElfW(Sym) *sym, *esym;
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
name = (char *) s1->dynsymtab_section->link->data + esym->st_name; name = (char *)symtab_section->link->data + sym->st_name;
sym_index = find_elf_sym(symtab_section, name); dynsym_index = find_elf_sym(s1->dynsymtab_section, name);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; if (sym->st_shndx != SHN_UNDEF
if (sym_index && sym->st_shndx != SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, if (dynsym_index || s1->rdynamic)
sym->st_info, 0, sym->st_shndx, name); set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
} else if (esym->st_shndx == SHN_UNDEF) { sym->st_info, 0, sym->st_shndx, name);
/* weak symbols can stay undefined */ } else if (dynsym_index) {
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) esym = (ElfW(Sym) *)s1->dynsymtab_section->data + dynsym_index;
tcc_warning("undefined dynamic symbol '%s'", name); if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name);
}
} }
} }
} }
@ -1800,11 +1796,10 @@ static void export_global_syms(TCCState *s1)
int dynindex, index; int dynindex, index;
const char *name; const char *name;
ElfW(Sym) *sym; ElfW(Sym) *sym;
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
name = (char *) symtab_section->link->data + sym->st_name; name = (char *) symtab_section->link->data + sym->st_name;
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, dynindex = set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name); sym->st_info, 0, sym->st_shndx, name);
index = sym - (ElfW(Sym) *) symtab_section->data; index = sym - (ElfW(Sym) *) symtab_section->data;
get_sym_attr(s1, index, 1)->dyn_index = dynindex; get_sym_attr(s1, index, 1)->dyn_index = dynindex;
@ -2532,13 +2527,7 @@ static Section *create_bsd_note_section(TCCState *s1,
} }
#endif #endif
static void elf_patch_global_offset_size(TCCState *s1, Section *s) static void alloc_sec_names(TCCState *s1, int is_obj);
{
int sym_index;
if (s && (sym_index = find_elf_sym(s, "_GLOBAL_OFFSET_TABLE_")))
((ElfW(Sym) *)s->data)[sym_index].st_size = s1->got->data_offset;
}
/* Output an elf, coff or binary file */ /* Output an elf, coff or binary file */
/* XXX: suppress unneeded sections */ /* XXX: suppress unneeded sections */
@ -2550,7 +2539,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
Section *interp, *dynamic, *dynstr, *note; Section *interp, *dynamic, *dynstr, *note;
struct ro_inf *roinf_use = NULL; struct ro_inf *roinf_use = NULL;
int textrel; int textrel, got_sym;
file_type = s1->output_type; file_type = s1->output_type;
s1->nb_errors = 0; s1->nb_errors = 0;
@ -2603,22 +2592,22 @@ static int elf_output_file(TCCState *s1, const char *filename)
dynamic->link = dynstr; dynamic->link = dynstr;
dynamic->sh_entsize = sizeof(ElfW(Dyn)); dynamic->sh_entsize = sizeof(ElfW(Dyn));
if (!s1->got) got_sym = build_got(s1);
build_got(s1);
if (file_type == TCC_OUTPUT_EXE) { if (file_type == TCC_OUTPUT_EXE) {
bind_exe_dynsyms(s1); bind_exe_dynsyms(s1);
if (s1->nb_errors) if (s1->nb_errors)
goto the_end; goto the_end;
}
build_got_entries(s1, got_sym);
if (file_type == TCC_OUTPUT_EXE) {
bind_libs_dynsyms(s1); bind_libs_dynsyms(s1);
} else { } else {
/* shared library case: simply export all global symbols */ /* shared library case: simply export all global symbols */
export_global_syms(s1); export_global_syms(s1);
} }
} else {
build_got_entries(s1, 0);
} }
build_got_entries(s1);
elf_patch_global_offset_size(s1, symtab_section);
elf_patch_global_offset_size(s1, s1->dynsym);
version_add (s1); version_add (s1);
} }

View file

@ -261,7 +261,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
#else #else
tcc_add_runtime(s1); tcc_add_runtime(s1);
resolve_common_syms(s1); resolve_common_syms(s1);
build_got_entries(s1); build_got_entries(s1, 0);
#endif #endif
if (s1->nb_errors) if (s1->nb_errors)
return -1; return -1;