Main source: “Anatomy of a System Call”, on lwn 1, 2. READ THIS FIRST
Calling a syscall is done by firing a specific interrupt, and the parameters have to be placed in specific registers first. The kernel then handles the interrupt as explained in the above articles. (I’m not going to copy those texts here.)
Each syscall is identified by its number, which should be placed in a specific
regsiter before invoking the syscall. A table can be found in your system’s
include/asm*/unistd*.h files. Note that syscall numbers are
architecture-dependent and some syscalls aren’t implemented on certain hardware
platforms, and some are only available in later versions of the kernel.
On i386, syscalls are invoked using the int 0x80 instruction. The syscall
number is placed in eax, arguments are placed in ebx, ecx, edx, esi,
edi registers. The return value is placed in the eax register.
On x86_64, syscalls are invoked using the syscall instruction. The syscall
number is placed in rax, arguments are placed in rdi, rsi, rdx, r10,
r8 and r9. r11 and rcx are destroyed when invoking a syscall. The
return value is placed in the rax register.
This is probably true for ARMv5 and ARMv7 as well. No guarantees for ARMv8 (aarch64).
Syscalls are invoked using the swi #0 instruction. The syscall number is
placed in r7, arguments are placed in r0 through r6. The return value is
placed in the r0 register.