mirror of
https://github.com/frida/tinycc
synced 2025-02-25 11:44:02 +03:00
tccrun: win64: add unwind function table for dynamic code
This works only when tcc.exe is compiled using MSC. MinGW does something in the startup code that defeats it.
This commit is contained in:
parent
232650f8b3
commit
df4c0892f3
9
tcc.h
9
tcc.h
@ -566,10 +566,11 @@ struct TCCState {
|
||||
int pe_subsystem;
|
||||
unsigned long pe_file_align;
|
||||
unsigned long pe_stack_size;
|
||||
struct pe_uw {
|
||||
Section *pdata;
|
||||
int sym_1, sym_2, offs_1;
|
||||
} pe_unwind;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
Section *uw_pdata;
|
||||
int uw_sym;
|
||||
unsigned uw_offs;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
|
93
tccpe.c
93
tccpe.c
@ -1694,54 +1694,65 @@ ST_FUNC int pe_add_dll(struct TCCState *s, const char *libname)
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
||||
static unsigned pe_add_uwwind_info(TCCState *s1)
|
||||
{
|
||||
static const char uw_info[] = {
|
||||
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
|
||||
0x04, // UBYTE Size of prolog
|
||||
0x02, // UBYTE Count of unwind codes
|
||||
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled)
|
||||
// USHORT * n Unwind codes array
|
||||
// 0x0b, 0x01, 0xff, 0xff, // stack size
|
||||
0x04, 0x03, // set frame ptr (mov rsp -> rbp)
|
||||
0x01, 0x50 // push reg (rbp)
|
||||
};
|
||||
|
||||
struct pe_uw *pe_uw = &tcc_state->pe_unwind;
|
||||
|
||||
Section *uw, *pd;
|
||||
WORD *p1;
|
||||
DWORD *p2;
|
||||
unsigned o2;
|
||||
|
||||
uw = data_section;
|
||||
pd = pe_uw->pdata;
|
||||
if (NULL == pd)
|
||||
{
|
||||
pe_uw->pdata = pd = find_section(tcc_state, ".pdata");
|
||||
pe_uw->pdata->sh_addralign = 4;
|
||||
section_ptr_add(uw, -uw->data_offset & 3);
|
||||
pe_uw->offs_1 = uw->data_offset;
|
||||
p1 = section_ptr_add(uw, sizeof uw_info);
|
||||
/* use one common entry for all functions */
|
||||
memcpy(p1, uw_info, sizeof uw_info);
|
||||
pe_uw->sym_1 = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
|
||||
pe_uw->sym_2 = put_elf_sym(symtab_section, 0, 0, 0, 0, uw->sh_num, NULL);
|
||||
if (NULL == s1->uw_pdata) {
|
||||
s1->uw_pdata = find_section(tcc_state, ".pdata");
|
||||
s1->uw_pdata->sh_addralign = 4;
|
||||
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
|
||||
}
|
||||
|
||||
o2 = pd->data_offset;
|
||||
p2 = section_ptr_add(pd, 3 * sizeof (DWORD));
|
||||
if (0 == s1->uw_offs) {
|
||||
/* As our functions all have the same stackframe, we use one entry for all */
|
||||
static const unsigned char uw_info[] = {
|
||||
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
|
||||
0x04, // UBYTE Size of prolog
|
||||
0x02, // UBYTE Count of unwind codes
|
||||
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled)
|
||||
// USHORT * n Unwind codes array
|
||||
// 0x0b, 0x01, 0xff, 0xff, // stack size
|
||||
0x04, 0x03, // set frame ptr (mov rsp -> rbp)
|
||||
0x01, 0x50 // push reg (rbp)
|
||||
};
|
||||
|
||||
Section *s = text_section;
|
||||
unsigned char *p;
|
||||
|
||||
section_ptr_add(s, -s->data_offset & 3); /* align */
|
||||
s1->uw_offs = s->data_offset;
|
||||
p = section_ptr_add(s, sizeof uw_info);
|
||||
memcpy(p, uw_info, sizeof uw_info);
|
||||
}
|
||||
|
||||
return s1->uw_offs;
|
||||
}
|
||||
|
||||
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
||||
{
|
||||
TCCState *s1 = tcc_state;
|
||||
Section *pd;
|
||||
unsigned o, n, d;
|
||||
struct /* _RUNTIME_FUNCTION */ {
|
||||
DWORD BeginAddress;
|
||||
DWORD EndAddress;
|
||||
DWORD UnwindData;
|
||||
} *p;
|
||||
|
||||
d = pe_add_uwwind_info(s1);
|
||||
pd = s1->uw_pdata;
|
||||
o = pd->data_offset;
|
||||
p = section_ptr_add(pd, sizeof *p);
|
||||
|
||||
/* record this function */
|
||||
p2[0] = start;
|
||||
p2[1] = end;
|
||||
p2[2] = pe_uw->offs_1;
|
||||
p->BeginAddress = start;
|
||||
p->EndAddress = end;
|
||||
p->UnwindData = d;
|
||||
|
||||
/* put relocations on it */
|
||||
put_elf_reloc(symtab_section, pd, o2, R_X86_64_RELATIVE, pe_uw->sym_1);
|
||||
put_elf_reloc(symtab_section, pd, o2+4, R_X86_64_RELATIVE, pe_uw->sym_1);
|
||||
put_elf_reloc(symtab_section, pd, o2+8, R_X86_64_RELATIVE, pe_uw->sym_2);
|
||||
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
|
||||
put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#define PE_STDSYM(n,s) n
|
||||
|
19
tccrun.c
19
tccrun.c
@ -30,6 +30,10 @@ static int rt_get_caller_pc(uplong *paddr, ucontext_t *uc, int level);
|
||||
static void rt_error(ucontext_t *uc, const char *fmt, ...);
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr);
|
||||
|
||||
#ifdef _WIN64
|
||||
static void win64_add_function_table(TCCState *s1);
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
@ -189,6 +193,10 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
set_pages_executable(s1->runtime_plt_and_got,
|
||||
s1->runtime_plt_and_got_offset);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
win64_add_function_table(s1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -578,6 +586,17 @@ static void set_exception_handler(void)
|
||||
SetUnhandledExceptionFilter(cpu_exception_handler);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static void win64_add_function_table(TCCState *s1)
|
||||
{
|
||||
RtlAddFunctionTable(
|
||||
(RUNTIME_FUNCTION*)(uplong)s1->uw_pdata->sh_addr,
|
||||
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
||||
(uplong)text_section->sh_addr
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define Eip Rip
|
||||
#define Ebp Rbp
|
||||
|
@ -57,17 +57,9 @@ P0:
|
||||
/* ---------------------------------------------- */
|
||||
/* setjmp/longjmp support */
|
||||
|
||||
.globl tinyc_no_getbp
|
||||
tinyc_no_getbp:
|
||||
.byte 0x90
|
||||
|
||||
.globl tinyc_getbp
|
||||
tinyc_getbp:
|
||||
xor %rax,%rax
|
||||
cmp %al,tinyc_no_getbp(%rax)
|
||||
je t1
|
||||
mov %rbp,%rax
|
||||
t1:
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
|
@ -549,7 +549,9 @@ ResetEvent
|
||||
ResetNLSUserInfoCache
|
||||
ResetWriteWatch
|
||||
ResumeThread
|
||||
RtlAddFunctionTable
|
||||
RtlFillMemory
|
||||
RtlInstallFunctionTableCallback
|
||||
RtlMoveMemory
|
||||
RtlUnwind
|
||||
RtlZeroMemory
|
||||
|
@ -772,8 +772,6 @@ void gfunc_epilog(void)
|
||||
/* align local size to word & save local variables */
|
||||
v = (func_scratch + -loc + 15) & -16;
|
||||
|
||||
pe_add_unwind_data(ind, saved_ind, v);
|
||||
|
||||
if (v >= 4096) {
|
||||
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
|
||||
oad(0xb8, v); /* mov stacksize, %eax */
|
||||
@ -785,7 +783,10 @@ void gfunc_epilog(void)
|
||||
o(0xec8148); /* sub rsp, stacksize */
|
||||
gen_le32(v);
|
||||
}
|
||||
ind = saved_ind;
|
||||
|
||||
cur_text_section->data_offset = saved_ind;
|
||||
pe_add_unwind_data(ind, saved_ind, v);
|
||||
ind = cur_text_section->data_offset;
|
||||
}
|
||||
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user