aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386-link.c7
-rw-r--r--tccelf.c56
-rw-r--r--tests/tests2/42_function_pointer.c6
-rw-r--r--tests/tests2/Makefile11
-rw-r--r--x86_64-link.c3
5 files changed, 56 insertions, 27 deletions
diff --git a/i386-link.c b/i386-link.c
index c098172..c232f39 100644
--- a/i386-link.c
+++ b/i386-link.c
@@ -56,12 +56,17 @@ int gotplt_entry_type (int reloc_type)
switch (reloc_type) {
case R_386_RELATIVE:
case R_386_16:
- case R_386_32:
case R_386_GLOB_DAT:
case R_386_JMP_SLOT:
case R_386_COPY:
return NO_GOTPLT_ENTRY;
+ case R_386_32:
+ /* This relocations shouldn't normally need GOT or PLT
+ slots if it weren't for simplicity in the code generator.
+ See our caller for comments. */
+ return AUTO_GOTPLT_ENTRY;
+
case R_386_PC16:
case R_386_PC32:
return AUTO_GOTPLT_ENTRY;
diff --git a/tccelf.c b/tccelf.c
index 003797c..e2ba5a4 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -956,32 +956,39 @@ ST_FUNC void build_got_entries(TCCState *s1)
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (gotplt_entry == NO_GOTPLT_ENTRY) {
-#ifdef TCC_TARGET_I386
- if (type == R_386_32 && sym->st_shndx == SHN_UNDEF) {
- /* the i386 generator uses the plt address for function
- pointers into .so. This may break pointer equality
- but helps to keep it simple */
- char *name = (char *)symtab_section->link->data + sym->st_name;
- int index = find_elf_sym(s1->dynsymtab_section, name);
- ElfW(Sym) *esym = (ElfW(Sym) *)s1->dynsymtab_section->data + index;
- if (index
- && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
- || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
- && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
- goto jmp_slot;
- }
-#endif
continue;
}
- /* Automatically create PLT/GOT [entry] it is an undefined reference
- (resolved at runtime), or the symbol is absolute, probably created
- by tcc_add_symbol, and thus on 64-bit targets might be too far
- from application code */
+ /* Automatically create PLT/GOT [entry] if it is an undefined
+ reference (resolved at runtime), or the symbol is absolute,
+ probably created by tcc_add_symbol, and thus on 64-bit
+ targets might be too far from application code. */
if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
if (sym->st_shndx == SHN_UNDEF) {
+ ElfW(Sym) *esym;
+ int dynindex;
if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
continue;
+ /* Relocations for UNDEF symbols would normally need
+ to be transferred into the executable or shared object.
+ If that were done AUTO_GOTPLT_ENTRY wouldn't exist.
+ But TCC doesn't do that (at least for exes), so we
+ need to resolve all such relocs locally. And that
+ means PLT slots for functions in DLLs and COPY relocs for
+ data symbols. COPY relocs were generated in
+ bind_exe_dynsyms (and the symbol adjusted to be defined),
+ and for functions we were generated a dynamic symbol
+ of function type. */
+ if (s1->dynsym) {
+ /* dynsym isn't set for -run :-/ */
+ dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ esym = (ElfW(Sym) *)s1->dynsym->data + dynindex;
+ if (dynindex
+ && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
+ || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
+ && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
+ goto jmp_slot;
+ }
} else if (!(sym->st_shndx == SHN_ABS && PTR_SIZE == 8))
continue;
}
@@ -994,9 +1001,7 @@ ST_FUNC void build_got_entries(TCCState *s1)
}
#endif
if (code_reloc(type)) {
-#ifdef TCC_TARGET_I386
jmp_slot:
-#endif
reloc_type = R_JMP_SLOT;
} else
reloc_type = R_GLOB_DAT;
@@ -1278,9 +1283,12 @@ static void bind_exe_dynsyms(TCCState *s1)
* of the function wanted by the caller of dlsym instead of
* the address of the function that would return that
* address */
- put_elf_sym(s1->dynsym, 0, esym->st_size,
- ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
- name);
+ int dynindex
+ = put_elf_sym(s1->dynsym, 0, esym->st_size,
+ ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
+ name);
+ int index = sym - (ElfW(Sym) *) symtab_section->data;
+ get_sym_attr(s1, index, 1)->dyn_index = dynindex;
} else if (type == STT_OBJECT) {
unsigned long offset;
ElfW(Sym) *dynsym;
diff --git a/tests/tests2/42_function_pointer.c b/tests/tests2/42_function_pointer.c
index 49c331b..697bd79 100644
--- a/tests/tests2/42_function_pointer.c
+++ b/tests/tests2/42_function_pointer.c
@@ -8,9 +8,13 @@ int fred(int p)
int (*f)(int) = &fred;
+/* To test what this is supposed to test the destination function
+ (fprint here) must not be called directly anywhere in the test. */
+int (*fprintfptr)(FILE *, const char *, ...) = &fprintf;
+
int main()
{
- printf("%d\n", (*f)(24));
+ fprintfptr(stdout, "%d\n", (*f)(24));
return 0;
}
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 2434215..166fb2a 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -34,6 +34,10 @@ ARGS =
31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c
+# And some tests don't test the right thing with -run
+NORUN =
+42_function_pointer.test : NORUN = true
+
# Some tests might need different flags
76_dollars_in_identifiers.test : TCCFLAGS += -fdollars-in-identifiers
@@ -49,7 +53,12 @@ all test: $(filter-out $(SKIP),$(TESTS))
%.test: %.c %.expect
@echo Test: $*...
# test -run
- @$(TCC) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true
+ @if test -z "$(NORUN)"; then \
+ $(TCC) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true; \
+ else \
+ $(TCC) $< -o ./$*.exe $(FILTER) 2>&1 && \
+ ./$*.exe $(ARGS) >$*.output 2>&1 || true; \
+ fi
@diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output
# automatically generate .expect files with gcc:
diff --git a/x86_64-link.c b/x86_64-link.c
index 602a8ef..27cad93 100644
--- a/x86_64-link.c
+++ b/x86_64-link.c
@@ -61,6 +61,9 @@ int gotplt_entry_type (int reloc_type)
case R_X86_64_RELATIVE:
return NO_GOTPLT_ENTRY;
+ /* The following relocs wouldn't normally need GOT or PLT
+ slots, but we need them for simplicity in the link
+ editor part. See our caller for comments. */
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64: