Summary
On AArch64, the frame pointer (x29) and stack pointer (sp) differ when stack adjustments occur outside the standard prologue/epilogue, such as during dynamic stack allocation or when handling variable-length data. This discrepancy is critical for frame-pointer-based unwinding, which relies on x29 to track function call frames independently of sp.
Root Cause
The root cause lies in non-standard stack modifications that occur outside the function’s prologue and epilogue. Specifically:
- Dynamic stack allocation: When the stack grows or shrinks mid-function (e.g.,
allocaor variable-length arrays). - Manual stack adjustments: Explicit modifications to
spwithout updatingx29.
Why This Happens in Real Systems
In real systems, this occurs when:
- Variable-length data is allocated on the stack.
- Optimized code avoids redundant frame pointer updates for performance.
- Exception handling or debugging tools require precise frame unwinding.
Real-World Impact
- Debugging: Tools like
gdbrely onx29for stack unwinding; mismatches lead to incorrect backtraces. - Performance: Unnecessary
x29updates can slow down function calls. - Security: Incorrect frame pointers can hinder exploit mitigation techniques like stack canaries.
Example or Code (if necessary and relevant)
void example() {
int arr[100]; // Dynamic stack allocation
// Here, sp is adjusted, but x29 remains unchanged
}
In the assembly, sp would be decremented by 400 (for arr), but x29 would not be updated, causing a mismatch.
How Senior Engineers Fix It
Senior engineers:
- Avoid dynamic stack allocation where possible.
- Manually update
x29whenspis adjusted mid-function. - Use compiler flags like
-fno-omit-frame-pointerto enforce frame pointer consistency.
Why Juniors Miss It
Juniors often:
- Assume
x29andspare always synchronized, ignoring edge cases. - Overlook dynamic stack allocation and its impact on frame pointers.
- Rely solely on compiler defaults, missing manual adjustments needed for correctness.