diff --git a/tccelf.c b/tccelf.c index d7cc847..a213048 100644 --- a/tccelf.c +++ b/tccelf.c @@ -996,12 +996,25 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) tgt += rel->r_addend; #endif addr = s->sh_addr + rel->r_offset; - relocate(s1, rel, type, ptr, addr, tgt); + { +#if !(defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \ + defined(TCC_TARGET_MACHO)) + int dynindex; + if (s == data_section && sym->st_shndx == SHN_UNDEF && + s1->dynsym && + (dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index)) { + rel->r_info = ELFW(R_INFO)(dynindex, type); + *qrel++ = *rel; + } + else +#endif + relocate(s1, rel, type, ptr, addr, tgt); + } } /* if the relocation is allocated, we change its symbol table */ if (sr->sh_flags & SHF_ALLOC) { sr->link = s1->dynsym; - if (s1->output_type == TCC_OUTPUT_DLL) { + if (qrel != (ElfW_Rel *)sr->data) { size_t r = (uint8_t*)qrel - sr->data; if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE && 0 == strcmp(s->name, ".stab")) @@ -1242,6 +1255,12 @@ ST_FUNC void build_got_entries(TCCState *s1) /* dynsym isn't set for -run :-/ */ dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; +#if !(defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \ + defined(TCC_TARGET_MACHO)) + if (dynindex && s == data_section->reloc) + s->sh_flags |= SHF_ALLOC; + else +#endif if (dynindex && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE diff --git a/tests/tests2/42_function_pointer.c b/tests/tests2/42_function_pointer.c index 697bd79..6b9db61 100644 --- a/tests/tests2/42_function_pointer.c +++ b/tests/tests2/42_function_pointer.c @@ -12,10 +12,18 @@ int (*f)(int) = &fred; (fprint here) must not be called directly anywhere in the test. */ int (*fprintfptr)(FILE *, const char *, ...) = &fprintf; +typedef int (*func) (int); +static int dummy1(int i) { return 0; } +int dummy2(int i) { return 0; } +static func allfunc[] = { putchar, dummy1, dummy2 }; + int main() { fprintfptr(stdout, "%d\n", (*f)(24)); + printf ("%d\n", allfunc[0] == putchar); + printf ("%d\n", allfunc[1] == dummy1); + printf ("%d\n", allfunc[2] == dummy2); return 0; } diff --git a/tests/tests2/42_function_pointer.expect b/tests/tests2/42_function_pointer.expect index 6c8b6ce..0a70141 100644 --- a/tests/tests2/42_function_pointer.expect +++ b/tests/tests2/42_function_pointer.expect @@ -1,2 +1,5 @@ yo 24 42 +1 +1 +1