这是IA32中央处理器所包含的一组八个存储单元的32位存储器。前六个是通用寄存器,对它们的使用没有限制。前三个寄存器(%eax,%ecx,%edx)的保存和恢复惯例不同于接下来的三个寄存器(%ebx,%esi,%edi)。最后两个寄存器保存着指向程序栈重要位置的指针,称为栈指针和帧指针。数据存放在寄存器中进行加减乘除等一些操作。原来的寄存器是16位的所以如图所示蓝色部分是0-15,之后寄存器进行了扩充,变成了32位的即0-31。
操作数指示符
大多数指令有一个或者多个操作数,指示该操作的元数据,以及放置目标的位置。x86-64支持多种操作数格式,源数据可以以常数形式给出,或是从寄存器或者内存中读出。根据读出位置的不同操作数的寻址大致分为三种形式。
立即数寻址:用来表示常数。在ATT格式的汇编代码中,立即数的表示方式为‘$’后面跟一个标准C语言表示的整数。
寄存器寻址:表示某个寄存器的内容,汇编中使用%+寄存器表示。
内存引用:根据计算出来的地址访问某个内存地址。
数据传送指令
数据传送指令:将数据从一个位置复制到另一个位置的指令。
S表示源操作指定的值是一个立即数,存储在寄存器中或者内存中。
D表示目的操作数指定一个位置,要么是一个寄存器或者是一个内存地址。x86-64加入了一条限制,传送指令两个操作数不能都指向内存位置。
movb、movsbl和movzbl之间的差别如下:
假设 %dh =8D,%eax=98765432
movb %dh ,%a1 %eax=9876548D
movsbl %dh , %eax %eax=FFFFFF8D
movzbl %dh,%eax %eax=0000008D
在以上的例子中都是将寄存器%eax 的低位字节设置为%edx 的第二个字节。movb指令不改变其他三个字节。根据原字节的最高为,movsbl指令将其他三个字节设为全1或全0。被调用过程movzbl指令无论如何都是将其他三个字节设为全0。
pushl 与popl是用来将数据压入栈中和从栈中弹出数据的。它们两个的指令都只有一个操作数,即它们所要压入或者弹出的数据。将一个双字值压入栈中,首先要将栈指针减4,然后将值写入到新的栈顶地址。弹出一个双字的操作是从栈顶位置读出数据,然后将栈指针加4。
压入与弹出栈数据
栈是一种数据结构,可以添加和删除数据,不过要遵循“后进先出”的原则,通过push操作将数据压入栈中,通过pop操作删除栈中数据。栈可以实现为一个数组,总是从栈的一端插入和删除元素,这一端称为栈顶。在x86-64中,程序栈存放在内存中的某个位置。
在内存中栈顶元素的地址是所有栈中元素地址中最低的。(按照惯例,我们的栈是倒过来画的,栈顶在底部。)栈指针%rsp保存着栈顶元素的地址。
上图中,开始%rsp = 0x108,%rax = 0x123。执行pushq %rax的效果,首先%rsp会减8,得到0x100,然后会将0x123存放到内存地址0x100处。
其中push指令相当于这两条指令subq $8 %rsp,mov %rbp %rsp;
一个程序在运行过程中,一个函数会调用另一个函数(比如递归),那么函数在进入的时候都会往栈里压点什么东西,函数退出时会弹出点什么东西,内层的函数是如何返回的,返回给外层函数的谁,返回到哪里,内层函数是怎么知道返回地址的?
解答:
会压入: 原来ebp的值, 参数, 以及调用函数的下一个指令地址
在调用一个函数时, 编译器就计算好函数需要的空间, 然后esp = ebp-需要的空间, 通过ebp+偏移量来访问。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-54154-2.html
过于激动没好处