From df4c0892f3fb5170042652cd648a29c94c3a2eca Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 14 Jul 2011 19:09:49 +0200 Subject: [PATCH] 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. --- tcc.h | 9 +++--- tccpe.c | 87 ++++++++++++++++++++++++++++---------------------- tccrun.c | 19 +++++++++++ win32/lib/chkstk.S | 8 ----- win32/lib/kernel32.def | 2 ++ x86_64-gen.c | 7 ++-- 6 files changed, 79 insertions(+), 53 deletions(-) diff --git a/tcc.h b/tcc.h index eaf0e65f..e1b27f24 100644 --- a/tcc.h +++ b/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 diff --git a/tccpe.c b/tccpe.c index 22b61a69..3510d9c1 100644 --- a/tccpe.c +++ b/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) - }; + 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); + } - struct pe_uw *pe_uw = &tcc_state->pe_unwind; + 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 *uw, *pd; - WORD *p1; - DWORD *p2; - unsigned o2; + Section *s = text_section; + unsigned char *p; - 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); + 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); } - o2 = pd->data_offset; - p2 = section_ptr_add(pd, 3 * sizeof (DWORD)); + 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 diff --git a/tccrun.c b/tccrun.c index 0423a1d3..e45c2184 100644 --- a/tccrun.c +++ b/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; } @@ -579,6 +587,17 @@ static void set_exception_handler(void) } #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 #endif diff --git a/win32/lib/chkstk.S b/win32/lib/chkstk.S index d53b31e0..27260615 100644 --- a/win32/lib/chkstk.S +++ b/win32/lib/chkstk.S @@ -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 /* ---------------------------------------------- */ diff --git a/win32/lib/kernel32.def b/win32/lib/kernel32.def index 85dd980d..5d56705e 100644 --- a/win32/lib/kernel32.def +++ b/win32/lib/kernel32.def @@ -549,7 +549,9 @@ ResetEvent ResetNLSUserInfoCache ResetWriteWatch ResumeThread +RtlAddFunctionTable RtlFillMemory +RtlInstallFunctionTableCallback RtlMoveMemory RtlUnwind RtlZeroMemory diff --git a/x86_64-gen.c b/x86_64-gen.c index 7c64f3bc..247027a5 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -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 -- 2.11.4.GIT