——所有汇编指令,必须用双引号包起来,超过一条指令必须用用 \n 进行分割,为了排版,需要加上 \t。比如说,下面是一张加 \t 和不加 \t 的对比图,可以看出加上 \t 后指令会对齐:
和 C 语言一样,加上 volatile 会告诉编译器不要优化内联汇编。
寄存器和内存之间可以互相交换数据,对于寄存器,必须要加 % 引用:
全局变量有着自己的标签,可以被内联汇编识别出来,但是局部变量就不行了。为了解决这个问题,出现了扩展内联汇编格式。
asm [volatile] ("汇编指令" : "输出操作数列表" : "输入操作数列表" : "改动的寄存器"),其规则如下:
——输出操作数列表,将处理结果传递到 C 代码。
——输入操作数列表,将 C 代码的操作数传递给内联汇编。
——告诉编译器用了哪些寄存器。
——改动的寄存器可以忽略,但前两个冒号必须要有,即使其中一个什么也没有。
告诉内联汇编代码,向哪些内存地址或寄存器读取/输出数据,这个过程需要满足一定的格式:
"[输出修饰符]约束"(寄存器或内存地址)
——a:使用 eax/ax/al 寄存器;
——b:使用 ebx/bx/bl 寄存器;
——c:使用 ecx/cx/cl 寄存器;
——d:使用 edx/dx/dl 寄存器;
——r:使用通用寄存器;
——m:使用内存地址。
——+:表示被修饰的操作数可读可写;
——=:表示被修饰的操作数只能写入;
——%:表示被修饰的操作数可以和下一个操作数互换;
——&:内联函数完成前,可以重新使用或删除被修饰的操作数。
用 eax 修饰变量 a,用 ebx 修饰变量 b,用 ecx 修饰变量 sum,输入变量可以不加输出修饰符,但输出变量需要加 "="去修饰,同时扩展内联汇编需要加两个 %% 去修饰寄存器:
上一小节中,可以看到 gcc 使用了 edx 寄存器,现在来让 gcc 不使用这个寄存器:
如果变量很多的话,寄存器不太够用,所以出现了占位符。
按照输入输出列表中的顺序,分别是 0,1,2......:
编号看起来还需要对比操作数列表,阅读体验感不佳,所以可以给他取个别名,这样一眼就可以看出是要进行 a + b 的操作,将结果赋给 sum:
其实和使用寄存器没啥区别,就是将修饰符改成 "m" 而已,但是由于指令不能直接操作两个内存,需要寄存器做中间变量: