mirror of
https://github.com/frida/tinycc
synced 2024-11-24 00:29:38 +03:00
56db092ab7
- revert Makefiles to state before last bcheck additions Instead, just load bcheck.o explicitly if that is what is wanted. - move tcc_add_bcheck() to the <target>-link.c files and remove revently added arguments. This function is to support tccelf.c with linking, not for tccgen.c to support compilation. - remove -ba option: It said: "-ba Enable better address checking with bounds checker" Okay, if it is better then to have it is not an option. - remove va_copy. It is C99 and we try to stay C89 in tinycc when possible. For example, MS compilers do not have va_copy. - win64: revert any 'fixes' to alloca It was correct as it was before, except for bound_checking where it was not implemented. This should now work too. - remove parasitic filename:linenum features Such feature is already present with rt_printline in tccrun.c. If it doesn't work it can be fixed. - revert changes to gen_bounded_ptr_add() gen_bounded_ptr_add() was working as it should before (mostly). For the sake of simplicity I switched it to CDECL. Anyway, FASTCALL means SLOWCALL with tinycc. In exchange you get one addition which is required for bounds_cnecking function arguments. The important thing is to check them *BEFORE* they are loaded into registers. New function gbound_args() does that. In any case, code instrumentation with the bounds-check functions as such now seems to work flawlessly again, which means when they are inserted as NOPs, any code that tcc can compile, seems to behave just the same as without them. What these functions then do when fully enabled, is a differnt story. I did not touch this.
314 lines
9.6 KiB
C
314 lines
9.6 KiB
C
#ifdef TARGET_DEFS_ONLY
|
|
|
|
#define EM_TCC_TARGET EM_386
|
|
|
|
/* relocation type for 32 bit data relocation */
|
|
#define R_DATA_32 R_386_32
|
|
#define R_DATA_PTR R_386_32
|
|
#define R_JMP_SLOT R_386_JMP_SLOT
|
|
#define R_GLOB_DAT R_386_GLOB_DAT
|
|
#define R_COPY R_386_COPY
|
|
#define R_RELATIVE R_386_RELATIVE
|
|
|
|
#define R_NUM R_386_NUM
|
|
|
|
#define ELF_START_ADDR 0x08048000
|
|
#define ELF_PAGE_SIZE 0x1000
|
|
|
|
#define PCRELATIVE_DLLPLT 0
|
|
#define RELOCATE_DLLPLT 0
|
|
|
|
#else /* !TARGET_DEFS_ONLY */
|
|
|
|
#include "tcc.h"
|
|
|
|
#ifndef ELF_OBJ_ONLY
|
|
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
relocations, returns -1. */
|
|
int code_reloc (int reloc_type)
|
|
{
|
|
switch (reloc_type) {
|
|
case R_386_RELATIVE:
|
|
case R_386_16:
|
|
case R_386_32:
|
|
case R_386_GOTPC:
|
|
case R_386_GOTOFF:
|
|
case R_386_GOT32:
|
|
case R_386_GOT32X:
|
|
case R_386_GLOB_DAT:
|
|
case R_386_COPY:
|
|
return 0;
|
|
|
|
case R_386_PC16:
|
|
case R_386_PC32:
|
|
case R_386_PLT32:
|
|
case R_386_JMP_SLOT:
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
different values. */
|
|
int gotplt_entry_type (int reloc_type)
|
|
{
|
|
switch (reloc_type) {
|
|
case R_386_RELATIVE:
|
|
case R_386_16:
|
|
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;
|
|
|
|
case R_386_GOTPC:
|
|
case R_386_GOTOFF:
|
|
return BUILD_GOT_ONLY;
|
|
|
|
case R_386_GOT32:
|
|
case R_386_GOT32X:
|
|
case R_386_PLT32:
|
|
return ALWAYS_GOTPLT_ENTRY;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
{
|
|
Section *plt = s1->plt;
|
|
uint8_t *p;
|
|
int modrm;
|
|
unsigned plt_offset, relofs;
|
|
|
|
/* on i386 if we build a DLL, we add a %ebx offset */
|
|
if (s1->output_type == TCC_OUTPUT_DLL)
|
|
modrm = 0xa3;
|
|
else
|
|
modrm = 0x25;
|
|
|
|
/* empty PLT: create PLT0 entry that pushes the library identifier
|
|
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
|
|
(GOT + 2 * PTR_SIZE) */
|
|
if (plt->data_offset == 0) {
|
|
p = section_ptr_add(plt, 16);
|
|
p[0] = 0xff; /* pushl got + PTR_SIZE */
|
|
p[1] = modrm + 0x10;
|
|
write32le(p + 2, PTR_SIZE);
|
|
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
|
|
p[7] = modrm;
|
|
write32le(p + 8, PTR_SIZE * 2);
|
|
}
|
|
plt_offset = plt->data_offset;
|
|
|
|
/* The PLT slot refers to the relocation entry it needs via offset.
|
|
The reloc entry is created below, so its offset is the current
|
|
data_offset */
|
|
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
|
|
|
|
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
|
|
p = section_ptr_add(plt, 16);
|
|
p[0] = 0xff; /* jmp *(got + x) */
|
|
p[1] = modrm;
|
|
write32le(p + 2, got_offset);
|
|
p[6] = 0x68; /* push $xxx */
|
|
write32le(p + 7, relofs);
|
|
p[11] = 0xe9; /* jmp plt_start */
|
|
write32le(p + 12, -(plt->data_offset));
|
|
return plt_offset;
|
|
}
|
|
|
|
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
address for PLT and GOT are known (see fill_program_header) */
|
|
ST_FUNC void relocate_plt(TCCState *s1)
|
|
{
|
|
uint8_t *p, *p_end;
|
|
|
|
if (!s1->plt)
|
|
return;
|
|
|
|
p = s1->plt->data;
|
|
p_end = p + s1->plt->data_offset;
|
|
|
|
if (p < p_end) {
|
|
add32le(p + 2, s1->got->sh_addr);
|
|
add32le(p + 8, s1->got->sh_addr);
|
|
p += 16;
|
|
while (p < p_end) {
|
|
add32le(p + 2, s1->got->sh_addr);
|
|
p += 16;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
|
{
|
|
int sym_index, esym_index;
|
|
|
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
|
|
switch (type) {
|
|
case R_386_32:
|
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
|
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
qrel->r_offset = rel->r_offset;
|
|
if (esym_index) {
|
|
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
|
|
qrel++;
|
|
return;
|
|
} else {
|
|
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
|
|
qrel++;
|
|
}
|
|
}
|
|
add32le(ptr, val);
|
|
return;
|
|
case R_386_PC32:
|
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
|
/* DLL relocation */
|
|
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
if (esym_index) {
|
|
qrel->r_offset = rel->r_offset;
|
|
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
|
|
qrel++;
|
|
return;
|
|
}
|
|
}
|
|
add32le(ptr, val - addr);
|
|
return;
|
|
case R_386_PLT32:
|
|
add32le(ptr, val - addr);
|
|
return;
|
|
case R_386_GLOB_DAT:
|
|
case R_386_JMP_SLOT:
|
|
write32le(ptr, val);
|
|
return;
|
|
case R_386_GOTPC:
|
|
add32le(ptr, s1->got->sh_addr - addr);
|
|
return;
|
|
case R_386_GOTOFF:
|
|
add32le(ptr, val - s1->got->sh_addr);
|
|
return;
|
|
case R_386_GOT32:
|
|
case R_386_GOT32X:
|
|
/* we load the got offset */
|
|
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
|
|
return;
|
|
case R_386_16:
|
|
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
|
|
output_file:
|
|
tcc_error("can only produce 16-bit binary files");
|
|
}
|
|
write16le(ptr, read16le(ptr) + val);
|
|
return;
|
|
case R_386_PC16:
|
|
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
|
|
goto output_file;
|
|
write16le(ptr, read16le(ptr) + val - addr);
|
|
return;
|
|
case R_386_RELATIVE:
|
|
#ifdef TCC_TARGET_PE
|
|
add32le(ptr, val - s1->pe_imagebase);
|
|
#endif
|
|
/* do nothing */
|
|
return;
|
|
case R_386_COPY:
|
|
/* This relocation must copy initialized data from the library
|
|
to the program .bss segment. Currently made like for ARM
|
|
(to remove noise of default case). Is this true?
|
|
*/
|
|
return;
|
|
default:
|
|
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
|
type, (unsigned)addr, ptr, (unsigned)val);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
|
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
|
{
|
|
addr_t *ptr;
|
|
int loc_glob;
|
|
int sym_index;
|
|
int bsym_index;
|
|
|
|
if (0 == s1->do_bounds_check)
|
|
return;
|
|
/* XXX: add an object file to do that */
|
|
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
|
|
*ptr = 0;
|
|
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
|
|
bsym_index = set_elf_sym(symtab_section, 0, 0,
|
|
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
|
|
bounds_section->sh_num, "__bounds_start");
|
|
/* pull bcheck.o from libtcc1.a */
|
|
sym_index = set_elf_sym(symtab_section, 0, 0,
|
|
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
SHN_UNDEF, "__bound_init");
|
|
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
|
/* add 'call __bound_init()' in .init section */
|
|
Section *init_section = find_section(s1, ".init");
|
|
unsigned char *pinit;
|
|
#ifdef TCC_TARGET_PE
|
|
pinit = section_ptr_add(init_section, 3);
|
|
pinit[0] = 0x55; /* push %rbp */
|
|
pinit[1] = 0x89; /* mov %esp,%ebp */
|
|
pinit[2] = 0xe5;
|
|
#endif
|
|
pinit = section_ptr_add(init_section, 5);
|
|
pinit[0] = 0xe8;
|
|
write32le(pinit + 1, -4);
|
|
put_elf_reloc(symtab_section, init_section,
|
|
init_section->data_offset - 4, R_386_PC32, sym_index);
|
|
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
|
pinit = section_ptr_add(init_section, 6);
|
|
pinit[0] = 0xb8; /* mov xx,%eax */
|
|
write32le(pinit + 1, 0);
|
|
pinit[5] = 0x50; /* push %eax */
|
|
put_elf_reloc(symtab_section, init_section,
|
|
init_section->data_offset - 5, R_386_32, bsym_index);
|
|
sym_index = set_elf_sym(symtab_section, 0, 0,
|
|
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
SHN_UNDEF, "__bounds_add_static_var");
|
|
pinit = section_ptr_add(init_section, 5);
|
|
pinit[0] = 0xe8;
|
|
write32le(pinit + 1, -4);
|
|
put_elf_reloc(symtab_section, init_section,
|
|
init_section->data_offset - 4, R_386_PC32, sym_index);
|
|
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
|
pinit = section_ptr_add(init_section, 3);
|
|
pinit[0] = 0x83; /* add $0x4,%esp */
|
|
pinit[1] = 0xc4;
|
|
pinit[2] = 0x04;
|
|
#ifdef TCC_TARGET_PE
|
|
{
|
|
int init_index = set_elf_sym(symtab_section,
|
|
0, 0,
|
|
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
init_section->sh_num, "__init_start");
|
|
Sym sym;
|
|
init_section->sh_flags |= SHF_EXECINSTR;
|
|
pinit = section_ptr_add(init_section, 2);
|
|
pinit[0] = 0xc9; /* leave */
|
|
pinit[1] = 0xc3; /* ret */
|
|
sym.c = init_index;
|
|
add_init_array (s1, &sym);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif /* !TARGET_DEFS_ONLY */
|