aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2011-07-14 19:09:49 +0200
committergrischka <grischka>2011-07-14 19:09:49 +0200
commitdf4c0892f3fb5170042652cd648a29c94c3a2eca (patch)
tree0db41a085d08276f9804b4905949c60ff1f7500f
parent232650f8b3a786e82071c12a1ee8eea60684279a (diff)
downloadtinycc-df4c0892f3fb5170042652cd648a29c94c3a2eca.tar.gz
tinycc-df4c0892f3fb5170042652cd648a29c94c3a2eca.tar.bz2
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.
-rw-r--r--tcc.h9
-rw-r--r--tccpe.c87
-rw-r--r--tccrun.c19
-rw-r--r--win32/lib/chkstk.S8
-rw-r--r--win32/lib/kernel32.def2
-rw-r--r--x86_64-gen.c7
6 files changed, 79 insertions, 53 deletions
diff --git a/tcc.h b/tcc.h
index eaf0e65..e1b27f2 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 22b61a6..3510d9c 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 0423a1d..e45c218 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 d53b31e..2726061 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 85dd980..5d56705 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 7c64f3b..247027a 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