elf: Fix last commit

Forgot to mark tccelf.c as to be committed in last commit :-/
master
Michael Matz 2017-05-07 04:52:21 +02:00
parent 680e84fe42
commit 5732a1882e
1 changed files with 53 additions and 7 deletions

View File

@ -906,11 +906,30 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
name = (char *) symtab_section->link->data + sym->st_name;
if (s1->dynsym) {
if (0 == attr->dyn_index)
attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size,
info, 0, sym->st_shndx, name);
put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
attr->dyn_index);
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
/* Hack alarm. We don't want to emit dynamic symbols
and symbol based relocs for STB_LOCAL symbols, but rather
want to resolve them directly. At this point the symbol
values aren't final yet, so we must defer this. We will later
have to create a RELATIVE reloc anyway, so we misuse the
relocation slot to smuggle the symbol reference until
fill_local_got_entries. Not that the sym_index is
relative to symtab_section, not s1->dynsym! Nevertheless
we use s1->dyn_sym so that if this is the first call
that got->reloc is correctly created. Also note that
RELATIVE relocs are not normally created for the .got,
so the types serves as a marker for later (and is retained
also for the final output, which is okay because then the
got is just normal data). */
put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE,
sym_index);
} else {
if (0 == attr->dyn_index)
attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size,
info, 0, sym->st_shndx, name);
put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
attr->dyn_index);
}
} else {
put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type,
sym_index);
@ -1006,8 +1025,9 @@ ST_FUNC void build_got_entries(TCCState *s1)
}
#ifdef TCC_TARGET_X86_64
if (type == R_X86_64_PLT32 &&
ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) {
if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) &&
(ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) {
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
continue;
}
@ -1270,6 +1290,30 @@ ST_FUNC void fill_got(TCCState *s1)
}
}
/* See put_got_entry for a description. This is the second stage
where GOT references to local defined symbols are rewritten. */
static void fill_local_got_entries(TCCState *s1)
{
ElfW_Rel *rel;
for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
int sym_index = ELFW(R_SYM) (rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
unsigned offset = attr->got_offset;
if (offset != rel->r_offset - s1->got->sh_addr)
tcc_error_noabort("huh");
rel->r_info = ELFW(R_INFO)(0, R_RELATIVE);
#if SHT_RELX == SHT_RELA
rel->r_addend = sym->st_value;
#else
/* All our REL architectures also happen to be 32bit LE. */
write32le(s1->got->data + offset, sym->st_value);
#endif
}
}
}
/* Bind symbols of executable: resolve undefined symbols from exported symbols
in shared libraries and export non local defined symbols to shared libraries
if -rdynamic switch was given on command line */
@ -2129,6 +2173,8 @@ static int elf_output_file(TCCState *s1, const char *filename)
/* Perform relocation to GOT or PLT entries */
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
fill_got(s1);
else if (s1->got)
fill_local_got_entries(s1);
/* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);