summary refs log tree commit diff
path: root/linux.e
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-05-16 13:53:08 -0700
committerIrene Knapp <ireneista@irenes.space>2026-05-16 13:53:08 -0700
commitfe3de0772dac094b94f8de89efbb815a62b1a2fa (patch)
treecf5fca8004005f5015a6dcfc7c25fd8ff2879d3d /linux.e
parentf4112a05de8bf4c69a7abb9817c7ca70be9f7fb5 (diff)
implement more internal words
Force-Push: yes
Change-Id: I273879e9d05260db0603bc5a36970e240f3e366a
Diffstat (limited to 'linux.e')
-rw-r--r--linux.e69
1 files changed, 69 insertions, 0 deletions
diff --git a/linux.e b/linux.e
new file mode 100644
index 0000000..ce0b9b7
--- /dev/null
+++ b/linux.e
@@ -0,0 +1,69 @@
+~ ~~~~~~~~~~~~~~~~~~
+~ ~~ System calls ~~
+~ ~~~~~~~~~~~~~~~~~~
+~
+~   The kernel preserves every register except rax, rcx, and r11. The system
+~ call number goes in rax, as does the return value. Parameters go in rdi,
+~ rsi, rdx, r10, r8, and r9, in that order. [SysV] A.2.1.
+~
+~   Notice that rsi is our control stack, so we have to save it (for
+~ syscalls with at least two parameters). We can use the value stack to do
+~ that, since rsp is preserved. We don't save other registers because our
+~ caller should do that, if it cares.
+~
+
+~   This does the Linux exit() system call, passing it an exit code taken
+~ from the stack. It does not return.
+~
+~ (exit code -- *)
+: sys-exit
+  [ here @
+    60 :rax mov-reg64-imm64      ~ syscall number
+    :rdi pop-reg64               ~ exit code
+    syscall
+
+    ~ In the event we're still here, let's minimize confusion.
+    hlt
+
+    ~ This one, uniquely, doesn't need to be followed by the "next" macro. It
+    ~ is, though, since ;asm does that anyway.
+    here ! ] ;asm
+
+
+~   This does the Linux write() system call, passing it an address from the
+~ top of the stack and a length from the second position on the stack. It
+~ writes to file descriptor 1, which is stdout.
+~
+~   For our length parameter, we can pop directly from the stack into rdx,
+~ which directly becomes the syscall parameter. For our address parameter,
+~ the syscall wants it in rsi, which we also care about, so we have to do a
+~ little juggling.
+~
+~ (length to write, base address -- *)
+: sys-write
+  [ here @
+    :rcx pop-reg64               ~ address from stack
+    :rdx pop-reg64               ~ length from stack, passed directly
+    :rsi push-reg64              ~ save rsi
+    1 :rax mov-reg64-imm64       ~ syscall number
+    1 :rdi mov-reg64-imm64       ~ file descriptor
+    :rcx :rsi mov-reg64-reg64    ~ pass address
+    syscall
+    :rsi pop-reg64               ~ restore rsi
+    here ! ] ;asm
+
+
+~ (length to read, base address -- *)
+: sys-read
+  [ here @
+    :rcx pop-reg64               ~ address from stack
+    :rdx pop-reg64               ~ length from stack, passed directly
+    :rsi push-reg64              ~ save rsi
+    0 :rax mov-reg64-imm64       ~ syscall number
+    0 :rdi mov-reg64-imm64       ~ file descriptor
+    :rcx :rsi mov-reg64-reg64    ~ pass address
+    syscall
+    :rsi pop-reg64               ~ restore rsi
+    :rax push-reg64              ~ return length
+    here ! ] ;asm
+