This works only when tcc.exe is compiled using MSC. MinGW does something in the startup code that defeats it.
Unified · Split
| @@ -566,10 +566,11 @@ struct TCCState { · 565 unmodified lines | |||
| 566 | int pe_subsystem; | 566 | int pe_subsystem; |
| 567 | unsigned long pe_file_align; | 567 | unsigned long pe_file_align; |
| 568 | unsigned long pe_stack_size; | 568 | unsigned long pe_stack_size; |
| 569 | struct pe_uw { | 569 | #ifdef TCC_TARGET_X86_64 |
| 570 | Section *pdata; | 570 | Section *uw_pdata; |
| 571 | int sym_1, sym_2, offs_1; | 571 | int uw_sym; |
| 572 | } pe_unwind; | 572 | unsigned uw_offs; |
| 573 | #endif | ||
| 573 | #endif | 574 | #endif |
| 574 | 575 | ||
| 575 | #ifndef TCC_TARGET_PE | 576 | #ifndef TCC_TARGET_PE |
| @@ -1694,54 +1694,65 @@ ST_FUNC int pe_add_dll(struct TCCState *s, const char *libname) · 1693 unmodified lines | |||
| 1694 | 1694 | ||
| 1695 | /* ------------------------------------------------------------- */ | 1695 | /* ------------------------------------------------------------- */ |
| 1696 | #ifdef TCC_TARGET_X86_64 | 1696 | #ifdef TCC_TARGET_X86_64 |
| 1697 | ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) | 1697 | static unsigned pe_add_uwwind_info(TCCState *s1) |
| 1698 | { | 1698 | { |
| 1699 | static const char uw_info[] = { | 1699 | if (NULL == s1->uw_pdata) { |
| 1700 | 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags | 1700 | s1->uw_pdata = find_section(tcc_state, ".pdata"); |
| 1701 | 0x04, // UBYTE Size of prolog | 1701 | s1->uw_pdata->sh_addralign = 4; |
| 1702 | 0x02, // UBYTE Count of unwind codes | 1702 | s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); |
| 1703 | 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) | 1703 | } |
| 1704 | // USHORT * n Unwind codes array | ||
| 1705 | // 0x0b, 0x01, 0xff, 0xff, // stack size | ||
| 1706 | 0x04, 0x03, // set frame ptr (mov rsp -> rbp) | ||
| 1707 | 0x01, 0x50 // push reg (rbp) | ||
| 1708 | }; | ||
| 1709 | 1704 | ||
| 1710 | struct pe_uw *pe_uw = &tcc_state->pe_unwind; | 1705 | if (0 == s1->uw_offs) { |
| 1706 | /* As our functions all have the same stackframe, we use one entry for all */ | ||
| 1707 | static const unsigned char uw_info[] = { | ||
| 1708 | 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags | ||
| 1709 | 0x04, // UBYTE Size of prolog | ||
| 1710 | 0x02, // UBYTE Count of unwind codes | ||
| 1711 | 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) | ||
| 1712 | // USHORT * n Unwind codes array | ||
| 1713 | // 0x0b, 0x01, 0xff, 0xff, // stack size | ||
| 1714 | 0x04, 0x03, // set frame ptr (mov rsp -> rbp) | ||
| 1715 | 0x01, 0x50 // push reg (rbp) | ||
| 1716 | }; | ||
| 1711 | 1717 | ||
| 1712 | Section *uw, *pd; | 1718 | Section *s = text_section; |
| 1713 | WORD *p1; | 1719 | unsigned char *p; |
| 1714 | DWORD *p2; | ||
| 1715 | unsigned o2; | ||
| 1716 | 1720 | ||
| 1717 | uw = data_section; | 1721 | section_ptr_add(s, -s->data_offset & 3); /* align */ |
| 1718 | pd = pe_uw->pdata; | 1722 | s1->uw_offs = s->data_offset; |
| 1719 | if (NULL == pd) | 1723 | p = section_ptr_add(s, sizeof uw_info); |
| 1720 | { | 1724 | memcpy(p, uw_info, sizeof uw_info); |
| 1721 | pe_uw->pdata = pd = find_section(tcc_state, ".pdata"); | ||
| 1722 | pe_uw->pdata->sh_addralign = 4; | ||
| 1723 | section_ptr_add(uw, -uw->data_offset & 3); | ||
| 1724 | pe_uw->offs_1 = uw->data_offset; | ||
| 1725 | p1 = section_ptr_add(uw, sizeof uw_info); | ||
| 1726 | /* use one common entry for all functions */ | ||
| 1727 | memcpy(p1, uw_info, sizeof uw_info); | ||
| 1728 | pe_uw->sym_1 = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); | ||
| 1729 | pe_uw->sym_2 = put_elf_sym(symtab_section, 0, 0, 0, 0, uw->sh_num, NULL); | ||
| 1730 | } | 1725 | } |
| 1731 | 1726 | ||
| 1732 | o2 = pd->data_offset; | 1727 | return s1->uw_offs; |
| 1733 | p2 = section_ptr_add(pd, 3 * sizeof (DWORD)); | 1728 | } |
| 1729 | |||
| 1730 | ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) | ||
| 1731 | { | ||
| 1732 | TCCState *s1 = tcc_state; | ||
| 1733 | Section *pd; | ||
| 1734 | unsigned o, n, d; | ||
| 1735 | struct /* _RUNTIME_FUNCTION */ { | ||
| 1736 | DWORD BeginAddress; | ||
| 1737 | DWORD EndAddress; | ||
| 1738 | DWORD UnwindData; | ||
| 1739 | } *p; | ||
| 1740 | |||
| 1741 | d = pe_add_uwwind_info(s1); | ||
| 1742 | pd = s1->uw_pdata; | ||
| 1743 | o = pd->data_offset; | ||
| 1744 | p = section_ptr_add(pd, sizeof *p); | ||
| 1745 | |||
| 1734 | /* record this function */ | 1746 | /* record this function */ |
| 1735 | p2[0] = start; | 1747 | p->BeginAddress = start; |
| 1736 | p2[1] = end; | 1748 | p->EndAddress = end; |
| 1737 | p2[2] = pe_uw->offs_1; | 1749 | p->UnwindData = d; |
| 1750 | |||
| 1738 | /* put relocations on it */ | 1751 | /* put relocations on it */ |
| 1739 | put_elf_reloc(symtab_section, pd, o2, R_X86_64_RELATIVE, pe_uw->sym_1); | 1752 | for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) |
| 1740 | put_elf_reloc(symtab_section, pd, o2+4, R_X86_64_RELATIVE, pe_uw->sym_1); | 1753 | put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym); |
| 1741 | put_elf_reloc(symtab_section, pd, o2+8, R_X86_64_RELATIVE, pe_uw->sym_2); | ||
| 1742 | } | 1754 | } |
| 1743 | #endif | 1755 | #endif |
| 1744 | |||
| 1745 | /* ------------------------------------------------------------- */ | 1756 | /* ------------------------------------------------------------- */ |
| 1746 | #ifdef TCC_TARGET_X86_64 | 1757 | #ifdef TCC_TARGET_X86_64 |
| 1747 | #define PE_STDSYM(n,s) n | 1758 | #define PE_STDSYM(n,s) n |
| @@ -30,6 +30,10 @@ static int rt_get_caller_pc(uplong *paddr, ucontext_t *uc, int level); · 29 unmodified lines | |||
| 30 | static void rt_error(ucontext_t *uc, const char *fmt, ...); | 30 | static void rt_error(ucontext_t *uc, const char *fmt, ...); |
| 31 | static int tcc_relocate_ex(TCCState *s1, void *ptr); | 31 | static int tcc_relocate_ex(TCCState *s1, void *ptr); |
| 32 | 32 | ||
| 33 | #ifdef _WIN64 | ||
| 34 | static void win64_add_function_table(TCCState *s1); | ||
| 35 | #endif | ||
| 36 | |||
| 33 | /* ------------------------------------------------------------- */ | 37 | /* ------------------------------------------------------------- */ |
| 34 | /* Do all relocations (needed before using tcc_get_symbol()) | 38 | /* Do all relocations (needed before using tcc_get_symbol()) |
| 35 | Returns -1 on error. */ | 39 | Returns -1 on error. */ |
| @@ -189,6 +193,10 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr) · 153 unmodified lines | |||
| 189 | set_pages_executable(s1->runtime_plt_and_got, | 193 | set_pages_executable(s1->runtime_plt_and_got, |
| 190 | s1->runtime_plt_and_got_offset); | 194 | s1->runtime_plt_and_got_offset); |
| 191 | #endif | 195 | #endif |
| 196 | |||
| 197 | #ifdef _WIN64 | ||
| 198 | win64_add_function_table(s1); | ||
| 199 | #endif | ||
| 192 | return 0; | 200 | return 0; |
| 193 | } | 201 | } |
| 194 | 202 | ||
| @@ -578,6 +586,17 @@ static void set_exception_handler(void) · 383 unmodified lines | |||
| 578 | SetUnhandledExceptionFilter(cpu_exception_handler); | 586 | SetUnhandledExceptionFilter(cpu_exception_handler); |
| 579 | } | 587 | } |
| 580 | 588 | ||
| 589 | #ifdef _WIN64 | ||
| 590 | static void win64_add_function_table(TCCState *s1) | ||
| 591 | { | ||
| 592 | RtlAddFunctionTable( | ||
| 593 | (RUNTIME_FUNCTION*)(uplong)s1->uw_pdata->sh_addr, | ||
| 594 | s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION), | ||
| 595 | (uplong)text_section->sh_addr | ||
| 596 | ); | ||
| 597 | } | ||
| 598 | #endif | ||
| 599 | |||
| 581 | #ifdef _WIN64 | 600 | #ifdef _WIN64 |
| 582 | #define Eip Rip | 601 | #define Eip Rip |
| 583 | #define Ebp Rbp | 602 | #define Ebp Rbp |
| @@ -57,17 +57,9 @@ P0: · 56 unmodified lines | |||
| 57 | /* ---------------------------------------------- */ | 57 | /* ---------------------------------------------- */ |
| 58 | /* setjmp/longjmp support */ | 58 | /* setjmp/longjmp support */ |
| 59 | 59 | ||
| 60 | .globl tinyc_no_getbp | ||
| 61 | tinyc_no_getbp: | ||
| 62 | .byte 0x90 | ||
| 63 | |||
| 64 | .globl tinyc_getbp | 60 | .globl tinyc_getbp |
| 65 | tinyc_getbp: | 61 | tinyc_getbp: |
| 66 | xor %rax,%rax | ||
| 67 | cmp %al,tinyc_no_getbp(%rax) | ||
| 68 | je t1 | ||
| 69 | mov %rbp,%rax | 62 | mov %rbp,%rax |
| 70 | t1: | ||
| 71 | ret | 63 | ret |
| 72 | 64 | ||
| 73 | /* ---------------------------------------------- */ | 65 | /* ---------------------------------------------- */ |
| @@ -549,7 +549,9 @@ ResetEvent · 548 unmodified lines | |||
| 549 | ResetNLSUserInfoCache | 549 | ResetNLSUserInfoCache |
| 550 | ResetWriteWatch | 550 | ResetWriteWatch |
| 551 | ResumeThread | 551 | ResumeThread |
| 552 | RtlAddFunctionTable | ||
| 552 | RtlFillMemory | 553 | RtlFillMemory |
| 554 | RtlInstallFunctionTableCallback | ||
| 553 | RtlMoveMemory | 555 | RtlMoveMemory |
| 554 | RtlUnwind | 556 | RtlUnwind |
| 555 | RtlZeroMemory | 557 | RtlZeroMemory |
| @@ -772,8 +772,6 @@ void gfunc_epilog(void) · 771 unmodified lines | |||
| 772 | /* align local size to word & save local variables */ | 772 | /* align local size to word & save local variables */ |
| 773 | v = (func_scratch + -loc + 15) & -16; | 773 | v = (func_scratch + -loc + 15) & -16; |
| 774 | 774 | ||
| 775 | pe_add_unwind_data(ind, saved_ind, v); | ||
| 776 | |||
| 777 | if (v >= 4096) { | 775 | if (v >= 4096) { |
| 778 | Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); | 776 | Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
| 779 | oad(0xb8, v); /* mov stacksize, %eax */ | 777 | oad(0xb8, v); /* mov stacksize, %eax */ |
| @@ -785,7 +783,10 @@ void gfunc_epilog(void) · 5 unmodified lines | |||
| 785 | o(0xec8148); /* sub rsp, stacksize */ | 783 | o(0xec8148); /* sub rsp, stacksize */ |
| 786 | gen_le32(v); | 784 | gen_le32(v); |
| 787 | } | 785 | } |
| 788 | ind = saved_ind; | 786 | |
| 787 | cur_text_section->data_offset = saved_ind; | ||
| 788 | pe_add_unwind_data(ind, saved_ind, v); | ||
| 789 | ind = cur_text_section->data_offset; | ||
| 789 | } | 790 | } |
| 790 | 791 | ||
| 791 | #else | 792 | #else |