程序的机器级表示
历史观点
SSE – 这是一类处理整数或浮点数向量的指令.
AVX 支持把数据封装进256位的向量.
一些通常对C语言程序员隐藏的处理器状态都是可见的
- 程序计数器(通常称为"PC", 在x86-64中用%rip表示)给出将要执行的下一条指令在内存中的地址.
- 整数寄存器文件包含16个命名的位置, 分别存储64位的值. 这些寄存器可以存储地址或整数数据. 有的寄存器用来保存临时数据, 例如过程的参数和局部变量, 以及函数的返回值.
- 条件码寄存器保存着最近执行的算术或逻辑指令的状态信息. 它们用来实现控制或数据流中的条件变化, 比如说用来实现if和while语句.
- 一组向量寄存器可以存放一个或多个整数或浮点数值.
x86-64的虚拟地址是由64位的字来表示的, 在目前的实现中, 这些地址的高十六位必须设置为0
为什么呢?
对于48位的内存地址, 内部机制已经多层嵌套, 复杂度已经很高.
48位已经可以支持64TB的内存,目前来说够用。
因为64机可供系统使用的线性地址空间太大,目前内存的容量还没有达到2的64次幂,没有必要使用全部的64位。48位的虚拟地址转换成物理地址需要4级页表,在tlb缺失时访存次数已经比32位时多了两次,虽然现在的处理器也有高层页表的缓存。如果在没有需求的情况下用满64位,浪费了空间,也增加了转换的访存次数。另外现在Intel已经发布了57位寻址方案的白皮书了。
操作系统和虚拟地址
操作系统负责管理虚拟地址空间, 将虚拟地址翻译成实际处理器内存中的物理地址.
程序编码
使用Unix命令行编译代码并形成机器及代码:
linux> gcc -Og -o p p1.c p2.c
命令gcc为gcc编译器, 它的别名是cc.
编译选项-Og告诉编译器使用会生成符合原始C代码整体结构的机器代码的优化等级. 而-O1, -02为较高级别的优化.
-o p指定产生最终的可执行代码文件p.
代码示例
long mult2(long, long);
void multstore(long x,long y, long *dest){
long t = mult2(x,y);
*dest =t;
}
在命令行上使用-S选项, 就能看到C语言编译器产生的汇编代码:
linux> gcc -Og S mstore.c
产生的汇编文件mstore.s的一部分代码如下:
multstore:
pushq %rbx
movq %rdx, %rbx
call mult2
movq %rax, (%rbx)
popq %rbx
ret
代码中的每一个缩进行都代表了一条机器指令, 比如pushq指令表示应该将寄存器%rbx的内容压入程序栈中.
如果我们使用-c选项, gcc就会编译并汇编该代码并产生目标代码文件mstore.o.
结果如下:
关于格式的注解
如下文件mstore.s
.file "010-mstore.c"
.text
.globl multstore
.type multstore, @function
multstore:
pushq %rbx
movq %rdx, %rbx
call mult2
movq %rax, (%rbx)
popq %rbx
ret
.size multstore, -multstore
.ident "GCC: (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1"
.section .note.GNU-stack,"",@progbits
所有以"."开头的行都是指导汇编器和链接器工作的伪指令.
数据格式
浮点数的后缀和整数后缀相同不会产生歧义, 因为浮点数使用的是一组完全不同的指令和寄存器.