diff options
author | Rokas Kupstys <rokups@zoho.com> | 2017-02-20 17:10:50 +0200 |
---|---|---|
committer | Rokas Kupstys <rokups@zoho.com> | 2017-02-20 17:24:19 +0200 |
commit | 373e667dbc6aff5dd74f5ada139d867287e9dc1f (patch) | |
tree | 41da1a7c7298e8ae5f146b528446b3d279480aca /lib/arch | |
parent | a3b8bf300df20f2922275ff62293e3f882cad090 (diff) | |
download | Nim-373e667dbc6aff5dd74f5ada139d867287e9dc1f.tar.gz |
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.
Diffstat (limited to 'lib/arch')
-rw-r--r-- | lib/arch/arch.nim | 62 | ||||
-rw-r--r-- | lib/arch/i386.asm | 79 | ||||
-rw-r--r-- | lib/arch/ms_amd64.asm | 90 | ||||
-rw-r--r-- | lib/arch/ms_i386.asm | 12 | ||||
-rw-r--r-- | lib/arch/unix_amd64.asm | 89 | ||||
-rw-r--r-- | lib/arch/unix_i386.asm | 12 | ||||
-rw-r--r-- | lib/arch/x86/amd64.S | 96 | ||||
-rw-r--r-- | lib/arch/x86/i386.S | 64 |
8 files changed, 160 insertions, 344 deletions
diff --git a/lib/arch/arch.nim b/lib/arch/arch.nim deleted file mode 100644 index 0b3df3d3c..000000000 --- a/lib/arch/arch.nim +++ /dev/null @@ -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.} diff --git a/lib/arch/i386.asm b/lib/arch/i386.asm deleted file mode 100644 index 61f6fdda7..000000000 --- a/lib/arch/i386.asm +++ /dev/null @@ -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 diff --git a/lib/arch/ms_amd64.asm b/lib/arch/ms_amd64.asm deleted file mode 100644 index 0503b31c9..000000000 --- a/lib/arch/ms_amd64.asm +++ /dev/null @@ -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 diff --git a/lib/arch/ms_i386.asm b/lib/arch/ms_i386.asm deleted file mode 100644 index a31a698d1..000000000 --- a/lib/arch/ms_i386.asm +++ /dev/null @@ -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' diff --git a/lib/arch/unix_amd64.asm b/lib/arch/unix_amd64.asm deleted file mode 100644 index 3005c150c..000000000 --- a/lib/arch/unix_amd64.asm +++ /dev/null @@ -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 diff --git a/lib/arch/unix_i386.asm b/lib/arch/unix_i386.asm deleted file mode 100644 index 278679067..000000000 --- a/lib/arch/unix_i386.asm +++ /dev/null @@ -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' diff --git a/lib/arch/x86/amd64.S b/lib/arch/x86/amd64.S new file mode 100644 index 000000000..47a26f627 --- /dev/null +++ b/lib/arch/x86/amd64.S @@ -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 diff --git a/lib/arch/x86/i386.S b/lib/arch/x86/i386.S new file mode 100644 index 000000000..d7de4a4c3 --- /dev/null +++ b/lib/arch/x86/i386.S @@ -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 |