本文简单介绍AT&T汇编语言,基于学过X86汇编
1.寄存器
引用寄存器要在寄存器号前加百分号%,如“movl %eax, %ebx
8个32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp
8个16-bit寄存器 它们事实上是上面8个32-bit寄存器的低16位:
%ax,%bx,%cx,%dx,%di,%si,%bp,%sp
8个8-bit寄存器 %ah,%al,%bh,%bl,%ch,%cl,%dh,%dl
它们事实上是寄存器%ax,%bx,%cx,%dx的高8位和低8位
6个段寄存器 %cs(code),%ds(data),%ss(stack), %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)
寄存器功能
以E开头的寄存器为32位
EAX(累加器,是算术运算的主要寄存器)
EBX(基址寄存器,在内存中寻址时存放基址)
ECX(计数器)
EDX(数据寄存器)
ESI(源变址)
EDI(目标变址)
ESP(堆栈指针)
EBP(基址指针)
EIP(程序计数器,存储的是将要执行的下一条指令放在内存中的地址)
EFLAGS(保存的是根据运算得到的结果设置的条件码ZF,CF,SF,OF)
段寄存器:
CS:代码段寄存器
SS:堆栈段寄存器
DS:数据段寄存器
ES、FS、GS:附加数据段寄存器
2.指令的长度后缀
在指令后面加上后缀表示长度,根据操作的是1字节、2字节、4字节、8字节,分别对应后缀b, w, l, q
movq $1, %rax
3.操作数顺序
操作数排列是从源(左)到目的(右)
movl %eax(源), %ebx(目的) (ebx) = (eax)
4.立即数
使用立即数,要在数前面加符号$
1:
movl $0x04, %ebx”
2:
para = 0x04
movl $para, %ebx
5.注释
在AT&T中,注释既可以使用" ;",也可以使用" ! "
6.符号常数
符号常数直接引用
value: .long 0x12a3f2de
movl value , %ebx
指令执行的结果是将常数0x12a3f2de装入寄存器ebx,
引用符号地址在符号前加符号$, 如“movl $value, % ebx”则是将符号value的地址装入寄存器ebx
7.调用和跳转指令
段内调用和跳转指令为"call",“ret"和"jmp”,段间调用和跳转指令为"lcall",“lret"和"ljmp”
段间调用和跳转指令的格式
lcall/ljmp $SECTION, $OFFSET
段间返回指令为
lret $STACK-ADJUST
jmp, jcc, call指令跳转
寄存器:如果想要跳到寄存器%rax内容对应的地址,不是写成jmpq %rax,而是写成*jmpq %rax
立即数:如上表所示,不用加*号
内存:如果想要跳转到%rip + 0x10对应的地址,不是写成jmpq 0x10(%rip),而是写成jmpq *0x10(%rip)
8.数据声明
格式:命令 数据类型
.ascii 文本字符串
.asciz 以空字符串结尾的文本字符串
.byte 字节值
.double 双精度浮点数
.float 单精度浮点数
.int 32位整数
.long 32位整数(同32)
.octa 16字节整数
.quad 8字节整数
.short 16位整数
.single 单精度浮点数(和.float同)
两个命令声明缓冲:
命令 描述
.comm 声明未初始化的数据的通用内存区域
.lcomm 声明未初始化的数据的本地通用内存区域
9.寻址方式
1.直接寻址
把某个地址上的值放到寄存器中
movl 0x8000, %eax # 把地址0x8000上的值放到eax中
2. 间址寻址
把寄存器上的值所代表的地址所指向的值放到寄存器中
movl $0x8000, %ebx
movl %ebx, %eax # 间址寻址, 把地址0x8000(在寄存器ebx中)上的值放到eax中
3. 基址寻址
以寄存器里的数值作为基址,加上一个常数得到最终地址,把地址上的值放到寄存器中
movl $0x8000, %eax
movl 4(%eax), %ebx #基址寻址, 把地址0x8004(0x8000+4)上的值放到eax中
4. 变址寻址
以两个寄存器里的数值之和加上一个常数得到最终地址,把地址上的值放到寄存器中
movl $0x8000, %eax
movl $0x4, %ebx
movl (%eax,%ebx), %ecx #变址寻址, 把地址0x8004(0x8000+4)上的值放到ecx中
movl 4(%eax,%ebx), %ecx #变址寻址, 把地址0x8008(0x8000+4+4)上的值放到ecx中
5. 比例变址寻址
以一个寄存器里的数值加上另一个寄存器里的数字 乘以一个比例因子(1,2,4,8)再加上一个常数得到最终地址,把地址上的值放到寄存器中
movl $0x2000, %eax
movl $0x2, %ebx
movl (,%eax,4), %ecx #比例变址寻址, 把地址0x8000(0x2000 *4)上的值放到ecx中
movl 6(,%eax,4), %ecx #比例变址寻址, 把地址0x8006(0x2000 *4+6)上的值放到ecx中
movl (%ebx,%eax,4), %ecx #变址寻址, 把地址0x8002(0x2000*4+2)上的值放到ecx中
movl 6(%ebx,%eax,4), %ecx #变址寻址, 把地址0x8008(0x2000*4+2+6)上的值放到ecx中
10.文件组成
.text:存放代码对应的指令 正文段
.bss:存放未初始化的全局和静态变量,在运行时该区域初始是全0
.rodata:存放只读数据和变量,例如字符串字面量
.data:存放余下的数据和变量,可读可写 数据段
.ascii:定义一个字符串并且用双引号包含
.byte: 定义一个字符用单引号
.org:定义当前的汇编的位置
伪操作符语句是汇编器使用的指示符,它通常并不会产生任何代码,它由伪操作码和0个或多个操作数组成。每个操作码都是由一个一个点字符’.'开始,表示编译过程中的位置计数器。其值是点符号出现机器指令第一个字节的地址。
11.编译
1)使用as命令对汇编文件进行汇编生成目标文件:as xxx.s -o xxx.o
2)使用ld命令对目标文件进行链接生成可执行文件:ld xxx.o -o xxx
注意,ld命令进行链接要求目标文件的.text段必须有一个入口点,ld默认认为_start标签对应的代码是入口点
1.前缀
Intel汇编寄存器和立即数无需前缀。后者寄存器前缀为%,立即数前缀为$
2.内存变量
Intel语法使用中括号[],后者使用小括号()
3.后缀
AT&T汇编指令有后缀(b,w,l,q),以表明数据类型(8位、16位等);Intel则根据寄存器自动识别