aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tccelf.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/tccelf.c b/tccelf.c
index da81d03..b5eea07 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -1632,8 +1632,16 @@ static int elf_output_file(TCCState *s1, const char *filename)
esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index];
type = ELFW(ST_TYPE)(esym->st_info);
if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) {
+ /* Indirect functions shall have STT_FUNC type
+ * in executable dynsym section. Indeed, a dlsym
+ * call following a lazy resolution would pick
+ * the symbol value from the executable dynsym
+ * entry which would contain the address of the
+ * function wanted by the caller of dlsym
+ * instead of the address of the function that
+ * would return that address */
put_got_entry(s1, R_JMP_SLOT, esym->st_size,
- ELFW(ST_INFO)(STB_GLOBAL,type),
+ ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC),
sym - (ElfW(Sym) *)symtab_section->data);
} else if (type == STT_OBJECT) {
unsigned long offset;
@@ -1733,8 +1741,9 @@ static int elf_output_file(TCCState *s1, const char *filename)
if ((ELFW(ST_TYPE)(sym->st_info) == STT_FUNC ||
ELFW(ST_TYPE)(sym->st_info) == STT_GNU_IFUNC)
&& sym->st_shndx == SHN_UNDEF) {
+ int visibility = ELFW(ST_BIND)(sym->st_info);
put_got_entry(s1, R_JMP_SLOT, sym->st_size,
- sym->st_info,
+ ELFW(ST_INFO)(visibility,STT_FUNC),
sym - (ElfW(Sym) *)symtab_section->data);
}
else if (ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT) {