Commissioned for this museum · after the System V AMD64 calling convention
hello, world
x86-64 assembly·2003·19 lines·565 bytes
; x86-64 Linux, NASM syntax. No libc: this talks to the kernel directly.
section .data
message: db "hello, world", 10
length: equ $ - message
section .text
global _start
_start:
mov rax, 1 ; syscall 1 = write
mov rdi, 1 ; fd 1 = stdout
mov rsi, message ; buffer
mov rdx, length ; count
syscall
mov rax, 60 ; syscall 60 = exit
xor rdi, rdi ; status 0
syscallCurator’s note
This is the only greeting in the hall with no library underneath it. There is no printf, no runtime, no main — the C version's one line of output is several thousand instructions of libc once you follow it down. Here the floor is the kernel, and you can see it.
The four mov instructions before each syscall are a form being filled in. On this platform the kernel reads its arguments from named registers, always the same ones and always in the same order: what to do in rax, then the arguments in rdi, rsi, rdx. Loading them is not calling anything. It is arranging the machine so that the single syscall instruction — which hands control to the kernel — finds everything where the kernel will look.
xor rdi, rdi is worth a moment. It sets the exit status to zero by exclusive-ORing a register with itself, which is guaranteed to produce zero and is one byte shorter than saying mov rdi, 0. That idiom is older than most people writing code today and survives because it is still, marginally, the better instruction.
The second syscall is not optional. There is no runtime here to tidy up after the last line, and a program that simply runs off the end of _start falls into whatever bytes follow it in memory.