diff options
author | Mike Pall <mike> | 2016-05-07 12:32:15 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2016-05-07 12:32:15 +0200 |
commit | 35b09e692ead67181755795352f1df12547fd4fa (patch) | |
tree | d120dd561f649f955ddbbe844fe00a97f7b9e625 /src | |
parent | 6a9973203c55daa4c1fcd611718bc5df09e4e5b5 (diff) | |
download | luajit-35b09e692ead67181755795352f1df12547fd4fa.tar.gz luajit-35b09e692ead67181755795352f1df12547fd4fa.tar.bz2 luajit-35b09e692ead67181755795352f1df12547fd4fa.zip |
Windows/x86: Add full exception interoperability.
Contributed by Peter Cawley.
Diffstat (limited to 'src')
-rw-r--r-- | src/host/buildvm.c | 2 | ||||
-rw-r--r-- | src/host/buildvm_peobj.c | 28 | ||||
-rw-r--r-- | src/lj_err.c | 38 | ||||
-rw-r--r-- | src/lj_frame.h | 12 | ||||
-rw-r--r-- | src/lj_vm.h | 4 | ||||
-rw-r--r-- | src/vm_x86.dasc | 77 |
6 files changed, 147 insertions, 14 deletions
diff --git a/src/host/buildvm.c b/src/host/buildvm.c index 6d9e09e1..57b4dc97 100644 --- a/src/host/buildvm.c +++ b/src/host/buildvm.c | |||
@@ -110,7 +110,7 @@ static const char *sym_decorate(BuildCtx *ctx, | |||
110 | if (p) { | 110 | if (p) { |
111 | #if LJ_TARGET_X86ORX64 | 111 | #if LJ_TARGET_X86ORX64 |
112 | if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) | 112 | if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) |
113 | name[0] = '@'; | 113 | name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */ |
114 | else | 114 | else |
115 | *p = '\0'; | 115 | *p = '\0'; |
116 | #elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE | 116 | #elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE |
diff --git a/src/host/buildvm_peobj.c b/src/host/buildvm_peobj.c index e8c927d8..42f6ac84 100644 --- a/src/host/buildvm_peobj.c +++ b/src/host/buildvm_peobj.c | |||
@@ -109,6 +109,8 @@ enum { | |||
109 | #if LJ_TARGET_X64 | 109 | #if LJ_TARGET_X64 |
110 | PEOBJ_SECT_PDATA, | 110 | PEOBJ_SECT_PDATA, |
111 | PEOBJ_SECT_XDATA, | 111 | PEOBJ_SECT_XDATA, |
112 | #elif LJ_TARGET_X86 | ||
113 | PEOBJ_SECT_SXDATA, | ||
112 | #endif | 114 | #endif |
113 | PEOBJ_SECT_RDATA_Z, | 115 | PEOBJ_SECT_RDATA_Z, |
114 | PEOBJ_NSECTIONS | 116 | PEOBJ_NSECTIONS |
@@ -208,6 +210,13 @@ void emit_peobj(BuildCtx *ctx) | |||
208 | sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; | 210 | sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; |
209 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ | 211 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ |
210 | pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; | 212 | pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; |
213 | #elif LJ_TARGET_X86 | ||
214 | memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1); | ||
215 | pesect[PEOBJ_SECT_SXDATA].ofs = sofs; | ||
216 | sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4); | ||
217 | pesect[PEOBJ_SECT_SXDATA].relocofs = sofs; | ||
218 | /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */ | ||
219 | pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240; | ||
211 | #endif | 220 | #endif |
212 | 221 | ||
213 | memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); | 222 | memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); |
@@ -232,7 +241,7 @@ void emit_peobj(BuildCtx *ctx) | |||
232 | nrsym = ctx->nrelocsym; | 241 | nrsym = ctx->nrelocsym; |
233 | pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; | 242 | pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; |
234 | #if LJ_TARGET_X64 | 243 | #if LJ_TARGET_X64 |
235 | pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */ | 244 | pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */ |
236 | #endif | 245 | #endif |
237 | 246 | ||
238 | /* Write PE object header and all sections. */ | 247 | /* Write PE object header and all sections. */ |
@@ -312,6 +321,19 @@ void emit_peobj(BuildCtx *ctx) | |||
312 | reloc.type = PEOBJ_RELOC_ADDR32NB; | 321 | reloc.type = PEOBJ_RELOC_ADDR32NB; |
313 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | 322 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); |
314 | } | 323 | } |
324 | #elif LJ_TARGET_X86 | ||
325 | /* Write .sxdata section. */ | ||
326 | for (i = 0; i < nrsym; i++) { | ||
327 | if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) { | ||
328 | uint32_t symidx = 1+2+i; | ||
329 | owrite(ctx, &symidx, 4); | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | if (i == nrsym) { | ||
334 | fprintf(stderr, "Error: extern lj_err_unwind_win not used\n"); | ||
335 | exit(1); | ||
336 | } | ||
315 | #endif | 337 | #endif |
316 | 338 | ||
317 | /* Write .rdata$Z section. */ | 339 | /* Write .rdata$Z section. */ |
@@ -333,8 +355,10 @@ void emit_peobj(BuildCtx *ctx) | |||
333 | #if LJ_TARGET_X64 | 355 | #if LJ_TARGET_X64 |
334 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); | 356 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); |
335 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); | 357 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); |
336 | emit_peobj_sym(ctx, "lj_err_unwind_win64", 0, | 358 | emit_peobj_sym(ctx, "lj_err_unwind_win", 0, |
337 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); | 359 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); |
360 | #elif LJ_TARGET_X86 | ||
361 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA); | ||
338 | #endif | 362 | #endif |
339 | 363 | ||
340 | emit_peobj_sym(ctx, ctx->beginsym, 0, | 364 | emit_peobj_sym(ctx, ctx->beginsym, 0, |
diff --git a/src/lj_err.c b/src/lj_err.c index a847ca07..1314c8db 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
@@ -46,7 +46,8 @@ | |||
46 | ** the wrapper function feature. Lua errors thrown through C++ frames | 46 | ** the wrapper function feature. Lua errors thrown through C++ frames |
47 | ** cannot be caught by C++ code and C++ destructors are not run. | 47 | ** cannot be caught by C++ code and C++ destructors are not run. |
48 | ** | 48 | ** |
49 | ** EXT is the default on x64 systems, INT is the default on all other systems. | 49 | ** EXT is the default on x64 systems and on Windows, INT is the default on all |
50 | ** other systems. | ||
50 | ** | 51 | ** |
51 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack | 52 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack |
52 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled | 53 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled |
@@ -55,7 +56,6 @@ | |||
55 | ** and all C libraries that have callbacks which may be used to call back | 56 | ** and all C libraries that have callbacks which may be used to call back |
56 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. | 57 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. |
57 | ** | 58 | ** |
58 | ** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH. | ||
59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance | 59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance |
60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). | 60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). |
61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). | 61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). |
@@ -63,7 +63,7 @@ | |||
63 | 63 | ||
64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND | 64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND |
65 | #define LJ_UNWIND_EXT 1 | 65 | #define LJ_UNWIND_EXT 1 |
66 | #elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS | 66 | #elif LJ_TARGET_WINDOWS |
67 | #define LJ_UNWIND_EXT 1 | 67 | #define LJ_UNWIND_EXT 1 |
68 | #endif | 68 | #endif |
69 | 69 | ||
@@ -384,7 +384,7 @@ static void err_raise_ext(int errcode) | |||
384 | 384 | ||
385 | #endif /* LJ_TARGET_ARM */ | 385 | #endif /* LJ_TARGET_ARM */ |
386 | 386 | ||
387 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | 387 | #elif LJ_ABI_WIN |
388 | 388 | ||
389 | /* | 389 | /* |
390 | ** Someone in Redmond owes me several days of my life. A lot of this is | 390 | ** Someone in Redmond owes me several days of my life. A lot of this is |
@@ -402,6 +402,7 @@ static void err_raise_ext(int errcode) | |||
402 | #define WIN32_LEAN_AND_MEAN | 402 | #define WIN32_LEAN_AND_MEAN |
403 | #include <windows.h> | 403 | #include <windows.h> |
404 | 404 | ||
405 | #if LJ_TARGET_X64 | ||
405 | /* Taken from: http://www.nynaeve.net/?p=99 */ | 406 | /* Taken from: http://www.nynaeve.net/?p=99 */ |
406 | typedef struct UndocumentedDispatcherContext { | 407 | typedef struct UndocumentedDispatcherContext { |
407 | ULONG64 ControlPc; | 408 | ULONG64 ControlPc; |
@@ -416,11 +417,14 @@ typedef struct UndocumentedDispatcherContext { | |||
416 | ULONG ScopeIndex; | 417 | ULONG ScopeIndex; |
417 | ULONG Fill0; | 418 | ULONG Fill0; |
418 | } UndocumentedDispatcherContext; | 419 | } UndocumentedDispatcherContext; |
420 | #else | ||
421 | typedef void *UndocumentedDispatcherContext; | ||
422 | #endif | ||
419 | 423 | ||
420 | /* Another wild guess. */ | 424 | /* Another wild guess. */ |
421 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | 425 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); |
422 | 426 | ||
423 | #ifdef MINGW_SDK_INIT | 427 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) |
424 | /* Workaround for broken MinGW64 declaration. */ | 428 | /* Workaround for broken MinGW64 declaration. */ |
425 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | 429 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); |
426 | #define RtlUnwindEx RtlUnwindEx_FIXED | 430 | #define RtlUnwindEx RtlUnwindEx_FIXED |
@@ -434,10 +438,15 @@ VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | |||
434 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 438 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) |
435 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | 439 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) |
436 | 440 | ||
437 | /* Win64 exception handler for interpreter frame. */ | 441 | /* Windows exception handler for interpreter frame. */ |
438 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | 442 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win(EXCEPTION_RECORD *rec, |
439 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | 443 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) |
440 | { | 444 | { |
445 | #if LJ_TARGET_X64 | ||
446 | void *cf = f; | ||
447 | #else | ||
448 | void *cf = (char *)f - CFRAME_OFS_SEH; | ||
449 | #endif | ||
441 | lua_State *L = cframe_L(cf); | 450 | lua_State *L = cframe_L(cf); |
442 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | 451 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? |
443 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | 452 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; |
@@ -457,6 +466,7 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
457 | /* Don't catch access violations etc. */ | 466 | /* Don't catch access violations etc. */ |
458 | return ExceptionContinueSearch; | 467 | return ExceptionContinueSearch; |
459 | } | 468 | } |
469 | #if LJ_TARGET_X64 | ||
460 | /* Unwind the stack and call all handlers for all lower C frames | 470 | /* Unwind the stack and call all handlers for all lower C frames |
461 | ** (including ourselves) again with EH_UNWINDING set. Then set | 471 | ** (including ourselves) again with EH_UNWINDING set. Then set |
462 | ** rsp = cf, rax = errcode and jump to the specified target. | 472 | ** rsp = cf, rax = errcode and jump to the specified target. |
@@ -466,6 +476,18 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
466 | lj_vm_unwind_c_eh), | 476 | lj_vm_unwind_c_eh), |
467 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | 477 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); |
468 | /* RtlUnwindEx should never return. */ | 478 | /* RtlUnwindEx should never return. */ |
479 | #else | ||
480 | UNUSED(ctx); | ||
481 | UNUSED(dispatch); | ||
482 | /* Call all handlers for all lower C frames (including ourselves) again | ||
483 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
484 | ** and errcode. | ||
485 | */ | ||
486 | lj_vm_rtlunwind(cf, (void *)rec, | ||
487 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
488 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
489 | /* lj_vm_rtlunwind does not return. */ | ||
490 | #endif | ||
469 | } | 491 | } |
470 | } | 492 | } |
471 | return ExceptionContinueSearch; | 493 | return ExceptionContinueSearch; |
diff --git a/src/lj_frame.h b/src/lj_frame.h index fc0e281c..db2e4da1 100644 --- a/src/lj_frame.h +++ b/src/lj_frame.h | |||
@@ -116,6 +116,17 @@ enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ | |||
116 | 116 | ||
117 | /* These definitions must match with the arch-specific *.dasc files. */ | 117 | /* These definitions must match with the arch-specific *.dasc files. */ |
118 | #if LJ_TARGET_X86 | 118 | #if LJ_TARGET_X86 |
119 | #if LJ_ABI_WIN | ||
120 | #define CFRAME_OFS_ERRF (19*4) | ||
121 | #define CFRAME_OFS_NRES (18*4) | ||
122 | #define CFRAME_OFS_PREV (17*4) | ||
123 | #define CFRAME_OFS_L (16*4) | ||
124 | #define CFRAME_OFS_SEH (9*4) | ||
125 | #define CFRAME_OFS_PC (6*4) | ||
126 | #define CFRAME_OFS_MULTRES (5*4) | ||
127 | #define CFRAME_SIZE (16*4) | ||
128 | #define CFRAME_SHIFT_MULTRES 0 | ||
129 | #else | ||
119 | #define CFRAME_OFS_ERRF (15*4) | 130 | #define CFRAME_OFS_ERRF (15*4) |
120 | #define CFRAME_OFS_NRES (14*4) | 131 | #define CFRAME_OFS_NRES (14*4) |
121 | #define CFRAME_OFS_PREV (13*4) | 132 | #define CFRAME_OFS_PREV (13*4) |
@@ -124,6 +135,7 @@ enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ | |||
124 | #define CFRAME_OFS_MULTRES (5*4) | 135 | #define CFRAME_OFS_MULTRES (5*4) |
125 | #define CFRAME_SIZE (12*4) | 136 | #define CFRAME_SIZE (12*4) |
126 | #define CFRAME_SHIFT_MULTRES 0 | 137 | #define CFRAME_SHIFT_MULTRES 0 |
138 | #endif | ||
127 | #elif LJ_TARGET_X64 | 139 | #elif LJ_TARGET_X64 |
128 | #if LJ_ABI_WIN | 140 | #if LJ_ABI_WIN |
129 | #define CFRAME_OFS_PREV (13*8) | 141 | #define CFRAME_OFS_PREV (13*8) |
diff --git a/src/lj_vm.h b/src/lj_vm.h index be35295d..d605b143 100644 --- a/src/lj_vm.h +++ b/src/lj_vm.h | |||
@@ -17,6 +17,10 @@ LJ_ASMF int lj_vm_cpcall(lua_State *L, lua_CFunction func, void *ud, | |||
17 | LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); | 17 | LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); |
18 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode); | 18 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode); |
19 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe); | 19 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe); |
20 | #if LJ_ABI_WIN && LJ_TARGET_X86 | ||
21 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_rtlunwind(void *cframe, void *excptrec, | ||
22 | void *unwinder, int errcode); | ||
23 | #endif | ||
20 | LJ_ASMF void lj_vm_unwind_c_eh(void); | 24 | LJ_ASMF void lj_vm_unwind_c_eh(void); |
21 | LJ_ASMF void lj_vm_unwind_ff_eh(void); | 25 | LJ_ASMF void lj_vm_unwind_ff_eh(void); |
22 | #if LJ_TARGET_X86ORX64 | 26 | #if LJ_TARGET_X86ORX64 |
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index f108c0b5..39ccaa2e 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc | |||
@@ -121,19 +121,68 @@ | |||
121 | |//----------------------------------------------------------------------- | 121 | |//----------------------------------------------------------------------- |
122 | |.if not X64 // x86 stack layout. | 122 | |.if not X64 // x86 stack layout. |
123 | | | 123 | | |
124 | |.define CFRAME_SPACE, aword*7 // Delta for esp (see <--). | 124 | |.if WIN |
125 | | | ||
126 | |.define CFRAME_SPACE, aword*9 // Delta for esp (see <--). | ||
125 | |.macro saveregs_ | 127 | |.macro saveregs_ |
126 | | push edi; push esi; push ebx | 128 | | push edi; push esi; push ebx |
129 | | push extern lj_err_unwind_win | ||
130 | | fs; push dword [0] | ||
131 | | fs; mov [0], esp | ||
127 | | sub esp, CFRAME_SPACE | 132 | | sub esp, CFRAME_SPACE |
128 | |.endmacro | 133 | |.endmacro |
129 | |.macro saveregs | 134 | |.macro restoreregs |
130 | | push ebp; saveregs_ | 135 | | add esp, CFRAME_SPACE |
136 | | fs; pop dword [0] | ||
137 | | pop edi // Short for esp += 4. | ||
138 | | pop ebx; pop esi; pop edi; pop ebp | ||
139 | |.endmacro | ||
140 | | | ||
141 | |.else | ||
142 | | | ||
143 | |.define CFRAME_SPACE, aword*7 // Delta for esp (see <--). | ||
144 | |.macro saveregs_ | ||
145 | | push edi; push esi; push ebx | ||
146 | | sub esp, CFRAME_SPACE | ||
131 | |.endmacro | 147 | |.endmacro |
132 | |.macro restoreregs | 148 | |.macro restoreregs |
133 | | add esp, CFRAME_SPACE | 149 | | add esp, CFRAME_SPACE |
134 | | pop ebx; pop esi; pop edi; pop ebp | 150 | | pop ebx; pop esi; pop edi; pop ebp |
135 | |.endmacro | 151 | |.endmacro |
136 | | | 152 | | |
153 | |.endif | ||
154 | | | ||
155 | |.macro saveregs | ||
156 | | push ebp; saveregs_ | ||
157 | |.endmacro | ||
158 | | | ||
159 | |.if WIN | ||
160 | |.define SAVE_ERRF, aword [esp+aword*19] // vm_pcall/vm_cpcall only. | ||
161 | |.define SAVE_NRES, aword [esp+aword*18] | ||
162 | |.define SAVE_CFRAME, aword [esp+aword*17] | ||
163 | |.define SAVE_L, aword [esp+aword*16] | ||
164 | |//----- 16 byte aligned, ^^^ arguments from C caller | ||
165 | |.define SAVE_RET, aword [esp+aword*15] //<-- esp entering interpreter. | ||
166 | |.define SAVE_R4, aword [esp+aword*14] | ||
167 | |.define SAVE_R3, aword [esp+aword*13] | ||
168 | |.define SAVE_R2, aword [esp+aword*12] | ||
169 | |//----- 16 byte aligned | ||
170 | |.define SAVE_R1, aword [esp+aword*11] | ||
171 | |.define SEH_FUNC, aword [esp+aword*10] | ||
172 | |.define SEH_NEXT, aword [esp+aword*9] //<-- esp after register saves. | ||
173 | |.define UNUSED2, aword [esp+aword*8] | ||
174 | |//----- 16 byte aligned | ||
175 | |.define UNUSED1, aword [esp+aword*7] | ||
176 | |.define SAVE_PC, aword [esp+aword*6] | ||
177 | |.define TMP2, aword [esp+aword*5] | ||
178 | |.define TMP1, aword [esp+aword*4] | ||
179 | |//----- 16 byte aligned | ||
180 | |.define ARG4, aword [esp+aword*3] | ||
181 | |.define ARG3, aword [esp+aword*2] | ||
182 | |.define ARG2, aword [esp+aword*1] | ||
183 | |.define ARG1, aword [esp] //<-- esp while in interpreter. | ||
184 | |//----- 16 byte aligned, ^^^ arguments for C callee | ||
185 | |.else | ||
137 | |.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only. | 186 | |.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only. |
138 | |.define SAVE_NRES, aword [esp+aword*14] | 187 | |.define SAVE_NRES, aword [esp+aword*14] |
139 | |.define SAVE_CFRAME, aword [esp+aword*13] | 188 | |.define SAVE_CFRAME, aword [esp+aword*13] |
@@ -154,6 +203,7 @@ | |||
154 | |.define ARG2, aword [esp+aword*1] | 203 | |.define ARG2, aword [esp+aword*1] |
155 | |.define ARG1, aword [esp] //<-- esp while in interpreter. | 204 | |.define ARG1, aword [esp] //<-- esp while in interpreter. |
156 | |//----- 16 byte aligned, ^^^ arguments for C callee | 205 | |//----- 16 byte aligned, ^^^ arguments for C callee |
206 | |.endif | ||
157 | | | 207 | | |
158 | |// FPARGx overlaps ARGx and ARG(x+1) on x86. | 208 | |// FPARGx overlaps ARGx and ARG(x+1) on x86. |
159 | |.define FPARG3, qword [esp+qword*1] | 209 | |.define FPARG3, qword [esp+qword*1] |
@@ -554,6 +604,10 @@ static void build_subroutines(BuildCtx *ctx) | |||
554 | |.else | 604 | |.else |
555 | | mov eax, FCARG2 // Error return status for vm_pcall. | 605 | | mov eax, FCARG2 // Error return status for vm_pcall. |
556 | | mov esp, FCARG1 | 606 | | mov esp, FCARG1 |
607 | |.if WIN | ||
608 | | lea FCARG1, SEH_NEXT | ||
609 | | fs; mov [0], FCARG1 | ||
610 | |.endif | ||
557 | |.endif | 611 | |.endif |
558 | |->vm_unwind_c_eh: // Landing pad for external unwinder. | 612 | |->vm_unwind_c_eh: // Landing pad for external unwinder. |
559 | | mov L:RB, SAVE_L | 613 | | mov L:RB, SAVE_L |
@@ -577,6 +631,10 @@ static void build_subroutines(BuildCtx *ctx) | |||
577 | |.else | 631 | |.else |
578 | | and FCARG1, CFRAME_RAWMASK | 632 | | and FCARG1, CFRAME_RAWMASK |
579 | | mov esp, FCARG1 | 633 | | mov esp, FCARG1 |
634 | |.if WIN | ||
635 | | lea FCARG1, SEH_NEXT | ||
636 | | fs; mov [0], FCARG1 | ||
637 | |.endif | ||
580 | |.endif | 638 | |.endif |
581 | |->vm_unwind_ff_eh: // Landing pad for external unwinder. | 639 | |->vm_unwind_ff_eh: // Landing pad for external unwinder. |
582 | | mov L:RB, SAVE_L | 640 | | mov L:RB, SAVE_L |
@@ -590,6 +648,19 @@ static void build_subroutines(BuildCtx *ctx) | |||
590 | | set_vmstate INTERP | 648 | | set_vmstate INTERP |
591 | | jmp ->vm_returnc // Increments RD/MULTRES and returns. | 649 | | jmp ->vm_returnc // Increments RD/MULTRES and returns. |
592 | | | 650 | | |
651 | |.if WIN and not X64 | ||
652 | |->vm_rtlunwind@16: // Thin layer around RtlUnwind. | ||
653 | | // (void *cframe, void *excptrec, void *unwinder, int errcode) | ||
654 | | mov [esp], FCARG1 // Return value for RtlUnwind. | ||
655 | | push FCARG2 // Exception record for RtlUnwind. | ||
656 | | push 0 // Ignored by RtlUnwind. | ||
657 | | push dword [FCARG1+CFRAME_OFS_SEH] | ||
658 | | call extern RtlUnwind@16 // Violates ABI (clobbers too much). | ||
659 | | mov FCARG1, eax | ||
660 | | mov FCARG2, [esp+4] // errcode (for vm_unwind_c). | ||
661 | | ret // Jump to unwinder. | ||
662 | |.endif | ||
663 | | | ||
593 | |//----------------------------------------------------------------------- | 664 | |//----------------------------------------------------------------------- |
594 | |//-- Grow stack for calls ----------------------------------------------- | 665 | |//-- Grow stack for calls ----------------------------------------------- |
595 | |//----------------------------------------------------------------------- | 666 | |//----------------------------------------------------------------------- |