GCC内联汇编中=与=&的区别及-O2下运行异常原因咨询
GCC内联汇编中"=&"与"="的区别及问题解析
一、两种输出约束的核心区别
- "="(普通输出约束):编译器允许输出操作数的寄存器与输入操作数的寄存器复用。也就是说,同一个寄存器既可以存放输入值,也能被分配给输出操作数,编译器仅基于约束规则判断是否允许复用,不会深入解析汇编代码的实际逻辑。
- "=&"(独占输出约束):强制编译器为该输出操作数分配完全独立的寄存器,绝对不能和任何输入操作数的寄存器重叠。这种约束用于告知编译器:该输出寄存器会在汇编代码的早期被覆盖,即便从约束表面看还未用到输入值,也禁止复用输入寄存器。
二、你的代码为何出现异常?
看你提供的汇编逻辑:
ldrb %[H], %[P0] ; 直接覆盖H寄存器的初始值 ldrb %[L], %[P4] ; 同理覆盖L寄存器 add %[H], %[Htbl], %[H], lsl #4 ; 需要用到输入的Htbl原始值 add %[L], %[Htbl], %[L], lsl #4 ; 同样需要Htbl的原始值 mov %[S], %[Z0], LSL #24 ; 需要Z0的原始值
如果给H/L使用"="约束,编译器可能会把H或L分配成与Htbl相同的寄存器。比如假设H复用了Htbl的寄存器,那第一行ldrb就会冲掉Htbl的原始值,后续add指令里的%[Htbl]就变成了从P[0]读出的字节值,而非原本的表基地址,最终结果必然错误。
而使用"=&"约束时,编译器会给H/L/S/tmp都分配独立于Htbl/Z0的寄存器,不管汇编代码如何操作,输入寄存器的原始值都不会被覆盖,逻辑就能正常执行。
三、未读取的tmp寄存器为何影响程序行为?
即便你的汇编代码完全没用到tmp这个输出寄存器,当使用"="约束时,编译器的寄存器分配逻辑会把所有输出操作数视为“可复用输入寄存器”的候选。比如编译器可能把tmp分配给Htbl的寄存器,虽然tmp未被使用,但这种复用可能间接干扰其他输出寄存器的分配策略,导致H/L意外与输入寄存器重叠。而"=&"约束会让所有输出寄存器都被标记为“独占”,编译器不会让任何输出寄存器与输入寄存器复用,所以哪怕tmp没用,也不会干扰其他寄存器的分配。
内容的提问来源于stack exchange,提问作者personal_cloud
相关产品推荐
相关产品推荐

