; Nicholas Noll 2019 ; ; =================================================================== %use altreg bits 64 default rel global _newcoro global _coroyield ; =================================================================== section .text ; ------------------------------------------------------------------- %assign L.coro -8 %assign L.func -16 coroinit: mov R7, [RBP + L.coro] mov R6, R0 call [RBP + L.func] rerun: mov R7, [RBP + L.coro] mov R6, R0 call _coroyield jmp rerun ; ------------------------------------------------------------------- ; # Register Mapping ; ; R0 R1 R2 R3 R4 R5 R6 R7 R8 ... ; RAX RCX RDX RBX RSP RBP RSI RDI R8 ... ; ; # Sys V calling convention ; func(R7, R6, R2, R1, R8, R9, Z0-7): R0 ; ; # Stack layout of an in-flight coro ; ^coro ; ^func ; ^bp (base pointer of stack) ; ....... STACK ......... ; Saved Clobbers ; ; ### ; Stack layout of an init coro ; Stores the func pointer to init ; Stores the clobber registers. ; ; L.coro [8] ; L.func [7] ; coroinit [6] ; RBP [5] ; R3 [4] ; R12 [3] ; R13 [2] ; R14 [1] ; R15 [0] %define WORDS 8 %define SAVES 9 ; func sys.newCoro(co ^coro, fn func, bp ^stack) _newcoro: lea R0, [coroinit] lea R1, [R2 - SAVES*WORDS] mov [R1 + 8*WORDS], R7 mov [R1 + 7*WORDS], R6 mov [R1 + 6*WORDS], R0 mov [R1 + 5*WORDS], R2 xor R0, R0 ; Blank out the clobbers mov [R1 + 4*WORDS], R0 ; R3 mov [R1 + 3*WORDS], R0 ; R12 mov [R1 + 2*WORDS], R0 ; R13 mov [R1 + 1*WORDS], R0 ; R14 mov [R1 + 0*WORDS], R0 ; R15 mov [R7], R1 ret %macro pushclobs 0 push RBP push R3 push R12 push R13 push R14 push R15 %endmacro %macro popclobs 0 pop R15 pop R14 pop R13 pop R12 pop R3 pop RBP %endmacro ; func coro.yield(co ^coro, ret uintptr) _coroyield: pushclobs mov R0, R6 ; Move return value into return register. xchg RSP, [R7] ; Atomically swap the stack pointer with the yieldee. popclobs ret