x86架构汇编指令一般有两种格式:Intel汇编和AT&T汇编,DOS、Windows使用Intel汇编,而Unix、Linux、MacOS使用AT&T汇编。
1.汇编组成
汇编程序是由定义好的段组成的,每个段的意义都不一样。最常用的由以下几个段:
- data段:存放大部分的数据
- bss段:存放未初始化的数据
- rodata段:存放只读的数据
- text段:存放代码
对于最简单一个程序而言,text段是必须的,其他都是可选的。
操作码:但是操作码都是一堆16进制字符,不太人性化,所以就就产生了助记符来方便程序员来编写汇编代码。
寄存器:x86_64 平台16个通用寄存器和6个16位段寄存器
立即数:x86_64 平台规定立即数的最大值不能超过32位。
大小写:指令不区分大小写,但是Intel格式的指令习惯上使用大写字母,而AT&T格式习惯上使用小写字母。
2.数据格式
GAS中每个操作都是有一个字符的后缀,表明操作数的大小。"b"表示 byte(一个字节) ;"w"表示 word(2 个字节) ;"l"表示 long(4 个字节) 。INTEL 中处理内存操作数时也有类似的语法如:BYTE PTR、WORD PTR、DWORD PTR。
C声明 | GAS后缀 | 大小(字节) |
---|---|---|
char | b | 1 |
short | w | 2 |
long | l | 4 |
注意:GAL使用后缀"l"同时表示4字节整数和8字节双精度浮点数,这不会产生歧义因为浮点数使用的是完全不同的指令和寄存器。
3.汇编指令格式
- 数据传送
movl %ebx,%eax #寄存器前加% movl $1,%eax #立即数前加$
传送方向与Intel格式相反,如:把EAX值存入EBX
intel格式:MOV EBA, EAX at&t格式:movl %eax, %ebx
2.跳转指令
lcall $secion:$offset
ljmp $secion:$offset
lret $stack_adjust
4.寻址方式
-
直接寻址
movl 0x8000, %eax # 把地址0x8000上的值放到eax中
-
寄存器寻址
movl $2, %ebx # 立即数寻址
-
立即数寻址
movl $2, %ebx # 把2放到寄存器ebx中
-
间接寻址
movl $0x8000, %ebx # 立即数寻址 movl %ebx, %eax # 间址寻址, 把地址0x8000(放在寄存器ebx中)上的值放到eax
-
基址寻址
movl $0x8000, %eax # 立即数寻址 movl 4(%eax), %ebx #基址寻址, 把地址0x8004(0x8000+4)上的值放到eax中
-
变址寻址
movl $0x8000, %eax # 立即数寻址 movl $0x4, %ebx # 立即数寻址 movl (%eax,%ebx), %ecx #变址寻址, 把地址0x8004(0x8000+4)上的值放到ecx中 movl 4(%eax,%ebx), %ecx #变址寻址, 把地址0x8008(0x8000+4+4)上的值放到ecx中
- 比例变址寻址
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中