AT&T 汇编是一种和intel汇编在语法上完全不同的汇编语言,为避免混淆intel语法,本文只介绍AT&T汇编,以下是所有的寄存器,AT&T的第一个特点就是每个寄存器名前必须加‘%’,立即数前必须加‘$’:(下面省略了%)
8个32位寄存器:eax, ecx, edx, ebx, esp, ebp, esi, edi
8个16位寄存器:ax, cx, dx, bx, sp, bp, si, di
8个8位寄存器:al, cl, dl, bl, ah, ch, dh, bh
(注:16位寄存器分别是32位寄存器的低16位,8位寄存器分别是ax,cx,dx,bx的高低8位【l:低位,h:高位】)
6个段寄存器:cs, ds, ss, es, fs, gs
3个控制寄存器:cr0, cr2, cr3
6个debug寄存器:db0, db1, db2, db3, db6, db7
2个测试寄存器:tr6, tr7
8个浮点寄存器栈:st(0), st(1), st(2), st(3), st(4), st(5), st(6), st(7)
AT&T语法一个很明显的特点是操作数从左到右排列的,简单来讲,例:
intel语法=》MOV AX,123 ;将123存入寄存器ax
AT&T语法=》mov $123,%ax #将123存入寄存器ax
在大多数指令上,两种汇编指令都是一样的。
在AT&T中,想要说明操作数的长度,有三种符号:l(long),w(word),b(byte),使用时在指令后面直接加上就行了,比如“movl $0x80,%eax”,指明了立即数0x80的长度为4字节
对于注释符号,AT&T允许了3种注释符号,c/c++的两种(单行注释“//”和多行注释“/**/”),还有"#"单行注释,值得注意的是,“//”虽然可以单行注释,但只能放在空行注释,其他两个注释均可以跟在代码行后面,"/**/"甚至允许你在代码行的最前面写一行注释。相比较而言,像nasm这样intel语法的汇编器只有一个单行注释符号“;”。AT&T汇编器虽然不支持这个注释符号,但碰到时会直接忽视掉。
(intel语法的汇编代码多用大写字母,AT&T则用小写字母)
汇编例子(linux下):
//向屏幕输出字符串
.section .data #声明数据段,.section用来指明这是一个段,在这里可不加
msg:
.ascii "goodmorning!\n" #.ascii声明为ASCII码,也可以用.string,一样的效果
len=.-msg #len储存了字符串长度
.section .text #声明代码段
.globl _start#.globl用来声明程序入口
_start:
movl$msg,%ecx #标号实质上就是一个地址,这个地址指向该段的第一个数据的地址
movl $len,%edx #将字符串的长度放进寄存器edx
movl $1,%ebx #
movl $4,%eax #将中断号存入eax
Int 0x80 #进入中断
movl$0,%ebx
movl $1,%eax#当eax存入1时进入中断,说明已经运行完了,程序将自动结束
Int 0x80
/*ebx储存程序的返回值,当程序在终端中执行完成后,你可以使用“echo $?”指令查看程序的返回值*/
一般linux系统都会装有AT&T编译器,下面简述一下执行上面那个代码的步骤
1.将上面的代码保存,命名为“m.s”(文件名随便,linux对文件后缀名要求并不严格)
2.在保存的目录下单机鼠标右键,打开终端。
3.在终端输入"as m.s -o m.o" (-o可以把生成文件命名为你想要的名字,这里m.s经过as程序编译后,生成的目标文件为m.o,当没有用-o指定文件名时,默认命名为“a.out”)
4.再在终端输入“ld m.o -o m”,ld是链接程序,任何要在操作系统层面上运行的程序必须要链接成可执行文件才能正常运行
5.生成的文件m就是我们的程序,输入“./m”,然后回车,就可以运行了,你可以输入echo $?来查看程序结束后的返回值,即ebx中的值。