本文总结内联汇编的基本用法和应用举例。

1 内联汇编语法格式

1
2
3
4
5
6
asm [volatile] (
    "汇编指令"
    : 输出操作数列表
    : 输入操作数列表
    : 被破坏的寄存器列表
);

1.1 内联汇编参数说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>                                                                                                                                                                                                                 

int add(int a, int b)
{
    int res;
    asm volatile(
        "addl %1, %2 \n\t"
        "movl %2, %0 \n\t"
        : "=r"(res)
        : "r"(a), "r"(b));
    return res;
}

int main(void)
{
    int result = add(1, 2);
    printf("result: %d\n", result);

    return 0;
}

代码说明:该代码为GCC内联汇编,汇编格式为AT&T。

  1. 内联汇编代码说明
  • 第7,8行为汇编代码。其中%0, %1, %2为占位符,占位符将在后续说明。
  • 内联汇编中,若有多行代码,一般使用\n\t分隔;
  • 此处%1表示的是第一个输出操作数。%1为第一个输入操作数,%2为第二个输入操作数。
  1. 输出操作数列表
  • 汇编代码结束后,紧挨着的一个冒号(:)后就是输出操作数列表;
  • 输出操作数可以为空,但是即使输出操作数列表为空,冒号却不能省略;
  • 若有多个输出操作数,多个输出操作数之间使用逗号(,)分隔。
  1. 输入操作数列表
  • 输出操作数列表后紧挨着的一个冒号(:)后就是输入操作数列表;
  • 输入操作数可以为空,但是即使输出操作数列表为空,冒号却不能省略;
  • 若有多个输入操作数,多个操作数之间使用逗号(,)分隔。
  1. 被破坏的寄存器列表
  • 若存在被破坏的寄存器列表,放在输入操作列表后。
  • 若被破坏的寄存器列表为空,则冒号可以省略;

1.2 内联汇编中符号的功能

1.2.1 占位符

在内联汇编中,%0、%1、%2 等是占位符(placeholders),代表操作数列表中各个操作数的引用。它们按照操作数在列表中的顺序进行编号。

编号规则:

  • 从0开始编号
  • 先从输出操作数开始,依次编号。
  • 编号顺序为:第一个输出操作数为%0,,第二个输出操作数为%1,然后一次编号输入操作数。输出操作数编号完毕后,紧接着编号输入操作数。

1.2.2 修饰符

修饰符用于控制输入操作数列表,输出操作数列表和被破坏寄存器列表,可以多个修饰符共同使用。

修饰符 功能说明 示例
= 表示当前变量为只写变量,一般用用于修饰输出操作数 “=r”(res)
+ 表示当前变量为可读写变量 “+r”(a)
& 表示修饰的变量不能与其他变量公用寄存器(或内存) “=&r”(result1)
r 表示当前操作数使用通用寄存器存放 “r”(sum)
m 表示当前操作数使用内存存放 “m”(res)
0-9 使用指定操作数保存变量 “0”(var)

2 内联汇编实例

2.1