ARM64 iOS Release版二进制中无unwind信息的浮点函数如何展开?
ARM64 iOS Release 二进制浮点函数的栈展开方案
针对你遇到的这个ARM64 iOS Release版二进制函数——无__unwind_info/__eh_frame展开信息、序言涉及浮点寄存器保存无法使用紧凑展开但兼容DWARF格式的情况,可以通过以下几种方式完成栈展开:
一、手动解析函数序言完成栈展开
首先拆解给定的函数序言指令,明确栈帧布局和寄存器保存规则:
stp d15, d14, [sp,#-160]! // 预分配160字节栈空间,同时保存d14、d15到栈顶(sp_old - 160) stp d13, d12, [sp,#16] // 保存d12、d13到 sp + 16(即sp_old - 144) stp d11, d10, [sp,#32] // 保存d10、d11到 sp + 32(即sp_old - 128) stp d9, d8, [sp,#48] // 保存d8、d9到 sp + 48(即sp_old - 112) stp x28, x27, [sp,#64] // 保存x27、x28到 sp + 64(即sp_old - 96) stp x26, x25, [sp,#80] // 保存x25、x26到 sp + 80(即sp_old - 80) stp x24, x23, [sp,#96] // 保存x23、x24到 sp + 96(即sp_old - 64) stp x22, x21, [sp,#112] // 保存x21、x22到 sp + 112(即sp_old - 48) stp x20, x19, [sp,#128] // 保存x19、x20到 sp + 128(即sp_old - 32) stp x29, x30, [sp,#144] // 保存x29(旧帧指针)、x30(返回地址)到 sp + 144(即sp_old - 16) add x29, sp, #0x90 // 将新帧指针x29设置为 sp + 0x90(即sp_old - 16,刚好是旧x29的保存位置) sub sp, sp, #0x190 // 额外分配400字节局部变量空间,总栈帧大小为160+400=560字节
基于上述分析,手动展开步骤如下:
- 恢复上一级帧指针(旧x29):直接读取当前x29指向的内存值,即
*(uint64_t*)x29 - 恢复返回地址(旧x30):读取当前x29+8位置的内存值,即
*(uint64_t*)(x29 + 8) - 恢复调用前的栈指针(sp_old):当前sp加上总栈帧大小560,即
sp + 0x230(0x160+0x190=0x230) - 若需要恢复浮点寄存器,从预分配的栈空间按对应偏移读取即可,比如d8保存在
sp + 48位置,d9在sp + 56位置,以此类推。
二、借助LLDB工具实现辅助/自动展开
LLDB能够解析符合DWARF规则的函数序言,自动推导栈展开信息:
- 用LLDB加载目标二进制,在目标函数入口设置断点:
breakpoint set -n <函数名> - 断点命中后,直接执行
bt(或thread backtrace)命令,LLDB会自动解析序言的栈操作,完成栈展开。 - 若默认自动展开失效,可手动操作:
- 执行
p/x *(uint64_t*)$x29得到上一级帧指针 - 执行
p/x *(uint64_t*)($x29 + 8)得到上一级返回地址 - 手动设置寄存器:
register write x29 <旧x29值>、register write sp $sp + 0x230,再执行bt即可展开上一级栈帧。
- 执行
三、手动构造DWARF CFI信息(长期分析场景)
如果需要让调试工具永久识别该函数的展开规则,可以手动构造DWARF调用帧信息(CFI)并注入到二进制中:
.cfi_startproc .cfi_def_cfa sp, 0 // 调用前的CFA(调用帧地址)为sp .cfi_offset x29, -16 // 旧x29保存在sp_old -16位置 .cfi_offset x30, -8 // 旧x30保存在sp_old -8位置 // 浮点寄存器偏移定义 .cfi_offset d8, -112 .cfi_offset d9, -104 .cfi_offset d10, -128 .cfi_offset d11, -120 .cfi_offset d12, -144 .cfi_offset d13, -136 .cfi_offset d14, -160 .cfi_offset d15, -152 .cfi_def_cfa_offset 560 // 总栈帧大小560字节 .cfi_endproc
将这段CFI信息嵌入到二进制的__eh_frame段,或通过调试符号注入工具关联到目标函数,后续调试工具即可自动识别展开规则。
内容的提问来源于stack exchange,提问作者Seva Alekseyev
相关产品推荐
相关产品推荐

