在 ARM GCC 中内嵌汇编允许你在 C 代码中直接插入 ARM 指令,这对性能优化、硬件访问或执行特殊操作非常有用。其核心语法结构如下:
__asm__ [__volatile__] ("汇编指令模板"
: "输出操作数约束" (C变量名)
: "输入操作数约束" (C表达式)
: "破坏描述列表"
);
asm:声明内嵌汇编表达式的关键字,也可以用asm,但asm更具可移植性。volatile:可选关键字。用于告诉编译器不要对这段汇编指令进行优化(例如移动指令位置或省略认为无用的指令),确保指令按代码中的样子执行。在对硬件进行操作或精确控制时序时尤其重要。"汇编指令模板":核心部分,包含要执行的 ARM 汇编指令。多条指令用\n\t分隔。操作数使用占位符%0,%1,%2... 来对应后面输出和输入操作数。- 输出操作数:用于将汇编结果传回 C 变量。格式为
"约束" (C变量)。约束字符串通常包含一个=表示只写或+表示读写。例如"=r" (result)表示结果输出到寄存器并存入result变量。 - 输入操作数:用于将 C 表达式的值传递给汇编代码。格式为
"约束" (C表达式)。例如"r" (a)表示变量a的值放在一个寄存器中作为输入。 - 破坏描述列表:告知编译器汇编指令可能会修改哪些寄存器或内存,但并未在输入输出列表中明确指定。这能避免编译器错误地依赖某些寄存器或内存值。例如
:"r0", "r1", "cc", "memory"。"cc":表示指令会修改条件码寄存器(如 CPSR 中的标志位)。"memory":表示指令会读写内存,可能改变了内存中的值,编译器在优化时不能假设寄存器中内存内容的副本仍然有效。
操作数约束详解
操作数约束告诉编译器如何分配和使用操作数:
| 约束符 | 含义 | 示例 |
|---|---|---|
r | 使用通用寄存器 | "r" (a) |
m | 使用内存地址 | "m" (value) |
i | 使用立即数 | "i" (0x80) |
=&r | 输出操作数,强调使用早期破坏的寄存器 | "=&r" (tmp) |
占位符引用
在汇编指令模板中,使用 %数字来引用操作数:
%0:引用第一个操作数(通常是输出)%1:引用第二个操作数(通常是第一个输入)- 以此类推
%2,%3...
举例
__asm__ ("mov r0, %1\n\t"
"add %0, r0, %2\n\t"
: "=r" (result)
: "r" (a), "r" (b)
: "r0" // 告诉编译器 r0 会被修改
);
int disable_interrupts(void) {
unsigned long old, temp;
__asm__ __volatile__(
"mrs %0, cpsr\n\t" // 读取 CPSR 到 old
"orr %1, %0, #0x80\n\t" // 将 temp 设置为 old | 0x80 (禁用IRQ)
"msr cpsr_c, %1" // 将 temp 写回 CPSR 的控制域
: "=r" (old), "=r" (temp) // 输出:old 和 temp
: // 无显式输入
: "memory" // 破坏描述:通知编译器内存可能变化
);
return (old & 0x80) == 0; // 返回原来IRQ是否使能
}