ASSEMBLY / CHAPTER 12
Leaf functions and calling contracts
MasterWrite a small System V AMD64 leaf routine with explicit register responsibilities.
By the end of this chapter
- Use declared argument and return registers
- Preserve callee-saved registers when touched
- Separate a callable routine from a complete program
The idea
Enter with registers, pointers, and stack concepts understood. Under the System V AMD64 calling convention used for ordinary Linux functions, the first integer or pointer arguments arrive in RDI and RSI, and a simple integer return value uses RAX. A leaf routine makes no further calls. It is still part of a larger program with a caller, valid arguments, and a return address.
Registers such as RBX must retain their incoming values when the routine returns, while caller-saved registers may be clobbered under the convention. The example avoids callee-saved registers entirely and leaves the stack pointer unchanged. More complex routines that make calls must also respect stack alignment and other ABI rules. These snippets are learning fragments; they perform no system call and produce no console output.
; NASM-style conceptual leaf routine
; Contract: unsigned 64-bit a in RDI, b in RSI
; Return low 64 bits of a+b in RAX
add_pair:
lea rax, [rdi+rsi]
retFor RDI=9 and RSI=4, returns RAX=13; no console output.
The routine computes the result in the return register, changes no callee-saved register, and returns to its caller.
Try it yourself
Write a leaf routine that returns the larger of two unsigned arguments without modifying callee-saved registers.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING