mirror of
https://github.com/frida/tinycc
synced 2025-01-01 17:44:26 +03:00
Fix gawk miscompile
See testcase. Function pointer use was hosed when the destination function wasn't also called normally by the program.
This commit is contained in:
parent
cd9514abc4
commit
77d7ea04ac
@ -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;
|
||||
|
56
tccelf.c
56
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user