aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/internal/task/task_stack_amd64.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/task/task_stack_amd64.S')
-rw-r--r--src/internal/task/task_stack_amd64.S74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/internal/task/task_stack_amd64.S b/src/internal/task/task_stack_amd64.S
new file mode 100644
index 000000000..44b5f065b
--- /dev/null
+++ b/src/internal/task/task_stack_amd64.S
@@ -0,0 +1,74 @@
+#ifdef __MACH__ // Darwin
+.global _tinygo_startTask
+_tinygo_startTask:
+#else // Linux etc
+.section .text.tinygo_startTask
+.global tinygo_startTask
+tinygo_startTask:
+#endif
+ .cfi_startproc
+ // Small assembly stub for starting a goroutine. This is already run on the
+ // new stack, with the callee-saved registers already loaded.
+ // Most importantly, r12 contain the pc of the to-be-started function and
+ // r13 contain the only argument it is given. Multiple arguments are packed
+ // into one by storing them in a new allocation.
+
+ // Indicate to the unwinder that there is nothing to unwind, this is the
+ // root frame. It avoids bogus extra frames in GDB like here:
+ // #10 0x00000000004277b6 in <goroutine wrapper> () at [...]
+ // #11 0x00000000004278f3 in tinygo_startTask () at [...]
+ // #12 0x0000000000002030 in ?? ()
+ // #13 0x0000000000000071 in ?? ()
+ .cfi_undefined rip
+
+ // Set the first argument of the goroutine start wrapper, which contains all
+ // the arguments.
+ movq %r13, %rdi
+
+ // Branch to the "goroutine start" function.
+ callq *%r12
+
+ // After return, exit this goroutine. This is a tail call.
+ #ifdef __MACH__
+ jmp _tinygo_pause
+ #else
+ jmp tinygo_pause
+ #endif
+ .cfi_endproc
+
+#ifdef __MACH__ // Darwin
+.global _tinygo_swapTask
+_tinygo_swapTask:
+#else // Linux etc
+.global tinygo_swapTask
+.section .text.tinygo_swapTask
+tinygo_swapTask:
+#endif
+ // This function gets the following parameters:
+ // %rdi = newStack uintptr
+ // %rsi = oldStack *uintptr
+
+ // Save all callee-saved registers:
+ pushq %r15
+ pushq %r14
+ pushq %r13
+ pushq %r12
+ pushq %rbp
+ pushq %rbx
+
+ // Save the current stack pointer in oldStack.
+ movq %rsp, (%rsi)
+
+ // Switch to the new stack pointer.
+ movq %rdi, %rsp
+
+ // Load saved register from the new stack.
+ popq %rbx
+ popq %rbp
+ popq %r12
+ popq %r13
+ popq %r14
+ popq %r15
+
+ // Return into the new task, as if tinygo_swapTask was a regular call.
+ ret