mirror of
https://github.com/frida/tinycc
synced 2025-01-04 11:04:42 +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) {
|
switch (reloc_type) {
|
||||||
case R_386_RELATIVE:
|
case R_386_RELATIVE:
|
||||||
case R_386_16:
|
case R_386_16:
|
||||||
case R_386_32:
|
|
||||||
case R_386_GLOB_DAT:
|
case R_386_GLOB_DAT:
|
||||||
case R_386_JMP_SLOT:
|
case R_386_JMP_SLOT:
|
||||||
case R_386_COPY:
|
case R_386_COPY:
|
||||||
return NO_GOTPLT_ENTRY;
|
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_PC16:
|
||||||
case R_386_PC32:
|
case R_386_PC32:
|
||||||
return AUTO_GOTPLT_ENTRY;
|
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];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
|
|
||||||
if (gotplt_entry == NO_GOTPLT_ENTRY) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Automatically create PLT/GOT [entry] it is an undefined reference
|
/* Automatically create PLT/GOT [entry] if it is an undefined
|
||||||
(resolved at runtime), or the symbol is absolute, probably created
|
reference (resolved at runtime), or the symbol is absolute,
|
||||||
by tcc_add_symbol, and thus on 64-bit targets might be too far
|
probably created by tcc_add_symbol, and thus on 64-bit
|
||||||
from application code */
|
targets might be too far from application code. */
|
||||||
if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
|
if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
|
||||||
if (sym->st_shndx == SHN_UNDEF) {
|
if (sym->st_shndx == SHN_UNDEF) {
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
int dynindex;
|
||||||
if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
|
if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
|
||||||
continue;
|
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))
|
} else if (!(sym->st_shndx == SHN_ABS && PTR_SIZE == 8))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -994,9 +1001,7 @@ ST_FUNC void build_got_entries(TCCState *s1)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (code_reloc(type)) {
|
if (code_reloc(type)) {
|
||||||
#ifdef TCC_TARGET_I386
|
|
||||||
jmp_slot:
|
jmp_slot:
|
||||||
#endif
|
|
||||||
reloc_type = R_JMP_SLOT;
|
reloc_type = R_JMP_SLOT;
|
||||||
} else
|
} else
|
||||||
reloc_type = R_GLOB_DAT;
|
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
|
* of the function wanted by the caller of dlsym instead of
|
||||||
* the address of the function that would return that
|
* the address of the function that would return that
|
||||||
* address */
|
* address */
|
||||||
put_elf_sym(s1->dynsym, 0, esym->st_size,
|
int dynindex
|
||||||
ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
|
= put_elf_sym(s1->dynsym, 0, esym->st_size,
|
||||||
name);
|
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) {
|
} else if (type == STT_OBJECT) {
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
ElfW(Sym) *dynsym;
|
ElfW(Sym) *dynsym;
|
||||||
|
@ -8,9 +8,13 @@ int fred(int p)
|
|||||||
|
|
||||||
int (*f)(int) = &fred;
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
printf("%d\n", (*f)(24));
|
fprintfptr(stdout, "%d\n", (*f)(24));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,10 @@ ARGS =
|
|||||||
31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
|
31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
|
||||||
46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c
|
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
|
# Some tests might need different flags
|
||||||
76_dollars_in_identifiers.test : TCCFLAGS += -fdollars-in-identifiers
|
76_dollars_in_identifiers.test : TCCFLAGS += -fdollars-in-identifiers
|
||||||
|
|
||||||
@ -49,7 +53,12 @@ all test: $(filter-out $(SKIP),$(TESTS))
|
|||||||
%.test: %.c %.expect
|
%.test: %.c %.expect
|
||||||
@echo Test: $*...
|
@echo Test: $*...
|
||||||
# test -run
|
# 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
|
@diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output
|
||||||
|
|
||||||
# automatically generate .expect files with gcc:
|
# automatically generate .expect files with gcc:
|
||||||
|
@ -61,6 +61,9 @@ int gotplt_entry_type (int reloc_type)
|
|||||||
case R_X86_64_RELATIVE:
|
case R_X86_64_RELATIVE:
|
||||||
return NO_GOTPLT_ENTRY;
|
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_32:
|
||||||
case R_X86_64_32S:
|
case R_X86_64_32S:
|
||||||
case R_X86_64_64:
|
case R_X86_64_64:
|
||||||
|
Loading…
Reference in New Issue
Block a user