计算机系统漫游第三章:程序的机器级表示(第三阶段)

第三章

访问信息

一个x86-64的中央处理单元(CPU)包含一组16个存储64位值的 通用目的的寄存器。这些寄存器用来存储整数数据和指针。

操作数指示符

大多数指令有一个或多个 操作数(operand),指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。x86-64支持多种操作数格式。如下图。源数据值可以以常数形式给出,或是从寄存器或内存中读出。结果可以存放在寄存器或内存中。因此,各种不同的操作数的可能性被分为三种类型。

第一种类型是 立即数(immediate),用来表示常数值。在ATT格式的汇编代码中,立即数的书写方式是'$'后面跟一个用标准C表示法表示的整数,比如,$-577或$0x1F。不同的指令允许的立即数数值范围不同,汇编器会自动选择最紧凑的方式进行数值编码。

第二种类型是 寄存器(register),它表示某个寄存器的内容,16个寄存器的低位1字节、2字节、4字节或8字节中的一个作为操作数,这些字节分别对应于8位、16位、32位或64位。符号ra来表示任意寄存器a,用引用R[ra]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器标识符做索引。

第三类操作数是 内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置。因为将内存看成一个很大的字节数组。

数据传送指令

最频繁使用的指令是将数据从一个位置复制到另一个位置。

指令效果描述

MOV      S,DD←S传送

movb传送字节

movw传送字(2字节)

movl传送双字(4字节)

movq传送四字(8字节)

movabsq    I,RR←I传送绝对的四字

源操作数指定的值是一个立即数,存储在寄存器中或者内存中。目的操作数指定一个 位置,要么是一个寄存器要么是一个内存地址。x86-64限制, 传送指令的两个操作数不能都指向内存位置。因为这样需要将需要两条指令:第一条指令将源值加载到寄存器中,第二条将寄存器值写入到目的位置。

压入和弹出栈数据

在x86-64中,程序栈存放在内存中某个区域。栈向下增长,这样一来,栈顶元素的地址是所有栈中元素地址中最低的。栈指针%rsp保存着栈顶元素的地址。

将一个四字值压入栈中,首先要将栈指针减8,然后将值写到新的栈顶地址。因此,指令 pushq %rbp的行为等价于下面两条指令:

subq $8,%rsp

movq %rbp,(%rsp)

它们之前的区别是在机器代码中pushq指令编码为1个字节,而上面那两条指令一共需要8个字节。

如下图前两栏给出的是,当%rsp为0x108,%rax 为0x123时,执行指令pushq %rax的效果。首先%rsp会减8,得到0x100,然后将0x123存放到内存地址0x100处。

计算机系统漫游第三章:程序的机器级表示(第三阶段)_第1张图片

弹出一个四字的操作包括从栈顶位置读出数据,然后将栈指针加8.因此,指令popq %rax等价于下面两条指令:

movq (%rsp),%rax

add $8,%rsp

上图的第三栏说明的是在执行完pushq后立即执行指令popq %rdx的效果。先从内存中读处值 0x123,再写到寄存器%rdx中,然后,寄存器%rsp的值将增加回到0x108。如图中所示,值0x123仍然会保持在内存位置0x100中,知道被覆盖(例如被另外一条入栈操作覆盖)。无论如何,%rsp指向的地址总是栈顶。

因为栈和程序代码以及其他形式的程序数据都是放在同一内存中,所以程序可以用标准的内存寻址方法访问栈内的任意位置。例如,假设栈顶元素是四字,指令movq 8(%rsp),%rdx会将第二个四字从栈中复制到寄存器%rdx.

你可能感兴趣的:(计算机系统漫游第三章:程序的机器级表示(第三阶段))