about summary refs log tree commit diff
path: root/language/static/linux.e
diff options
context:
space:
mode:
Diffstat (limited to 'language/static/linux.e')
-rw-r--r--language/static/linux.e153
1 files changed, 153 insertions, 0 deletions
diff --git a/language/static/linux.e b/language/static/linux.e
new file mode 100644
index 0000000..fd15ae0
--- /dev/null
+++ b/language/static/linux.e
@@ -0,0 +1,153 @@
+~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~ ~~ System calls for the Linux kernel ~~
+~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~
+~   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, or we can use one of the other registers. We
+~ don't ourselves save other registers because our caller should do that, if
+~ it cares.
+~
+~   In the kernel source, you may find the following files useful to
+~ reference:
+~
+~   * arch/x86/entry/syscalls/syscall_64.tbl
+~   * include/linux/syscalls.h
+~   * include/linux/compat.h
+~
+~   Don't be confused by tools/scripts/syscall.tbl, it's not for x86.
+~
+~   This file loads early, before anything in language/dynamic/. So, although
+~ it superficially appears to be able to do allocation and high-level flow
+~ control, those come from the transforms, which means they're shallow
+~ implementations. The stuff here can't be moved later, because
+~ language/dynamic/input.e relies on it, and the other dynamic stuff relies on
+~ that. So, there's additional Linux functionality in another file that loads
+~ later, language/dynamic/linux.e.
+
+
+~ (call number -- return value)
+: syscall-0
+  [ here @
+    :rax pop-reg64               ~ syscall number
+    syscall
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+~ (first param, call number -- return value)
+: syscall-1
+  [ here @
+    :rax pop-reg64               ~ syscall number
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+~ (first param, second param, call number -- return value)
+: syscall-2
+  [ here @
+    :rsi :rbx mov-reg64-reg64    ~ save rsi
+    :rax pop-reg64               ~ syscall number
+    :rsi pop-reg64               ~ second param
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rbx :rsi mov-reg64-reg64    ~ restore rsi
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+~ (first param, second param, third param, call number -- return value)
+: syscall-3
+  [ here @
+    :rsi :rbx mov-reg64-reg64    ~ save rsi
+    :rax pop-reg64               ~ syscall number
+    :rdx pop-reg64               ~ third param
+    :rsi pop-reg64               ~ second param
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rbx :rsi mov-reg64-reg64    ~ restore rsi
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+~ (first param, second param, third param, fourth param, call number
+~  -- return value)
+: syscall-4
+  [ here @
+    :rsi :rbx mov-reg64-reg64    ~ save rsi
+    :rax pop-reg64               ~ syscall number
+    :r10 pop-extrareg64          ~ fourth param
+    :rdx pop-reg64               ~ third param
+    :rsi pop-reg64               ~ second param
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rbx :rsi mov-reg64-reg64    ~ restore rsi
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+
+~ (first param, second param, third param, fourth param, fifth param,
+~  call number -- return value)
+: syscall-5
+  [ here @
+    :rsi :rbx mov-reg64-reg64    ~ save rsi
+    :rax pop-reg64               ~ syscall number
+    :r8 pop-extrareg64           ~ fifth param
+    :r10 pop-extrareg64          ~ fourth param
+    :rdx pop-reg64               ~ third param
+    :rsi pop-reg64               ~ second param
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rbx :rsi mov-reg64-reg64    ~ restore rsi
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+
+~ (first param, second param, third param, fourth param, fifth param,
+~  sixth param, call number -- return value)
+: syscall-6
+  [ here @
+    :rsi :rbx mov-reg64-reg64    ~ save rsi
+    :rax pop-reg64               ~ syscall number
+    :r9 pop-extrareg64           ~ sixth param
+    :r8 pop-extrareg64           ~ fifth param
+    :r10 pop-extrareg64          ~ fourth param
+    :rdx pop-reg64               ~ third param
+    :rsi pop-reg64               ~ second param
+    :rdi pop-reg64               ~ first param
+    syscall
+    :rbx :rsi mov-reg64-reg64    ~ restore rsi
+    :rax push-reg64              ~ return value
+    here ! ] ;asm
+
+
+~ Raw system calls
+~ ~~~~~~~~~~~~~~~~
+
+~   This does the Linux exit() system call, passing it an exit code taken
+~ from the stack. It does not return.
+~
+~ (exit code -- *)
+: sys-exit 60 syscall-1
+  ~ In the event we're still here, let's minimize confusion.
+  crash ;
+
+~   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
+~ uses a Unix file descriptor, which is a non-negative integer, to tell it
+~ where to write to. For stdout, use fd 1.
+~
+~ (file descriptor, base address, length to write -- result code or length)
+: sys-write 1 syscall-3 ;
+
+~ (file descriptor, base address, length to read -- result code or length)
+: sys-read 0 syscall-3 ;
+
+~ (filename, flags, mode -- result code or file descriptor)
+: sys-open 2 syscall-3 ;
+
+~ (file descriptor -- result code)
+: sys-close 3 syscall-1 ;
+