现在,能够静下心来去读一段汇编代码的程序员已经不多,因为大多数人的工作中基本用不到。但是能够读懂汇编代码能够提高程序员对程序如何在机器上跑起来的理解和提高程序员的基本功。
想要看懂汇编语言,首先就要熟悉汇编语言各种寻址方式。汇编语言不同的代码格式,本文主要介绍AT&T。Linux 内核使用的就是这样格式,linux 上的工具如gcc和objdump默认生成的代码也是AT&T格式。
简单说一下AT&T汇编,"#"井号开头的是注释行,"."点开始的指令一般都是伪指令,"$"美元符号修饰立即数,"%"修饰寄存器。AT&T 和Intel格式的对比可以参考这篇文章 https://www.ibm.com/developerworks/cn/linux/l-assembly/
汇编语言寻址方式主要有下表几种方式:
1. 立即数寻址
把常数放到寄存器或存储器中
movl $2, %ebx # 把2放到寄存器ebx中
2. 寄存器寻址
把寄存器中的值放到寄存器或存储器中
movl $2, %ebx # 立即数寻址
寄存器寻址, 把ebx的值放到eax中
3. 直接寻址(绝对寻址)
把某个地址上的值放到寄存器中
movl 0x8000, %eax # 把地址0x8000上的值放到eax中
4. 间址寻址
把寄存器上的值所代表的地址所指向的值放到寄存器中
movl $0x8000, %ebx # 立即数寻址
movl %ebx, %eax # 间址寻址, 把地址0x8000(放在寄存器ebx中)上的值放到eax中
5. 基址寻址
是以寄存器里的数值作为基址,加上一个常数得到最终地址,把地址上的值放到寄存器中
movl $0x8000, %eax # 立即数寻址
movl 4(%eax), %ebx #基址寻址, 把地址0x8004(0x8000+4)上的值放到eax中
6. 变址寻址
是以两个寄存器里的数值之和加上一个常数得到最终地址,把地址上的值放到寄存器中
movl $0x8000, %eax # 立即数寻址
movl $0x4, %ebx # 立即数寻址
movl (%eax,%ebx), %ecx #变址寻址, 把地址0x8004(0x8000+4)上的值放到ecx中
movl 4(%eax,%ebx), %ecx #变址寻址, 把地址0x8008(0x8000+4+4)上的值放到ecx中
7. 比例变址寻址
是以一个寄存器里的数值加上另一个寄存器里的数字 乘以一个比例因子(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中
下面写段汇编代码演示一下几种不同的寻址方式
as test.s -o test.o
ld test.o -o test
./test
echo $?