在函数入口将X30(LR)保存到x18所指向的shadow callstack里;在函数返回时将x18所指向的shadow callstack里的LR pop到X30(LR)
push 2d5bc: d10183ff sub sp, sp, #0x60 2d5c0: f800865e str x30, [x18],#8 2d5c4: a9027bfd stp x29, x30, [sp,#32] pop 2d6b8: a9427bfd ldp x29, x30, [sp,#32] 2d6bc: f9401bf7 ldr x23, [sp,#48] 2d6c0: f85f8e5e ldr x30, [x18,#-8]!
从上面的汇编指令可以看出:
1. shadow callstack里保存的数据都是函数调用栈的返回地址(X30(LR))
2. shadow callstack增长方向是向上递增的,跟legacy stack的向下增长是相反的
3. legacy stack中仍然有保存x29/x30,所以其它的unwinder仍然能根据其获得callstack,但是程序执行流程返回地址不再使用它,而是使用x18所指向的shadow callstack里的