文章目录
  1. 基本语法
  2. GCC基本内联汇编
  3. GCC扩展内联汇编

基本语法

AT&T与Inter汇编主要有以下几个不同:

  • 寄存器的命名;
    1
    AT&T:%eax                   Intel:eax
  • 源操作数与目的操作数的顺序;AT&T赋值方向为从左向右。
    1
    AT&T:movl %eax, %ebx         Intel:mov ebx, eax
  • 常数与立即数的格式;
    1
    AT&T:movl $12, %ebx          Intel:mov eax, 12
  • 地址;
    1
    AT&T:movl $0xd00d, %ebx      Intel:mov eax, 0xd00d
  • 操作数长度标识;
    1
    AT&T:movw %ax, %bx           Intel:mov bx, ax
  • 寻址方式;
    1
    2
    3
    4
    5
    6
    #通用寻址
    AT&T:imm32(base, ip, scale) Intel:[base+ip×scale+imm32]
    #直接寻址
    AT&T:foo Intel:[foo]
    #寄存器间接寻址
    AT&T:(%eax) Intel:[eax]

GCC基本内联汇编

基本内联汇编的格式为:asm("statements");

GCC扩展内联汇编

GCC扩展内联汇编的格式为:

1
2
3
4
asm [volatile]( Assembler Template
: Output Operands
[ : Input Operands
[ : Clobbers ]])

注:如果不希望汇编语句被gcc优化而改变位置,就需要在asm符号后添加volatile关键词;

样例

1
2
3
4
5
6
7
#define read_cr0() ({ \
unsigned int __dummy; \
__asm__( \
"movl %%cr0, %0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})

说明

  • __asm__的括号内,第一行为汇编程序模板;其中%0以占位符作为汇编指令的操作数,GCC将这些占位符与C语言表达式按照出现的顺序相对应。即%0对应C语言表达式__dummy
  • 第二行为输出部分;输出部分用来规定输出变量如何与寄存器结合的约束,输出部分可以有多个约束,互相以逗号分开,每个约束以”=”开头,接着用一个字母来表示操作数的类型,接着是关于变量结合的约束。在上例中,”r”代表任一通用寄存器,其他常用约束字母与含义见下表:

 

  • 如果有输入部分;输入部分与输出部分相似,但是没有”=”;
  • 汇编程序模板为必选项,输入部分与输出部分为可选项;当存在输入部分而不存在输出部分时,需要保留”:”(代表输出部分,即使输出部分不存在),而当只存在修改部分时,需要保留”:::”(代表输出部分、输入部分与修改部分);

练习

扩展内联汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
int count=1;
int value=1;
int buf[10];
void main()
{
asm(
"cld \n\t"
"rep \n\t"
"stosl"
:
: "c" (count), "a" (value) , "D" (buf)
);
}

经过GCC编译之后得到的汇编代码为:

1
2
3
4
5
6
7
8
movl count,%ecx
movl value,%eax
movl buf,%edi
#APP
cld
rep
stosl
#NO_APP