Coroutine rework.
* ucontext backend (default on unix)
* setjmp backend
* fibers backend (default and required on windows)
* Fixed coroutine loop timing issues
* Fixed saving of xmm registers on x64 windows
* Fixed alignment issues
* Updated coroutine sample with cooperative fibonacci calculation.
* Disable glibc security features only when platform jump functions are used
* Removed dependency on fasm.
* Using fiber api on windows.
* Other platforms and compilers will use built in assembler and .S files or API provided by platform libc.
* Replaced stack switching procs with `coroExecWithStack()` which never returns. This makes compiler always generate proper code.
This commit is contained in:
parent
a3b8bf300d
commit
373e667dbc
11 changed files with 421 additions and 446 deletions
|
|
@ -1,62 +0,0 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Rokas Kupstys
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
# Architecture-specific optimizations and features.
|
||||
# arch.nim can be imported by only a subset of the
|
||||
# architectures supported by Nim.
|
||||
|
||||
when defined(windows):
|
||||
const
|
||||
ABI* = "ms"
|
||||
elif defined(unix):
|
||||
const
|
||||
ABI* = "unix"
|
||||
else:
|
||||
{.error: "Unsupported ABI".}
|
||||
|
||||
when defined(amd64):
|
||||
when defined(unix):
|
||||
# unix (sysv) ABI
|
||||
type
|
||||
JmpBufReg* {.pure.} = enum
|
||||
BX, BP, R12, R13, R14, R15, SP, IP, TOTAL
|
||||
elif defined(windows):
|
||||
# ms ABI
|
||||
type
|
||||
JmpBufReg* {.pure.} = enum
|
||||
BX, BP, R12, R13, R14, R15, SP, IP, SI, DI, TOTAL
|
||||
type
|
||||
Reg* {.pure.} = enum
|
||||
AX, BX, CX, DX, SI, DI, BP, SP, IP, R8, R9, R10, R11, R12, R13, R14, R15, TOTAL
|
||||
|
||||
elif defined(i386) or defined(nimdoc):
|
||||
# identical fastcall calling convention on all x86 OS
|
||||
type
|
||||
JmpBufReg* {.pure.} = enum
|
||||
BX, SI, DI, BP, SP, IP, TOTAL
|
||||
|
||||
Reg* {.pure.} = enum
|
||||
AX, BX, CX, BP, SP, DI, SI, TOTAL
|
||||
|
||||
else:
|
||||
{.error: "Unsupported architecture".}
|
||||
|
||||
{.compile: "./" & ABI & "_" & hostCPU & ".asm"}
|
||||
|
||||
type
|
||||
JmpBuf* = array[JmpBufReg.TOTAL, pointer]
|
||||
Registers* = array[Reg.TOTAL, pointer]
|
||||
|
||||
|
||||
proc getRegisters*(ctx: var Registers) {.importc: "narch_$1", fastcall.}
|
||||
|
||||
proc setjmp*(ctx: var JmpBuf): int {.importc: "narch_$1", fastcall.}
|
||||
proc longjmp*(ctx: JmpBuf, ret=1) {.importc: "narch_$1", fastcall.}
|
||||
|
||||
proc coroSwitchStack*(sp: pointer) {.importc: "narch_$1", fastcall.}
|
||||
proc coroRestoreStack*() {.importc: "narch_$1", fastcall.}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
;
|
||||
;
|
||||
; Nim's Runtime Library
|
||||
; (c) Copyright 2015 Rokas Kupstys
|
||||
;
|
||||
; See the file "copying.txt", included in this
|
||||
; distribution, for details about the copyright.
|
||||
;
|
||||
|
||||
section ".text" executable
|
||||
public narch_getRegisters
|
||||
public @narch_getRegisters@4
|
||||
public narch_setjmp
|
||||
public @narch_setjmp@4
|
||||
public narch_longjmp
|
||||
public @narch_longjmp@8
|
||||
public narch_coroSwitchStack
|
||||
public @narch_coroSwitchStack@4
|
||||
public narch_coroRestoreStack
|
||||
public @narch_coroRestoreStack@0
|
||||
|
||||
@narch_getRegisters@4:
|
||||
narch_getRegisters:
|
||||
mov [ecx], eax
|
||||
mov [ecx+4], ebx
|
||||
mov [ecx+8], ecx
|
||||
mov [ecx+0Ch], ebp
|
||||
mov [ecx+10h], esp
|
||||
mov [ecx+14h], edi
|
||||
mov [ecx+18h], esi
|
||||
ret
|
||||
|
||||
|
||||
@narch_setjmp@4:
|
||||
narch_setjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov [ecx], ebx
|
||||
mov [ecx+4], esi
|
||||
mov [ecx+8], edi
|
||||
mov [ecx+0Ch], ebp
|
||||
lea eax, [esp+4]
|
||||
mov [ecx+10h], eax
|
||||
mov eax, [esp]
|
||||
mov [ecx+14h], eax
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
|
||||
@narch_longjmp@8:
|
||||
narch_longjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov eax, edx
|
||||
test eax, eax
|
||||
jnz @F
|
||||
inc eax
|
||||
@@:
|
||||
mov ebx, [ecx]
|
||||
mov esi, [ecx+4]
|
||||
mov edi, [ecx+8]
|
||||
mov ebp, [ecx+0Ch]
|
||||
mov esp, [ecx+10h]
|
||||
mov edx, [ecx+14h]
|
||||
jmp edx
|
||||
|
||||
|
||||
@narch_coroSwitchStack@4:
|
||||
narch_coroSwitchStack:
|
||||
pop eax ; return address
|
||||
mov edx, esp ; old esp for saving
|
||||
mov esp, ecx ; swap stack with one passed to func
|
||||
push edx ; store old stack pointer on newly switched stack
|
||||
jmp eax ; return
|
||||
|
||||
|
||||
@narch_coroRestoreStack@0:
|
||||
narch_coroRestoreStack:
|
||||
pop eax ; return address
|
||||
pop esp ; resture old stack pointer
|
||||
jmp eax ; return
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
;
|
||||
;
|
||||
; Nim's Runtime Library
|
||||
; (c) Copyright 2015 Rokas Kupstys
|
||||
;
|
||||
; See the file "copying.txt", included in this
|
||||
; distribution, for details about the copyright.
|
||||
;
|
||||
|
||||
format MS64 COFF
|
||||
|
||||
section ".text" executable align 16
|
||||
public narch_getRegisters
|
||||
public narch_setjmp
|
||||
public narch_longjmp
|
||||
public narch_coroSwitchStack
|
||||
public narch_coroRestoreStack
|
||||
|
||||
|
||||
narch_getRegisters:
|
||||
mov [rcx], rax
|
||||
mov [rcx+8], rbx
|
||||
mov [rcx+10h], rcx
|
||||
mov [rcx+18h], rdx
|
||||
mov [rcx+20h], rsi
|
||||
mov [rcx+28h], rdi
|
||||
mov [rcx+30h], rbp
|
||||
mov [rcx+38h], rsp
|
||||
mov rax, [rsp]
|
||||
mov [rcx+40h], rax ; rip
|
||||
mov [rcx+48h], r8
|
||||
mov [rcx+50h], r9
|
||||
mov [rcx+58h], r10
|
||||
mov [rcx+60h], r11
|
||||
mov [rcx+68h], r12
|
||||
mov [rcx+70h], r13
|
||||
mov [rcx+78h], r14
|
||||
mov [rcx+80h], r15
|
||||
ret
|
||||
|
||||
|
||||
narch_setjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov [rcx], rbx ; rcx is jmp_buf, move registers onto it
|
||||
mov [rcx+8], rbp
|
||||
mov [rcx+10h], r12
|
||||
mov [rcx+18h], r13
|
||||
mov [rcx+20h], r14
|
||||
mov [rcx+28h], r15
|
||||
lea rdx, [rsp+8] ; this is our rsp WITHOUT current ret addr
|
||||
mov [rcx+30h], rdx
|
||||
mov rdx, [rsp] ; save return addr ptr for new rip
|
||||
mov [rcx+38h], rdx
|
||||
mov [rcx+40h], rsi
|
||||
mov [rcx+48h], rdi
|
||||
xor rax, rax ; always return 0
|
||||
ret
|
||||
|
||||
narch_longjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov rax, rdx ; val will be longjmp return
|
||||
test rax, rax
|
||||
jnz @F
|
||||
inc rax ; if val==0, val=1 per longjmp semantics
|
||||
@@:
|
||||
mov rbx, [rcx] ; rax is the jmp_buf, restore regs from it
|
||||
mov rbp, [rcx+8]
|
||||
mov r12, [rcx+10h]
|
||||
mov r13, [rcx+18h]
|
||||
mov r14, [rcx+20h]
|
||||
mov r15, [rcx+28h]
|
||||
mov rsp, [rcx+30h] ; this ends up being the stack pointer
|
||||
mov rdx, [rcx+38h] ; this is the instruction pointer
|
||||
jmp rdx ; goto saved address without altering rsp
|
||||
|
||||
|
||||
narch_coroSwitchStack:
|
||||
pop rax ; return address
|
||||
mov rdx, rsp ; old rsp for saving
|
||||
mov rsp, rcx ; swap stack with one passed to func
|
||||
push rdx ; store old stack pointer on newly switched stack
|
||||
sub rsp, 28h ; stack alignment + shadow space
|
||||
jmp rax ; return
|
||||
|
||||
|
||||
narch_coroRestoreStack:
|
||||
pop rax ; return address
|
||||
add rsp, 28h ; stack alignment + shadow space
|
||||
pop rsp ; resture old stack pointer
|
||||
jmp rax ; return
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
;
|
||||
;
|
||||
; Nim's Runtime Library
|
||||
; (c) Copyright 2015 Rokas Kupstys
|
||||
;
|
||||
; See the file "copying.txt", included in this
|
||||
; distribution, for details about the copyright.
|
||||
;
|
||||
|
||||
format MS COFF
|
||||
|
||||
include 'i386.asm'
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
;
|
||||
;
|
||||
; Nim's Runtime Library
|
||||
; (c) Copyright 2015 Rokas Kupstys
|
||||
;
|
||||
; See the file "copying.txt", included in this
|
||||
; distribution, for details about the copyright.
|
||||
;
|
||||
|
||||
format ELF64
|
||||
|
||||
section ".text" executable align 16
|
||||
public narch_getRegisters
|
||||
public narch_setjmp
|
||||
public narch_longjmp
|
||||
public narch_coroSwitchStack
|
||||
public narch_coroRestoreStack
|
||||
|
||||
|
||||
narch_getRegisters:
|
||||
mov [rdi], rax
|
||||
mov [rdi+8], rbx
|
||||
mov [rdi+10h], rcx
|
||||
mov [rdi+18h], rdx
|
||||
mov [rdi+20h], rsi
|
||||
mov [rdi+28h], rdi
|
||||
mov [rdi+30h], rbp
|
||||
mov [rdi+38h], rsp
|
||||
mov rax, [rsp]
|
||||
mov [rdi+40h], rax ; rip
|
||||
mov [rdi+48h], r8
|
||||
mov [rdi+50h], r9
|
||||
mov [rdi+58h], r10
|
||||
mov [rdi+60h], r11
|
||||
mov [rdi+68h], r12
|
||||
mov [rdi+70h], r13
|
||||
mov [rdi+78h], r14
|
||||
mov [rdi+80h], r15
|
||||
ret
|
||||
|
||||
|
||||
narch_setjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov [rdi], rbx ; rdi is jmp_buf, move registers onto it
|
||||
mov [rdi+8], rbp
|
||||
mov [rdi+10h], r12
|
||||
mov [rdi+18h], r13
|
||||
mov [rdi+20h], r14
|
||||
mov [rdi+28h], r15
|
||||
lea rdx, [rsp+8] ; this is our rsp WITHOUT current ret addr
|
||||
mov [rdi+30h], rdx
|
||||
mov rdx, [rsp] ; save return addr ptr for new rip
|
||||
mov [rdi+38h], rdx
|
||||
xor rax, rax ; always return 0
|
||||
ret
|
||||
|
||||
|
||||
narch_longjmp:
|
||||
; Based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
mov rax, rsi ; val will be longjmp return
|
||||
test rax, rax
|
||||
jnz @F
|
||||
inc rax ; if val==0, val=1 per longjmp semantics
|
||||
@@:
|
||||
mov rbx, [rdi] ; rdi is the jmp_buf, restore regs from it
|
||||
mov rbp, [rdi+8]
|
||||
mov r12, [rdi+10h]
|
||||
mov r13, [rdi+18h]
|
||||
mov r14, [rdi+20h]
|
||||
mov r15, [rdi+28h]
|
||||
mov rsp, [rdi+30h] ; this ends up being the stack pointer
|
||||
mov rdx, [rdi+38h] ; this is the instruction pointer
|
||||
jmp rdx ; goto saved address without altering rsp
|
||||
|
||||
|
||||
narch_coroSwitchStack:
|
||||
pop rsi ; return address
|
||||
mov rdx, rsp ; old rsp for saving
|
||||
mov rsp, rdi ; swap stack with one passed to func
|
||||
push rdx ; store old stack pointer on newly switched stack
|
||||
sub rsp, 8h ; stack alignment
|
||||
jmp rsi ; return
|
||||
|
||||
|
||||
narch_coroRestoreStack:
|
||||
pop rsi ; return address
|
||||
add rsp, 8h ; stack alignment
|
||||
pop rsp ; resture old stack pointer
|
||||
jmp rsi ; return
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
;
|
||||
;
|
||||
; Nim's Runtime Library
|
||||
; (c) Copyright 2015 Rokas Kupstys
|
||||
;
|
||||
; See the file "copying.txt", included in this
|
||||
; distribution, for details about the copyright.
|
||||
;
|
||||
|
||||
format ELF
|
||||
|
||||
include 'i386.asm'
|
||||
96
lib/arch/x86/amd64.S
Normal file
96
lib/arch/x86/amd64.S
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Rokas Kupstys
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
# Partially based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
.globl narch_coroExecWithStack
|
||||
.globl narch_setjmp
|
||||
.globl narch_longjmp
|
||||
.text
|
||||
|
||||
|
||||
# SysV ABI - first argument is rdi.
|
||||
# MS ABI - first argument is rcx.
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#define REG_ARG1 rcx
|
||||
#define REG_ARG2 rdx
|
||||
#else
|
||||
#define REG_ARG1 rdi
|
||||
#define REG_ARG2 rsi
|
||||
#endif
|
||||
|
||||
|
||||
narch_coroExecWithStack:
|
||||
mov %REG_ARG2, %rsp # swap stack with one passed to func
|
||||
sub $0x30, %rsp # shadow space (for ms ABI) 0x20 + 0x10 for possible misalignment
|
||||
and $-0x10, %rsp # 16-byte stack alignment
|
||||
call *%REG_ARG1
|
||||
|
||||
|
||||
narch_setjmp:
|
||||
add $0x10, %REG_ARG1 # 16-byte alignment
|
||||
and $-0x10, %REG_ARG1
|
||||
mov %rbx, 0x00(%REG_ARG1) # jmp_buf, move registers onto it
|
||||
mov %rbp, 0x08(%REG_ARG1)
|
||||
mov %r12, 0x10(%REG_ARG1)
|
||||
mov %r13, 0x18(%REG_ARG1)
|
||||
mov %r14, 0x20(%REG_ARG1)
|
||||
mov %r15, 0x28(%REG_ARG1)
|
||||
lea 0x08(%rsp), %rdx # this is our rsp WITHOUT current ret addr
|
||||
mov %rdx, 0x30(%REG_ARG1)
|
||||
mov (%rsp), %rdx # save return addr ptr for new rip
|
||||
mov %rdx, 0x38(%REG_ARG1)
|
||||
mov %rsi, 0x40(%REG_ARG1)
|
||||
mov %rdi, 0x48(%REG_ARG1)
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
movaps %xmm6, 0x50(%REG_ARG1)
|
||||
movaps %xmm7, 0x60(%REG_ARG1)
|
||||
movaps %xmm8, 0x70(%REG_ARG1)
|
||||
movaps %xmm9, 0x80(%REG_ARG1)
|
||||
movaps %xmm10, 0x90(%REG_ARG1)
|
||||
movaps %xmm11, 0xA0(%REG_ARG1)
|
||||
movaps %xmm12, 0xB0(%REG_ARG1)
|
||||
movaps %xmm13, 0xC0(%REG_ARG1)
|
||||
movaps %xmm14, 0xD0(%REG_ARG1)
|
||||
movaps %xmm15, 0xE0(%REG_ARG1)
|
||||
#endif
|
||||
xor %rax, %rax # always return 0
|
||||
ret
|
||||
|
||||
|
||||
narch_longjmp:
|
||||
add $0x10, %REG_ARG1 # 16-byte alignment
|
||||
and $-0x10, %REG_ARG1 #
|
||||
mov %REG_ARG2, %rax # val will be longjmp return
|
||||
test %rax, %rax
|
||||
jnz narch_longjmp_1
|
||||
inc %rax # if val==0, val=1 per longjmp semantics
|
||||
narch_longjmp_1:
|
||||
mov 0x00(%REG_ARG1), %rbx # jmp_buf, restore regs from it
|
||||
mov 0x08(%REG_ARG1), %rbp
|
||||
mov 0x10(%REG_ARG1), %r12
|
||||
mov 0x18(%REG_ARG1), %r13
|
||||
mov 0x20(%REG_ARG1), %r14
|
||||
mov 0x28(%REG_ARG1), %r15
|
||||
mov 0x30(%REG_ARG1), %rsp # this ends up being the stack pointer
|
||||
mov 0x38(%REG_ARG1), %rdx # this is the instruction pointer
|
||||
mov 0x40(%REG_ARG1), %rsi
|
||||
mov 0x48(%REG_ARG1), %rdi
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
movaps 0x50(%REG_ARG1), %xmm6
|
||||
movaps 0x60(%REG_ARG1), %xmm7
|
||||
movaps 0x70(%REG_ARG1), %xmm8
|
||||
movaps 0x80(%REG_ARG1), %xmm9
|
||||
movaps 0x90(%REG_ARG1), %xmm10
|
||||
movaps 0xA0(%REG_ARG1), %xmm11
|
||||
movaps 0xB0(%REG_ARG1), %xmm12
|
||||
movaps 0xC0(%REG_ARG1), %xmm13
|
||||
movaps 0xD0(%REG_ARG1), %xmm14
|
||||
movaps 0xE0(%REG_ARG1), %xmm15
|
||||
#endif
|
||||
jmp *%rdx # goto saved address without altering rsp
|
||||
64
lib/arch/x86/i386.S
Normal file
64
lib/arch/x86/i386.S
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Rokas Kupstys
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
# Partially based on code from musl libc Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
.globl narch_coroExecWithStack
|
||||
.globl narch_setjmp
|
||||
.globl narch_longjmp
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
.globl @narch_coroExecWithStack@8
|
||||
.globl @narch_setjmp@4
|
||||
.globl @narch_longjmp@8
|
||||
#endif
|
||||
.text
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
@narch_coroExecWithStack@8:
|
||||
#endif
|
||||
narch_coroExecWithStack:
|
||||
mov %edx, %esp # swap stack with one passed to func
|
||||
sub $0x10, %esp # 16-byte alignment
|
||||
and $-0x10, %esp #
|
||||
sub $4, %esp # Simulate misalignment caused by return addr
|
||||
jmp *%ecx
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
@narch_setjmp@4:
|
||||
#endif
|
||||
narch_setjmp:
|
||||
mov %ebx, (%ecx)
|
||||
mov %esi, 0x04(%ecx)
|
||||
mov %edi, 0x08(%ecx)
|
||||
mov %ebp, 0x0C(%ecx)
|
||||
lea 0x04(%esp), %eax
|
||||
mov %eax, 0x10(%ecx)
|
||||
mov (%esp), %eax
|
||||
mov %eax, 0x14(%ecx)
|
||||
xor %eax, %eax
|
||||
ret
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
@narch_longjmp@8:
|
||||
#endif
|
||||
narch_longjmp:
|
||||
mov %edx, %eax
|
||||
test %eax, %eax
|
||||
jnz narch_longjmp_1
|
||||
inc %eax
|
||||
narch_longjmp_1:
|
||||
mov (%ecx), %ebx
|
||||
mov 0x04(%ecx), %esi
|
||||
mov 0x08(%ecx), %edi
|
||||
mov 0x0C(%ecx), %ebp
|
||||
mov 0x10(%ecx), %esp
|
||||
mov 0x14(%ecx), %edx
|
||||
jmp *%edx
|
||||
Loading…
Add table
Add a link
Reference in a new issue