diff options
| author | Thomas Preud'homme <robotux@celest.fr> | 2014-03-25 22:35:11 +0800 |
|---|---|---|
| committer | Thomas Preud'homme <robotux@celest.fr> | 2014-03-25 22:35:11 +0800 |
| commit | dc8ea93b13faefb565fb937f8b8c08c40c063549 (patch) | |
| tree | 5c5311364fc646d4871e07291b6fa9cfb8ee8869 | |
| parent | 078ba241d9c24b15f734b4959f877519d7098140 (diff) | |
| download | tinycc-dc8ea93b13faefb565fb937f8b8c08c40c063549.tar.gz tinycc-dc8ea93b13faefb565fb937f8b8c08c40c063549.tar.bz2 | |
Support GOT32 and PLT32 reloc for same symbol
Some symbol (such as __gmon_start__ but this one does not matter to tcc)
can have both a R_386_GOT32 and R_386_PLT32 relocation. It is thus not
enough to test if a GOT reloc was already done when deciding whether to
return early from put_got_entry.
| -rw-r--r-- | tccelf.c | 42 |
1 files changed, 31 insertions, 11 deletions
@@ -1008,7 +1008,7 @@ static void put_got_entry(TCCState *s1, int reloc_type, unsigned long size, int info, int sym_index) { - int index; + int index, need_plt_entry, got_entry_present = 0; const char *name; ElfW(Sym) *sym; unsigned long offset; @@ -1017,25 +1017,38 @@ static void put_got_entry(TCCState *s1, if (!s1->got) build_got(s1); + need_plt_entry = s1->dynsym && +#ifdef TCC_TARGET_X86_64 + (reloc_type == R_X86_64_JUMP_SLOT); +#elif defined(TCC_TARGET_I386) + (reloc_type == R_386_JMP_SLOT); +#elif defined(TCC_TARGET_ARM) + (reloc_type == R_ARM_JUMP_SLOT); +#else + 0; +#endif + /* if a got entry already exists for that symbol, no need to add one */ if (sym_index < s1->nb_sym_attrs && - s1->sym_attrs[sym_index].got_offset) - return; + s1->sym_attrs[sym_index].got_offset) { + if (!need_plt_entry) + return; + else + got_entry_present = 1; + } alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_offset; if (s1->dynsym) { sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; name = (char *) symtab_section->link->data + sym->st_name; + if (!find_elf_sym(s1->dynsym, name)) + need_plt_entry = 1; + else + return; offset = sym->st_value; #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - if (reloc_type == -#ifdef TCC_TARGET_X86_64 - R_X86_64_JUMP_SLOT -#else - R_386_JMP_SLOT -#endif - ) { + if (need_plt_entry) { Section *plt; uint8_t *p; int modrm; @@ -1080,7 +1093,7 @@ static void put_got_entry(TCCState *s1, offset = plt->data_offset - 16; } #elif defined(TCC_TARGET_ARM) - if (reloc_type == R_ARM_JUMP_SLOT) { + if (need_plt_entry) { Section *plt; uint8_t *p; @@ -1123,6 +1136,13 @@ static void put_got_entry(TCCState *s1, #endif index = put_elf_sym(s1->dynsym, offset, size, info, 0, sym->st_shndx, name); + if (got_entry_present) { + put_elf_reloc(s1->dynsym, s1->got, + s1->sym_attrs[sym_index].got_offset, + reloc_type, index); + return; + } + /* put a got entry */ put_elf_reloc(s1->dynsym, s1->got, s1->got->data_offset, |
