Add assembly based libcontext implementation for MSVC builds

This commit is contained in:
Marek Roszko 2021-03-03 20:27:37 -05:00
parent 1fc399fa31
commit 320b519278
7 changed files with 649 additions and 4 deletions

View File

@ -9,9 +9,28 @@ if( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STR
)
endif()
list(APPEND LIBCONTEXT_SOURCES
libcontext.cpp
)
if( MSVC )
enable_language(ASM_MASM)
if ( NOT CMAKE_SIZEOF_VOID_P EQUAL 8 )
list(APPEND LIBCONTEXT_SOURCES
make_i386_ms_pe_masm.asm
jump_i386_ms_pe_masm.asm
)
elseif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
list(APPEND LIBCONTEXT_SOURCES
make_x86_64_ms_pe_masm.asm
jump_x86_64_ms_pe_masm.asm
)
endif()
endif()
add_library( libcontext OBJECT
libcontext.cpp
${LIBCONTEXT_SOURCES}
)
target_include_directories( libcontext PUBLIC

View File

@ -0,0 +1,142 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ---------------------------------------------------------------------------------
; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
; ---------------------------------------------------------------------------------
; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch |
; ---------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI |
; ---------------------------------------------------------------------------------
; ---------------------------------------------------------------------------------
; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
; ---------------------------------------------------------------------------------
; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch |
; ---------------------------------------------------------------------------------
; | ESI | EBX | EBP | EIP | EXIT | | SEH NXT |SEH HNDLR|
; ---------------------------------------------------------------------------------
.386
.XMM
.model flat, c
.code
jump_fcontext PROC EXPORT
; fourth arg of jump_fcontext() == flag indicating preserving FPU
mov ecx, [esp+010h]
push ebp ; save EBP
push ebx ; save EBX
push esi ; save ESI
push edi ; save EDI
assume fs:nothing
; load NT_TIB into ECX
mov edx, fs:[018h]
assume fs:error
; load current SEH exception list
mov eax, [edx]
push eax
; load current stack base
mov eax, [edx+04h]
push eax
; load current stack limit
mov eax, [edx+08h]
push eax
; load current deallocation stack
mov eax, [edx+0e0ch]
push eax
; load fiber local storage
mov eax, [edx+010h]
push eax
; prepare stack for FPU
lea esp, [esp-08h]
; test for flag preserve_fpu
test ecx, ecx
je nxt1
; save MMX control- and status-word
stmxcsr [esp]
; save x87 control-word
fnstcw [esp+04h]
nxt1:
; first arg of jump_fcontext() == context jumping from
mov eax, [esp+030h]
; store ESP (pointing to context-data) in EAX
mov [eax], esp
; second arg of jump_fcontext() == context jumping to
mov edx, [esp+034h]
; third arg of jump_fcontext() == value to be returned after jump
mov eax, [esp+038h]
; restore ESP (pointing to context-data) from EDX
mov esp, edx
; test for flag preserve_fpu
test ecx, ecx
je nxt2
; restore MMX control- and status-word
ldmxcsr [esp]
; restore x87 control-word
fldcw [esp+04h]
nxt2:
; prepare stack for FPU
lea esp, [esp+08h]
assume fs:nothing
; load NT_TIB into ECX
mov edx, fs:[018h]
assume fs:error
; restore fiber local storage
pop ecx
mov [edx+010h], ecx
; restore current deallocation stack
pop ecx
mov [edx+0e0ch], ecx
; restore current stack limit
pop ecx
mov [edx+08h], ecx
; restore current stack base
pop ecx
mov [edx+04h], ecx
; restore current SEH exception list
pop ecx
mov [edx], ecx
pop edi ; save EDI
pop esi ; save ESI
pop ebx ; save EBX
pop ebp ; save EBP
; restore return-address
pop edx
; use value in EAX as return-value after jump
; use value in EAX as first arg in context function
mov [esp+04h], eax
; indirect jump to context
jmp edx
jump_fcontext ENDP
END

View File

@ -0,0 +1,216 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ----------------------------------------------------------------------------------
; | 0 | 1 | |
; ----------------------------------------------------------------------------------
; | 0x0 | 0x4 | |
; ----------------------------------------------------------------------------------
; | <indicator> | |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
; ----------------------------------------------------------------------------------
; | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | 0x20 | 0x24 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
; ----------------------------------------------------------------------------------
; | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | 0x40 | 0x44 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
; ----------------------------------------------------------------------------------
; | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | 0x60 | 0x64 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
; ----------------------------------------------------------------------------------
; | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | 0x80 | 0x84 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
; ----------------------------------------------------------------------------------
; | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | 0xa0 | 0xa4 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
; ----------------------------------------------------------------------------------
; | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | 0xc0 | 0xc4 |
; ----------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| <alignment> | fbr_strg | fc_dealloc |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
; ----------------------------------------------------------------------------------
; | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | 0xe0 | 0xe4 |
; ----------------------------------------------------------------------------------
; | limit | base | R12 | R13 |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
; ----------------------------------------------------------------------------------
; | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | 0x100 | 0x104 |
; ----------------------------------------------------------------------------------
; | R14 | R15 | RDI | RSI |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
; ----------------------------------------------------------------------------------
; | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | 0x120 | 0x124 |
; ----------------------------------------------------------------------------------
; | RBX | RBP | RIP | EXIT |
; ----------------------------------------------------------------------------------
.code
jump_fcontext PROC EXPORT FRAME
.endprolog
push rbp ; save RBP
push rbx ; save RBX
push rsi ; save RSI
push rdi ; save RDI
push r15 ; save R15
push r14 ; save R14
push r13 ; save R13
push r12 ; save R12
; load NT_TIB
mov r10, gs:[030h]
; save current stack base
mov rax, [r10+08h]
push rax
; save current stack limit
mov rax, [r10+010h]
push rax
; save current deallocation stack
mov rax, [r10+01478h]
push rax
; save fiber local storage
mov rax, [r10+018h]
push rax
; prepare stack for FPU
lea rsp, [rsp-0a8h]
; test for flag preserve_fpu
test r9, r9
je nxt1
; save MMX control- and status-word
stmxcsr [rsp+0a0h]
; save x87 control-word
fnstcw [rsp+0a4h]
; save XMM storage
movaps [rsp], xmm6
movaps [rsp+010h], xmm7
movaps [rsp+020h], xmm8
movaps [rsp+030h], xmm9
movaps [rsp+040h], xmm10
movaps [rsp+050h], xmm11
movaps [rsp+060h], xmm12
movaps [rsp+070h], xmm13
movaps [rsp+080h], xmm14
movaps [rsp+090h], xmm15
nxt1:
; set R10 to zero
xor r10, r10
; set indicator
push r10
; store RSP (pointing to context-data) in RCX
mov [rcx], rsp
; restore RSP (pointing to context-data) from RDX
mov rsp, rdx
; load indicator
pop r10
; test for flag preserve_fpu
test r9, r9
je nxt2
; restore MMX control- and status-word
ldmxcsr [rsp+0a0h]
; save x87 control-word
fldcw [rsp+0a4h]
; restore XMM storage
movaps xmm6, [rsp]
movaps xmm7, [rsp+010h]
movaps xmm8, [rsp+020h]
movaps xmm9, [rsp+030h]
movaps xmm10, [rsp+040h]
movaps xmm11, [rsp+050h]
movaps xmm12, [rsp+060h]
movaps xmm13, [rsp+070h]
movaps xmm14, [rsp+080h]
movaps xmm15, [rsp+090h]
nxt2:
; set offset of stack
mov rcx, 0a8h
; test for indicator
test r10, r10
je nxt3
add rcx, 08h
nxt3:
; prepare stack for FPU
lea rsp, [rsp+rcx]
; load NT_TIB
mov r10, gs:[030h]
; restore fiber local storage
pop rax
mov [r10+018h], rax
; restore deallocation stack
pop rax
mov [r10+01478h], rax
; restore stack limit
pop rax
mov [r10+010h], rax
; restore stack base
pop rax
mov [r10+08h], rax
pop r12 ; restore R12
pop r13 ; restore R13
pop r14 ; restore R14
pop r15 ; restore R15
pop rdi ; restore RDI
pop rsi ; restore RSI
pop rbx ; restore RBX
pop rbp ; restore RBP
; restore return-address
pop r10
; use third arg as return-value after jump
mov rax, r8
; use third arg as first arg in context function
mov rcx, r8
; indirect jump to context
jmp r10
jump_fcontext ENDP
END

View File

@ -1340,7 +1340,7 @@ __asm (
#endif
#if defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386)
#if defined(LIBCONTEXT_USE_WINFIBER) && (defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386))
#include <map>
@ -1411,7 +1411,7 @@ void LIBCONTEXT_CALL_CONVENTION release_fcontext( fcontext_t ctx )
};
#endif
#else // defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386)
#else // defined(LIBCONTEXT_USE_WINFIBER) && (defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386))
#ifdef __cplusplus
extern "C" {

View File

@ -78,9 +78,11 @@
#define LIBCONTEXT_CALL_CONVENTION
#endif
#endif
#elif defined (_MSC_VER)
#elif defined (_MSC_VER )
#if defined( LIBCONTEXT_USE_WINFIBER )
#define LIBCONTEXT_HAS_OWN_STACK
#endif
#define LIBCONTEXT_CALL_CONVENTION __cdecl

View File

@ -0,0 +1,122 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ---------------------------------------------------------------------------------
; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
; ---------------------------------------------------------------------------------
; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch |
; ---------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI |
; ---------------------------------------------------------------------------------
; ---------------------------------------------------------------------------------
; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
; ---------------------------------------------------------------------------------
; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch |
; ---------------------------------------------------------------------------------
; | ESI | EBX | EBP | EIP | EXIT | | SEH NXT |SEH HNDLR|
; ---------------------------------------------------------------------------------
.386
.XMM
.model flat, c
; standard C library function
_exit PROTO, value:SDWORD
.code
make_fcontext PROC EXPORT
; first arg of make_fcontext() == top of context-stack
mov eax, [esp+04h]
; reserve space for first argument of context-function
; EAX might already point to a 16byte border
lea eax, [eax-08h]
; shift address in EAX to lower 16 byte boundary
and eax, -16
; reserve space for context-data on context-stack
; size for fc_mxcsr .. EIP + return-address for context-function
; on context-function entry: (ESP -0x4) % 8 == 0
; additional space is required for SEH
lea eax, [eax-03ch]
; first arg of make_fcontext() == top of context-stack
mov ecx, [esp+04h]
; save top address of context stack as 'base'
mov [eax+014h], ecx
; second arg of make_fcontext() == size of context-stack
mov edx, [esp+08h]
; negate stack size for LEA instruction (== substraction)
neg edx
; compute bottom address of context stack (limit)
lea ecx, [ecx+edx]
; save bottom address of context-stack as 'limit'
mov [eax+010h], ecx
; save bottom address of context-stack as 'dealloction stack'
mov [eax+0ch], ecx
; third arg of make_fcontext() == address of context-function
mov ecx, [esp+0ch]
mov [eax+02ch], ecx
; save MMX control- and status-word
stmxcsr [eax]
; save x87 control-word
fnstcw [eax+04h]
; compute abs address of label finish
mov ecx, finish
; save address of finish as return-address for context-function
; will be entered after context-function returns
mov [eax+030h], ecx
; traverse current seh chain to get the last exception handler installed by Windows
; note that on Windows Server 2008 and 2008 R2, SEHOP is activated by default
; the exception handler chain is tested for the presence of ntdll.dll!FinalExceptionHandler
; at its end by RaiseException all seh-handlers are disregarded if not present and the
; program is aborted
assume fs:nothing
; load NT_TIB into ECX
mov ecx, fs:[0h]
assume fs:error
walk:
; load 'next' member of current SEH into EDX
mov edx, [ecx]
; test if 'next' of current SEH is last (== 0xffffffff)
inc edx
jz found
dec edx
; exchange content; ECX contains address of next SEH
xchg edx, ecx
; inspect next SEH
jmp walk
found:
; load 'handler' member of SEH == address of last SEH handler installed by Windows
mov ecx, [ecx+04h]
; save address in ECX as SEH handler for context
mov [eax+03ch], ecx
; set ECX to -1
mov ecx, 0ffffffffh
; save ECX as next SEH item
mov [eax+038h], ecx
; load address of next SEH item
lea ecx, [eax+038h]
; save next SEH
mov [eax+018h], ecx
ret ; return pointer to context-data
finish:
; exit code is zero
xor eax, eax
mov [esp], eax
; exit application
call _exit
hlt
make_fcontext ENDP
END

View File

@ -0,0 +1,144 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ----------------------------------------------------------------------------------
; | 0 | 1 | |
; ----------------------------------------------------------------------------------
; | 0x0 | 0x4 | |
; ----------------------------------------------------------------------------------
; | <indicator> | |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
; ----------------------------------------------------------------------------------
; | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | 0x20 | 0x24 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
; ----------------------------------------------------------------------------------
; | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | 0x40 | 0x44 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
; ----------------------------------------------------------------------------------
; | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | 0x60 | 0x64 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
; ----------------------------------------------------------------------------------
; | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | 0x80 | 0x84 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
; ----------------------------------------------------------------------------------
; | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | 0xa0 | 0xa4 |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
; ----------------------------------------------------------------------------------
; | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | 0xc0 | 0xc4 |
; ----------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| <alignment> | fbr_strg | fc_dealloc |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
; ----------------------------------------------------------------------------------
; | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | 0xe0 | 0xe4 |
; ----------------------------------------------------------------------------------
; | limit | base | R12 | R13 |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
; ----------------------------------------------------------------------------------
; | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | 0x100 | 0x104 |
; ----------------------------------------------------------------------------------
; | R14 | R15 | RDI | RSI |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
; ----------------------------------------------------------------------------------
; | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | 0x120 | 0x124 |
; ----------------------------------------------------------------------------------
; | RBX | RBP | RIP | EXIT |
; ----------------------------------------------------------------------------------
; standard C library function
EXTERN _exit:PROC
.code
; generate function table entry in .pdata and unwind information in
make_fcontext PROC EXPORT FRAME
; .xdata for a function's structured exception handling unwind behavior
.endprolog
; first arg of make_fcontext() == top of context-stack
mov rax, rcx
; reserve 32byte shadow-space for context-function
sub rax, 028h
; shift address in RAX to lower 16 byte boundary
; == pointer to fcontext_t and address of context stack
and rax, -16
; reserve space for context-data on context-stack
; size for fc_mxcsr .. RIP + return-address for context-function
; on context-function entry: (RSP -0x8) % 16 == 0
sub rax, 0128h
; third arg of make_fcontext() == address of context-function
mov [rax+0118h], r8
; first arg of make_fcontext() == top of context-stack
; save top address of context stack as 'base'
mov [rax+0d0h], rcx
; second arg of make_fcontext() == size of context-stack
; negate stack size for LEA instruction (== substraction)
neg rdx
; compute bottom address of context stack (limit)
lea rcx, [rcx+rdx]
; save bottom address of context stack as 'limit'
mov [rax+0c8h], rcx
; save address of context stack limit as 'dealloction stack'
mov [rax+0c0h], rcx
; save MMX control- and status-word
stmxcsr [rax+0a8h]
; save x87 control-word
fnstcw [rax+0ach]
; compute abs address of label finish
lea rcx, finish
; save address of finish as return-address for context-function
; will be entered after context-function returns
mov [rax+0120h], rcx
; set indicator
mov rcx, 1
mov [rax], rcx
ret ; return pointer to context-data
finish:
; 32byte shadow-space for _exit() are
; already reserved by make_fcontext()
; exit code is zero
xor rcx, rcx
; exit application
call _exit
hlt
make_fcontext ENDP
END