前言
最近工作了,变得忙起来了,但是博客还是要坚持写的,哈哈
之前写过一篇有关arm汇编的学习笔记,貌似当时没有考虑到MIPS,现在就补充一下吧
几个常识
内存:存储指令
CPU:解释和执行指令
EIP:一般其修改是通过call,ret,jmp,条件jmp来改变的.
AT&T与Intel汇编语言的比较
Linux是Unix家族的一员,尽管Linux的历史不长,但与其相关的很多事情都发源于Unix。就Linux所使用的386汇编语言而言,它也是起源于Unix。Unix最初是为PDP-11开发的,曾先后被移植到VAX及68000系列的处理器上,这些处理器上的汇编语言都采用的是AT&T的指令格式。当Unix被移植到i386时,自然也就采用了AT&T的汇编语言格式,而不是Intel的格式。尽管这两种汇编语言在语法上有一定的差异,但所基于的硬件知识是相同的,因此,如果你非常熟悉Intel的语法格式,那么你也可以很容易地把它“移植“到AT&T来。下面我们通过对照Intel与AT&T的语法格式,以便于你把过去的知识能很快地“移植”过来
1.前缀
在Intel的语法中,寄存器和和立即数都没有前缀。但是在AT&T中,寄存器前冠以“%”,而立即数前冠以“$”。在Intel的语法中,十六进制和二进制立即数后缀分别冠以“h”和“b”,而在AT&T中,十六进制立即数前冠以“0x”,表2.2给出几个相应的例子。
表2.2 Intel与AT&T前缀的区别:
Intel语法 | AT&T语法 |
---|---|
mov eax,8 | movl $8,%eax |
mov ebx,0xffffh | movl $0xffff,%ebx |
int 80h | int $0x80h |
2. 操作数的方向
Intel与AT&T操作数的方向正好相反。在Intel语法中,第一个操作数是目的操作数,第二个操作数源操作数。而在AT&T中,第一个数是源操作数,第二个数是目的操作数。由此可以看出,AT&T 的语法符合人们通常的阅读习惯。
e.g.:
在Intel中, mov eax,[ecx]
在AT&T中,movl (%ecx),%eax
3.内存单元操作数
从上面的例子可以看出,内存操作数也有所不同。在Intel的语法中,基寄存器用“[]”括起来,而在AT&T中,用“()”括起来。
在Intel中,mov eax,[ebx+5]
在AT&T,movl 5(%ebx),%eax
4.间接寻址方式
与Intel的语法比较,AT&T间接寻址方式可能更晦涩难懂一些。Intel的指令格式是segreg:[base+index*scale+disp],而AT&T的格式是%segreg:disp(base,index,scale)。其中index/scale/disp/segreg全部是可选的,完全可以简化掉。如果没有指定scale而指定了index,则scale的缺省值为1。segreg段寄存器依赖于指令以及应用程序是运行在实模式还是保护模式下,在实模式下,它依赖于指令,而在保护模式下,segreg是多余的。在AT&T中,当立即数用在scale/disp中时,不应当在其前冠以“$”前缀,表2.3给出其语法及几个相应的例子。
表2.3 内存操作数的语法及举例
Intel语法 | AT&T语法 |
---|---|
指令 foo,segreg:[base + index*scaale + disp] | 指令 %segreg:disp(base,index,scale),foo |
mov eax,[ebx + 20h] | Movl 0x20(%ebx),%eax |
add eax,[ebx+ecx*2ch] | addl (%ebx,%ecx,0x2),%eax |
lea eax,[ebx+ecx] | lea (%ebx,%ecx),%eax |
sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x0x4),%eax |
AT&T的语法比较晦涩难懂,因为[base+index*scale+disp]一眼就可以看出其含义,而disp(base,index,scale)则不可能做到这点。
这种寻址方式常常用在访问数据结构数组中某个特定元素内的一个字段,其中,base为数组的起始地址,scale为每个数组元素的大小,index为下标。如果数组元素还是一个结构,则disp为具体字段在结构中的位移。
5.操作码的后缀
在上面的例子中你可能已注意到,在AT&T的操作码后面有一个后缀,其含义就是指出操作码的大小。“l”表示长整数(32位),“w”表示字(16位),“b”表示字节(8位)。而在Intel的语法中,则要在内存单元操作数的前面加上byte ptr、 word ptr,和dword ptr,“dword”对应“long”.
movl
movq:表示64位(quad)
movl:表示32位(long)
movw:表示16位(word)
movb:表示8位(byte)
寄存器寻址
movl %eax,%edx edx = eax ;
注:寄存器寻址:操作的都是寄存器,不和内存打交道,%表示寄存器
这条指令表示将eax中内容放到edx中
立即数寻址
movl $0x123, %edx edx = 0x123
注:$表示数值,这里将0x123这个值发给edx这个寄存器里面
直接寻址
movl 0x123,%edx edx = *(int32_t*)0x123 ;类似于edx =[0x123] 注:啥也没有,表示0x123是一个地址,这条指令的意思:将以0x123为地址的内存里面的数据传给edx 直接寻址:直接访问一个指定的内存地址的数据
间接寻址
movl (%ebx),%edx edx = %(int32_t*)ebx;类似于edx = [ebx]
注:
间接寻址:(%ebx)表示ebx寄存器里面存的值作为内存地址,将这个内存地址里面的数据放到edx里面
变址寻址
movl 4(%ebx), %edx edx = *(int32_t*)(ebx +4); 类似于edx =[ebx + 4]