GCC 内联汇编

How to Use Inline Assembly Language in C Code1

The asm keyword allows you to embed assembler instructions within C code. The asm keyword is a GNU extension. When writing code that can be compiled with -ansi and the various -std options, use __asm__ instead of asm

While the uses of asm are many and varied, it may help to think of an asm statement as a series of low-level instructions that convert input parameters to output parameters.

要使用 C 语言及汇编语言混合编程的话,需要用到 asm 或者 __asm__关键字。GCC 支持两种类型的语法形式,见下文。

Basic Asm

A basic asm statement is one with no operands.

asm asm-qualifiers ( AssemblerInstructions )
  • volatile
    The optional volatile qualifier has no effect. All basic asm blocks are implicitly volatile.
  • inline
    If you use the inline qualifier, then for inlining purposes the size of the asm statement is taken as the smallest size possible

举例如下:

asm volatile ("smc #1234");
// macro
#define DebugBreak() asm("int $3")

多条语句用换行符区分即可。\n

asm volatile (
	"smc #1234 \n"
	"smc #0"
);

Extended Asm

An extended asm statement includes one or more operands.The extended form is preferred for mixing C and assembly language within a function, but to include assembly language at top level you must use basic asm.

基本的 Asm 语法在有的场景不支持一些功能,比如在汇编代码里调用一个 C 函数。 Extended Asm 能够完成上述功能,但是其作用域仅限于函数内部。

There are a number of reasons you might want to convert basic asm statements into extended asm:

使用扩展形式内联汇编2

  • Extended asm allows the programmer to specify inputs and outputs for the asm as well as which registers it modifies (clobbers) while basic asm does not.
  • Different C compilers use different semantics regarding which registers the asm code can overwrite. gcc assumes no registers get modified. If your asm modifies registers without informing the compiler (which requires using extended asm), undefined behavior will result.
  • Clobbering registers (which basic asm does not support) can give better performance than push/pop.
  • Some compilers automatically flush registers to memory before invoking any asm (what gcc calls a “memory” clobber). However gcc’s basic asm does not do this. If your asm requires this, you need to use the “memory” clobber in extended asm.
  • gcc is considering changing the long-time semantics of basic asm. Instead of not clobbering anything, it may soon begin clobbering everything. This may fix subtle errors in existing code. However there is a (small) chance this will cause problems with existing, correctly function code. Further, this could also introduce performance issues as the contents of some/all registers (even ones your asm doesn’t use) may need to be saved/reloaded around your asm statement. To “future-proof” your code against these types of changes, use extended asm and specify exactly what needs to be clobbered.
  • Because of the fact that gcc’s basic asm has no inputs, outputs or clobbers, it can be difficult for optimizers to consistently position basic asm in the generated code.
asm asm-qualifiers (
	AssemblerTemplate 
    : OutputOperands 
    : InputOperands
    : Clobbers
)

// 下面的形式支持 goto 的语法
asm asm-qualifiers (
	AssemblerTemplate 
	: OutputOperands
	: InputOperands
	: Clobbers
	: GotoLabels
)
  • volatile
    The typical use of extended asm statements is to manipulate input values to produce output values. However, your asm statements may also produce side effects. If so, you may need to use the volatile qualifier to disable certain optimizations. See Volatile.

  • inline
    If you use the inline qualifier, then for inlining purposes the size of the asm statement is taken as the smallest size possible.

  • goto
    This qualifier informs the compiler that the asm statement may perform a jump to one of the labels listed in the GotoLabels.

参数

  • AssemblerTemplate
    这个填写相应的汇编指令,其中可能包含了对输入、输出的操作,goto 参数等。
  • OutputOperands
    输出操作数,该操作数被上面的汇编指令所修改。用逗号分隔,可以为空。
  • InputOperands
    输入操作数,该操作数被上面的汇编指令所读取,用逗号分隔,可以为空。
  • Clobbers
    寄存器或者其他变量,这些寄存器或变量值被上面的汇编指令所修改,但是不作为输出,用逗号分隔,可以为空。
  • GotoLabels
    当使用 goto 形式的语法时,这里放着 C 标号,作为跳转目标。

The total number of input + output + goto operands is limited to 30.

// exp1 This code copies src to dst and add 1 to dst.
void foo {
	int src = 1;
	int dst;   

	asm ("mov %1, %0\n\t"
    	"add $1, %0"
    	: "=r" (dst) 
    	: "r" (src));

	printf("%d\n", dst);
}

// exp2 输出列表为空,但是后面的列表非空,: 也是不能省略的
asm("msr cpsr, %[ps]" : : [ps] "r" (status));
// 操作数语法为 [符号名] "限制字符" (C变量名)
// 符号名用于汇编指令中引用C变量,语法是 %[符号名]
// 符号操作符的名字使用了独立的命名空间。这就意味着它使用的是其他的符号表。不必关心使用的符号名在C代码中已经使用了。
asm (
	"msr cpsr, %[ps]" /* read status to cpsr */ 
	: /* No output, empty list */
	: [ps] "r" (status) /* input list */
);

// exp3 不使用符号名,在汇编代码中操作数的引用使用的是%后面跟一个数字
// 顺序是从输出寄存器序列从左到右从上到下以 %0 开始,分别记为 %0、%1 ···
// 这种方式不方便维护代码,不推荐使用
asm (
	"msr cpsr, %0" /* read status to cpsr */ 
	: /* No output, empty list */
	: "r" (status) /* input list */
);

  1. https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html#Using-Assembly-Language-with-C ↩︎

  2. https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended ↩︎

你可能感兴趣的:(C语言,ARM)