机器级操作:访问信息 gaunthan Posted on May 14 2016 ? Assembly Instruction ? ## 概述 一个IA32中央处理器(CPU)包含一组8个存储32位值的寄存器。这些寄存器用来存储整数数据和指针。 它们的名字都以`e`开头,每个都有特殊的用途:  所有8个寄存器都可以作为16位(字)或32位(双字)来访问。其中,可以独立访问eax、ebx、ecx和edx的两个低位字节。 ## 操作数指示符 大多数指令有一个或多个**操作数**(operand),指示出执行一个操作中要引用的源数据值,以及放置结果的目标位置。IA32支持多种操作数格式。源数据值可以以常数形式给出,或是从寄存器或存储器中读出。结果可以存放在寄存器或存储器中。因此,各种不同的操作数的可能性被划分为三种: * 立即数(immediate) 常数值。在AT&T格式的汇编代码中,立即数的书写方式是`$`后面跟一个用标准C表示法表示的整数,比如`$0xff`。任何能放进一个32位的字里的数值都可以用做立即数。 * 寄存器(register) 表示某个寄存器的内容。对双字操作来说,可以是8个32位寄存器中的一个(例如,%eax),对字操作来说,可以是8个16位寄存器中的一个(例如,%ax),或者对字节操作来说,可以是8个单字节紧促其元素中的一个(例如,%al)。 * 存储器(memory)引用 它会根据计算计算出来的地址(通常称为有效地址)访问某个存储器位置。 操作数格式和对应的寻址方式关系见下图(其中,符号$E_a$表示任意寄存器$a$、引用$R[E_a]$表示它的值;符号$M_b[Addr]$表示对存储在存储器中从地址$Addr$开始的$b$个字节值的引用,为了方便,通常省去下方的$b$):  ## 数据传送指令 将数据从一个位置复制到另一个位置的指令是最频繁使用的指令。操作数表示的通用性使得一条简单的数据传送指令能够完成在许多机器中要好几条指令才能完成的功能。下图列出了一些比较重要的数据传送指令,它们之间的某部分被归为同一类,如MOV类由三条指令组成:`movb`、`movw`和`movl`。这些指令都执行同样的操作,不同的是它们分别是在大小为1、2和4个字节的数据上进行操作:  ### MOV `MOV`类中的指令将源操作数的值复制到目的操作数中。源操作数指定的值是一个立即数,存储在寄存器中或者存储器中。目的操作数指定一个位置,要么是一个寄存器,要么是一个存储器位置。IA32增加了一条限制,**传送指令的两个操作数不能都指向存储器位置**。将一个值从一个存储器位置复制到另一个存储器位置需要两条指令:第一条指令将源值加载到寄存器中,第二条将该寄存器值写入目的位置。 ### MOVS和MOVZ `MOVS`和`MOVZ`指令类都是将一个较小的源数据复制到一个较大的数据位置,高位用符号位扩展(`MOVS`)或者零扩展(`MOVZ`)进行填充。用符号位扩展,目的位置的所有高位用源值的最高位数值进行填充。用零扩展,所有高位都用零填充。 ### pushl和popl 最后两个数据传送操作可以将数据压入程序栈中(`pushl`),以及从程序栈中弹出数据(`popl`)。[栈](http://leanote.com/blog/post/5783b770ab644135ea00892c)在处理[过程调用](http://leanote.com/blog/post/5714c1e0ab64415fa600068f)中起到至关重要的作用。栈是一个数据结构,可以添加或者删除值,不过要遵循“后进先出”的原则。通过`push`操作把数据压入栈中,通过`pop`操作删除数据;它具有一个属性;弹出的值永远是最近压入而且仍然在栈中的值。栈可以实现为一个数组,总是从数组的一端插入和删除元素。这一端称为**栈顶**。在IA32中,程序栈存放在存储器中某个区域。栈一般是**向下增长**的(由高地址向低地址增长),栈顶元素的地址是所有栈中元素地址中最低的。栈指针esp保存着栈顶元素的地址。 * 指令`pushl %ebp`的行为等价于 ```c subl $4, $esp # 栈指针减4 movl %ebp, (%esp) # 将%ebp的值写入栈顶 ``` * 指令`popl %eax`的行为等价于 ```c movl (%esp), %eax # 从栈顶位置读出数据 addl $4, %esp # 栈指针加4 ``` ## References - RandalE.Bryant, DavidR.O’Hallaron, 布赖恩特,等. 深入理解计算机系统[M]. 机械工业出版社, 2011. 赏 Wechat Pay Alipay 数组分配和访问 机器级操作:算术和逻辑操作