~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ ~~ 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. ~ (call number -- return value) : syscall-0 [ here @ :rax pop-reg64 ~ syscall number syscall :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param -- return value) : syscall-1 [ here @ :rdi pop-reg64 ~ first param :rax pop-reg64 ~ syscall number syscall :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param, second param -- return value) : syscall-2 [ here @ :rsi :rbx mov-reg64-reg64 ~ save rsi :rsi pop-reg64 ~ second param :rdi pop-reg64 ~ first param :rax pop-reg64 ~ syscall number syscall :rbx :rsi mov-reg64-reg64 ~ restore rsi :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param, second param, third param -- return value) : syscall-3 [ here @ :rsi :rbx mov-reg64-reg64 ~ save rsi :rdx pop-reg64 ~ third param :rsi pop-reg64 ~ second param :rdi pop-reg64 ~ first param :rax pop-reg64 ~ syscall number syscall :rbx :rsi mov-reg64-reg64 ~ restore rsi :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param, second param, third param, fourth param ~ -- return value) : syscall-4 [ here @ :rsi :rbx mov-reg64-reg64 ~ save rsi :r10 pop-extrareg64 ~ fourth param :rdx pop-reg64 ~ third param :rsi pop-reg64 ~ second param :rdi pop-reg64 ~ first param :rax pop-reg64 ~ syscall number syscall :rbx :rsi mov-reg64-reg64 ~ restore rsi :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param, second param, third param, fourth param, ~ fifth param -- return value) : syscall-5 [ here @ :rsi :rbx mov-reg64-reg64 ~ save rsi :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 :rax pop-reg64 ~ syscall number syscall :rbx :rsi mov-reg64-reg64 ~ restore rsi :rax push-reg64 ~ return value here ! ] ;asm ~ (call number, first param, second param, third param, fourth param, ~ fifth param, sixth param -- return value) : syscall-6 [ here @ :rsi :rbx mov-reg64-reg64 ~ save rsi :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 :rax pop-reg64 ~ syscall number syscall :rbx :rsi mov-reg64-reg64 ~ restore rsi :rax push-reg64 ~ return value here ! ] ;asm ~ 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