Fix gawk miscompile

See testcase.  Function pointer use was hosed when the destination
function wasn't also called normally by the program.
master
Michael Matz 2016-12-18 05:18:19 +01:00
parent cd9514abc4
commit 77d7ea04ac
5 changed files with 56 additions and 27 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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:

View File

@ -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: