How would you write a minimal "hello, world" using raw x86_64 syscalls, callable from C?
Wrap the write syscall (number 1) and the exit syscall (number 60) in tiny assembly functions; because the function-ABI and syscall registers nearly align, the C arguments are already in the right registers.
This is the classic "first assembly program" done without any libc. The trick: for my_write, the C arguments arrive in %rdi/%rsi/%rdx — exactly where the write syscall wants fd, buf, and count — so you only need to load the syscall number and fire:
.globl my_write
.globl my_exit
.section .text
# ssize_t my_write(int fd, const void *buf, size_t count)
my_write:
mov $1, %rax # rax = 1 (write); rdi/rsi/rdx already hold fd/buf/count
syscall
ret
# void my_exit(int status)
my_exit:
mov $60, %rax # rax = 60 (exit); rdi already holds status
syscall
ret # never reached
Calling it from C:
int main(void) {
my_write(1, "hello, world\n", 13);
my_exit(0);
}
Why it's so short: the only real work is choosing the syscall number and executing syscall. The argument registers (%rdi, %rsi, %rdx) overlap between the function ABI and the syscall ABI for the first three args, so no shuffling is needed.
Go deeper:
SYSCALL — x86 instruction reference — the SYSCALL instruction.
syscall(2) — Linux manual page — the write and exit syscall register layout.
System call (Wikipedia) — system calls overview.