1. 内联汇编

(一)内联汇编 参考Linux中x86的内联汇编

1
2
3
4
5
6
7
asm (assembler template
    
    : output operands               (optional)
    : input operands                (optional)
    : list of clobbered registers   
    (optional)                
);

汇编程序模板由汇编指令组成。输入操作数是充当指令输入操作数使用的 C 表达式。输出操作数是将对其执行汇编指令输出的 C 表达式。

内敛汇编的基本要素

1
2
3
4
5
6
7
8
{
    int a=10, b;
        asm ("movl %1, %%eax;
            movl %%eax, %0;"
            :"=r"(b)  /* output */    
            :"r"(a)       /* input */
            :"%eax"); /* clobbered register */
}

·”b”是输出操作数,由%0引用,“a”是输入操作数,由%1引用
·”r”是操作数的约束,它指定将变量”a”和”b”存储在寄存器中。输出操作数约束应该带有一个约束修饰符”=“,表示它是输出操作数
·要在”asm”内使用寄存器%eax,%eax的前面应该再加一个%,换句话说是%%eax,因为”asm”使用%0、%1等来表示变量。任何带有一个%的数都看做是输入/输出操作数,而不认为是寄存器
·第三个冒号后的修饰寄存器%eax告诉将在asm中修改GCC%eax的值,这样GCC就不适用该寄存器存储任何其它的值
·movl %1, %%eax将”a”的值移到%eax中, movl %%eax, %0将%eax的内容移到”b”中
·因为”b”被指定成输出操作数,因此当”asm”的执行完成后,它将反映出更新的值。换句话说,对”asm”内”b”所做的更改将在”asm”外反映出来

汇编程序模板

汇编程序模板是一组插入到 C 程序中的汇编指令(可以是单个指令,也可以是一组指令)。每条指令都应该由双引号括起,或者整组指令应该由双引号括起。每条指令还应该用一个定界符结尾。有效的定界符为新行 (\n) 和分号 (;)。 ‘\n’ 后可以跟一个 tab(\t) 作为格式化符号,增加 GCC 在汇编文件中生成的指令的可读性。 指令通过数 %0、%1 等来引用 C 表达式(指定为操作数)。

如果希望确保编译器不会在 “asm” 内部优化指令,可以在 “asm” 后使用关键字 “volatile”。如果程序必须与 ANSI C 兼容,则应该使用 asmvolatile,而不是 asm 和 volatile

操作数

C 表达式用作 “asm” 内的汇编指令操作数。在汇编指令通过对 C 程序的 C 表达式进行操作来执行有意义的作业的情况下,操作数是内联汇编的主要特性。

每个操作数都由操作数约束字符串指定,后面跟用括弧括起的 C 表达式,例如:”constraint” (C expression)。操作数约束的主要功能是确定操作数的寻址方式。

可以在输入和输出部分中同时使用多个操作数。每个操作数由逗号分隔开。

在汇编程序模板内部,操作数由数字引用。如果总共有 n 个操作数(包括输入和输出),那么第一个输出操作数的编号为 0,逐项递增,最后那个输入操作数的编号为 n -1。总操作数的数目限制在 10,如果机器描述中任何指令模式中的最大操作数数目大于 10,则使用后者作为限制。

修饰寄存器列表

如果 “asm” 中的指令指的是硬件寄存器,可以告诉 GCC 我们将自己使用和修改它们。这样,GCC 就不会假设它装入到这些寄存器中的值是有效值。通常不需要将输入和输出寄存器列为 clobbered,因为 GCC 知道 “asm” 使用它们(因为它们被明确指定为约束)。不过,如果指令使用任何其它的寄存器,无论是明确的还是隐含的(寄存器不在输入约束列表中出现,也不在输出约束列表中出现),寄存器都必须被指定为修饰列表。修饰寄存器列在第三个冒号之后,其名称被指定为字符串。

至于关键字,如果指令以某些不可预知且不明确的方式修改了内存,则可能将 “memory” 关键字添加到修饰寄存器列表中。这样就告诉 GCC 不要在不同指令之间将内存值高速缓存在寄存器中。

操作数约束

前面提到过,”asm” 中的每个操作数都应该由操作数约束字符串描述,后面跟用括弧括起的 C 表达式。操作数约束主要是确定指令中操作数的寻址方式。约束也可以指定: 1. 是否允许操作数位于寄存器中,以及它可以包括在哪些种类的寄存器中 2. 操作数是否可以是内存引用,以及在这种情况下使用哪些种类的地址 3. 操作数是否可以是立即数 约束还要求两个操作数匹配。

Comments