C语言内联汇编

💡 原文英文,约600词,阅读约需3分钟。
📝

内容提要

本文介绍C语言内联汇编:基础asm可直接嵌入汇编指令,但无法操作C变量;扩展asm支持输入输出约束,如“r”将C表达式存入通用寄存器,“=r”用于输出;volatile防止GCC优化;若汇编修改了其他寄存器,需在clobber列表中声明,避免GCC误用。

🔎

延伸解读

基础asm与扩展asm的核心区别

基础asm仅能嵌入汇编指令,无法直接操作C变量,且所有基础asm块隐式带有volatile属性。扩展asm则支持输入输出约束,允许在汇编中读写C变量,并能从汇编跳转到C标签。这一区别决定了何时需要更复杂的扩展语法。

约束“r”与“=r”的实用含义

在扩展asm中,约束“r”表示输入表达式可存入通用寄存器,GCC会分配寄存器并填充占位符;“=r”表示输出为只写寄存器,GCC将寄存器与C左值绑定。例如读取PMCR_EL0时,用“=r”将结果输出到变量f。理解这两个约束是编写正确内联汇编的基础。

volatile与clobber列表的必要性

volatile限定符告诉GCC不要优化该汇编块,防止因优化导致意外行为。若汇编修改了其他寄存器,必须在clobber列表中声明,否则GCC可能误用这些寄存器。例如x86示例中将eax和ecx标记为clobber,确保GCC不依赖它们维护其他值。

❓

Q&A

C语言内联汇编中,基础asm和扩展asm有什么区别?

基础asm可以直接嵌入汇编指令,但无法操作C变量;扩展asm支持输入输出约束,可以读写C变量,并支持从汇编跳转到C标签。

在扩展asm中,约束“r”和“=r”分别代表什么?

“r”表示将C表达式存入通用寄存器,常用于输入约束;“=r”表示只写寄存器,常用于输出约束。

为什么在内联汇编中需要使用volatile关键字?

volatile用于告诉GCC不要优化这段汇编代码,因为汇编指令可能有副作用,GCC无法理解其含义。

什么是clobber列表?为什么需要它?

clobber列表用于声明汇编代码中修改的寄存器,这样GCC就不会依赖这些寄存器来维护其他值,避免错误。

能否给出一个使用扩展asm读取系统寄存器的例子?

例如:long long f; asm("mrs %0, PMCR_EL0" : "=r" (f)); 这会将PMCR_EL0的值读入变量f。

在内联汇编中,如何将C变量作为输入传递给汇编指令?

使用输入约束,例如"r" ((u64)(0 << 31)),GCC会分配一个通用寄存器,并将表达式的值填入。

🏷️

标签

➡️

继续阅读