evocation/syscall-abi-linux.e
2026-09-24 17:47:58 +03:00

122 lines
4.3 KiB
Text

~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ ~~ 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 dynamic.e. 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 input.e relies on it, and the dynamic
~ stuff relies on that. So, there's additional Linux functionality in another
~ file that loads later, linux-dynamic.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