ARM64内联汇编BL/BLR/BR指令调用异常问题求助
ARM64内联汇编BL调用异常导致main循环无法执行的修复方案
问题根源分析
你的代码核心问题是内联汇编未告知编译器寄存器X30(链接寄存器LR)会被修改,同时存在输出约束与实际汇编逻辑不匹配的问题,导致函数返回地址被破坏,程序执行流异常跳走,因此main函数的for循环无法进入。
具体问题点:
- BL指令会将当前PC+4写入X30,用于函数返回,但你的内联汇编没有在clobber列表中声明X30,编译器会假设X30的值(即
BranchingModes函数的返回地址)保持不变。当myFunction返回后,X30已经被BL修改为myFunction调用后的地址,BranchingModes函数返回时需要的原X30值已丢失,导致程序跳转到错误地址,直接终止或跑飞。 - 输出约束中声明了
[reg0] "=r"(regw0),但汇编代码中从未给regw0对应的寄存器赋值,触发未定义行为,可能进一步破坏寄存器状态。 myFunction中的ret x30属于非标准写法,ARM64标准返回指令是ret(默认使用X30的值),冗余写法可能在部分环境下引发问题。
修复步骤
- 添加寄存器clobber列表:在内联汇编末尾添加
:"x30",告诉编译器X30会被修改,让编译器提前保存、执行后恢复该寄存器的值。 - 移除未使用的输出约束:删除
[reg0] "=r"(regw0),避免未定义行为。 - 修正
myFunction的返回指令:将ret x30改为标准的ret指令。 - 调整逻辑条件:原if条件要求
regw0和regw1都等于10,这永远无法满足,修改为只判断regw1(匹配myFunction的返回值逻辑)。
完整修正代码
#include <stdio.h> #define LDRARRAYLENGTH (4) __asm __volatile ( ".global myFunction \n\t" ".p2align 4 \n\t" ".type myFunction,%function \n\t" "myFunction: \n\t" "mov x0, #10 \n\t" "ret \n\t" // 改为标准ARM64返回指令 ); bool BranchingModes(void) { bool BranchingModesFlag = false; int regw1 = 0x00; __asm __volatile ( "bl myFunction \n\t" // BL调用会修改X30 "mov %[reg1], x0 \n\t" // 将返回值存入regw1 :[reg1] "=r"(regw1) // 移除未使用的reg0输出约束 : :"x30" // 声明X30会被修改,让编译器处理寄存器保存 ); // 调整条件为只判断regw1,匹配myFunction的返回值逻辑 if(regw1 == 10) { BranchingModesFlag = true; } else { BranchingModesFlag = false; } return BranchingModesFlag; } int main() { unsigned int i0 = 0x00; unsigned int counter = 0x00; BranchingModes(); for(i0=0x00; i0<=10000; i0++) { counter = counter + 1; } return 0; }
额外注意事项
- ARM64内联汇编必须严格遵循调用约定,所有被修改的寄存器(除输出约束指定的)都需要在clobber列表中声明,包括X30、X1-X15等临时寄存器。
- BL指令用于子程序调用,会自动设置X30为返回地址,子程序返回时直接用
ret即可,无需显式指定X30。 - 输出约束必须与汇编代码中的赋值操作一一对应,避免未定义行为。
内容的提问来源于stack exchange,提问作者tahoe250
相关产品推荐
相关产品推荐

