diff options
Diffstat (limited to 'language/static/linux.e')
| -rw-r--r-- | language/static/linux.e | 153 |
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 ; + |