如何用C宏实现ARM64寄存器读取代码的寄存器参数化?
如何用C宏实现ARM64寄存器读取代码的寄存器参数化?
嘿,我来帮你搞定这个ARM64寄存器读取的宏定义问题!你遇到的核心困惑应该是怎么把寄存器名这个宏参数,正确嵌入到内联汇编的字符串字面量里对吧?其实用C宏的字符串化操作符#就能轻松解决,我给你一步步讲清楚。
首先,你的原始内联汇编是固定寄存器的,现在要把<reg>改成可以通过宏传入的参数,关键在于把寄存器名转换成字符串并和汇编指令的其他部分拼接起来。C里有个实用特性:相邻的字符串字面量会被编译器自动合并成一个完整的字符串,结合宏的#操作符(它能把宏参数转换成对应的字符串),我们就能写出正确的宏:
#define READ_ARM64_REG(reg, value) \ asm volatile( \ "str " #reg " [%0]\n" \ : \ : "r"(value) \ : "memory" \ )
我给你拆解下这个宏的工作逻辑:
- 当你调用
READ_ARM64_REG(x0, my_val)时,#reg会把参数x0转换成字符串"x0" - 然后相邻的
"str "、"x0"和" [%0]\n"会被自动合并成完整的汇编指令字符串:"str x0 [%0]\n" - 剩下的部分就和你原来的内联汇编完全一致了,把指定寄存器的值存储到
value指向的内存位置
举个实际使用的例子,比如要读取ARM64的x1寄存器到一个64位变量里:
#include <stdint.h> int main() { uint64_t reg_value; // 读取x1寄存器的值到reg_value中 READ_ARM64_REG(x1, reg_value); return 0; }
你之前尝试可能出错的原因,大概率是误用了##拼接操作符——##是用来拼接标识符的,不是字符串,而这里我们需要的是把寄存器名转成字符串,所以#才是正确的选择。
另外还要注意两点:
- 传入的
reg必须是合法的ARM64寄存器名,比如x0-x30、sp、fp这些,不然汇编阶段会报错 - 保留
volatile和"memory"约束很重要:volatile防止编译器优化掉这段汇编,"memory"告诉编译器这段代码会访问内存,避免编译器乱序优化导致的错误
备注:内容来源于stack exchange,提问作者songzh
相关产品推荐
相关产品推荐

