Tianya
发布于 2026-07-24 / 0 阅读
0
0

C语言内联汇编(GCC)

在 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是否使能
}

评论