ARM 32位GCC内联汇编原子寄存器对加载/存储约束问题
32位ARM原子寄存器对操作的GCC内联汇编约束问题
指令与寄存器要求
32位ARM汇编中,用于原子加载和存储寄存器对的指令分为两类:
ldaexd/stlexd:适配支持获取-释放内存顺序的32位ARMv8架构ldrexd/strexd:适配无内置屏障的ARMv7架构
这类指令对传输寄存器对(Rt和Rt2)有硬性要求:
- Rt必须是偶数编号寄存器,且不能为LR(链接寄存器)
- Rt2必须是Rt的下一个寄存器,即R(t+1)
不符合要求的示例代码
以下C/C++内联汇编代码未满足上述寄存器编号规则:
inline static void atomic_exclusive_load_pair_aquire(uint32_t atomic[2], uint32_t target[2]) { asm volatile("ldaexd %0, %1, [%2]" // 原子获取式加载寄存器对 : "=r"(target[0]), // 第一个传输寄存器 "=r"(target[1]) // 第二个传输寄存器 : "r"(&atomic[0]) // 原子变量基地址寄存器 : "memory"); // "memory"作为编译器读写屏障 }
问题
如何通过GCC内联汇编约束描述寄存器对的依赖关系,让编译器自动选择符合规则的寄存器?该方案是否可行?使用“多替代约束”是否是有效解决路径?
解决方案
通过uint64_t类型实现寄存器对的自动映射——在32位ARM平台上,uint64_t会被分配一组偶/奇编号的寄存器对(禁用Thumb模式时符合指令要求)。同时利用GCC半文档化的约束符%Q和%R分别拆分寄存器对的低32位和高32位:
inline static void atomic_exclusive_load_pair_aquire(uint32_t atomic[2], uint32_t transfer[2]) { uint64_t pair; asm volatile("ldaexd %Q[pair], %R[pair], [%[addr]]" // 原子获取式加载寄存器对 : [pair] "=r"(pair) // 传输寄存器对 : [addr] "r"(&atomic[0]) // 原子变量基地址寄存器 : "memory"); // "memory"作为编译器读写屏障 transfer[0] = static_cast<uint32_t>(pair); transfer[1] = static_cast<uint32_t>(pair >> 32); }
内容的提问来源于stack exchange,提问作者S. Gleissner
相关产品推荐
相关产品推荐

