如何修改遵循AAPCS64的ARM64汇编代码以适配PAC/BTI?
ARM64汇编适配PAC/BTI通用指南(含链接属性修复)
先解决链接器属性缺失错误
链接器提示的GNU_PROPERTY_AARCH64_FEATURE_1_BTI属性缺失,有两种修复方式:
- 编译时自动添加:用GCC或Clang编译汇编文件时,添加选项
-mbranch-protection=bti,汇编器会自动给目标文件加上BTI属性,同时生成必要的BTI指令框架。 - 手动添加属性段:如果是纯手写汇编且不用编译器选项,可在代码开头插入以下段:
注意:仅添加属性只是满足链接要求,代码本身仍需适配BTI/PAC才能真正生效。.section .note.gnu.property,"a" .p2align 3 .long 4, 4, 0x5 .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ .long 0x2 /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI */ .long 0, 0, 0
一、BTI(分支目标识别)代码适配
BTI要求所有间接分支的目标必须是合法的BTI指令,防止非法跳转。
- 对外可见函数入口:所有被C/C++或外部函数调用的汇编函数,入口首行必须加
bti c(匹配AAPCS64的C调用约定):.global md5block_arm64 md5block_arm64: bti c // 标记为C调用的合法分支目标 // 原函数逻辑代码 - 内部函数/代码块入口:仅被汇编内部直接跳转的代码块,入口加
bti j:internal_func: bti j // 标记为内部跳转的合法目标 // 代码逻辑 - 间接分支目标校验:所有可能通过寄存器跳转(如
br x0、blr x0)到达的代码位置,必须添加对应BTI指令,否则会触发硬件异常。
二、PAC(指针认证)代码适配
PAC用于验证返回地址完整性,防范栈溢出篡改返回地址,需严格遵循AAPCS64约定:
- 函数入口生成PAC:在函数入口(BTI指令后)添加
paciasp,为返回地址(lr寄存器)生成基于栈指针的认证码:md5block_arm64: bti c paciasp // 生成lr的PAC,绑定栈指针上下文 // 原函数逻辑 - 函数出口验证并清除PAC:返回前必须用
autiasp验证PAC有效性并清除,再执行ret:// 函数结尾 autiasp // 验证lr的PAC,清除认证码 ret - 栈帧保存/恢复处理:若函数需保存lr到栈,必须保存带PAC的原始lr值,恢复后再验证:
md5block_arm64: bti c paciasp stp x29, x30, [sp, #-16]! // 保存帧指针和带PAC的lr到栈 mov x29, sp // 函数逻辑 ldp x29, x30, [sp], #16 // 恢复帧指针和带PAC的lr autiasp ret - 间接函数调用处理:调用带PAC的函数指针时,先验证指针的PAC,再执行调用:
若需生成函数指针的PAC,使用// x0为带PAC的函数指针 autia1716 x0 // 验证函数指针的PAC(上下文为x17/x16) blr x0 // 调用函数pacia1716指令。
三、编译链接统一配置
- C/C++代码编译:添加
-mbranch-protection=pac+bti,确保编译器生成适配PAC/BTI的代码。 - 汇编代码编译:用
-mbranch-protection=bti(GCC/Clang),让汇编器自动处理指令和属性。 - 链接阶段:使用支持PAC/BTI的链接器(GNU ld 2.34+、LLD 11+),链接选项添加
-z bti和-z pac-plt(若使用PLT)。
内容的提问来源于stack exchange,提问作者fuz
相关产品推荐
相关产品推荐

