ASSEMBLY / CHAPTER 12

Leaf functions and calling contracts

Master

Write 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.

Assembly example
; 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]
ret
Result
For 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

Chapter checkpoint

A leaf routine uses RBX as scratch under System V AMD64. What must it guarantee?