CSAPP:第3章 程序的机器级表示 3.1 历史观点 & 3.2 程序编码 & 3.3 数据格式

第3章 程序的机器级表示
- IA32 是 x86-64 的 32 位前身。
3.1 历史观点
- 摩尔定律:集成电路上可容纳的晶体管数量,大约每经过26个月便会翻一番。
3.2 程序编码
gcc命令调用一整套的程序,将源代码转化成可执行代码。
C预处理器扩展源代码,插入所有用#include命令指定的文件,并扩展所有用#define声明指定的宏;编译器产生源文件的汇编代码(.s文件);汇编器将汇编代码转化成二进制目标代码(.o文件);链接器将目标代码与实现库函数的代码合并,产生最终的可执行代码文件(.exe文件)。
1.机器级代码
两种抽象
- 指令集架构(ISA),将程序的行为描述成好像每条指令都是按顺序执行的。
- 虚拟地址,认为程序使用的内存模型是一个非常大的字节数组。
x86-64 的机器代码和原始的 C 代码差别非常大。一些通常对 C 语言程序员隐藏的处理器状态都是可见的:
- 程序计数器(PC。在x86-64中用 %rip表示)给出将要执行的下一条指令在内存中的地址。
- 整数寄存器文件包含16个命名的位置,分别存储64位的值。这些寄存器可以存储地址或整数数据。有的寄存器被用来记录某些重要的程序状态,而其他的寄存器用来保存临时数据,例如过程的参数和局部变量,以及函数的返回值。
- 条件码寄存器保存着最近执行的算术或逻辑指令的状态信息。它们用来实现控制或数据流中的条件变化,如实现if和while语句。
- 一组向量寄存器可以存放一个或多个整数或浮点数值。
- C语言中的聚合数据类型,例如数组和结构,在机器代码中用一组连续的字节来表示。即使是对标量数据类型,汇编代码也不区分有符号或无符号整数,不区分各种类型的指针,甚至于不区分指针和整数。
- 程序内存包含:程序的可执行机器代码,操作系统需要的一些信息,用来管理过程调 用和返回的运行时栈,以及用户分配的内存块(比如说用 malloc库函数分配的)。
2.代码示例
long mult2(long, long);
void multstore(long x, long y, long* dest) {
long t = mult2(x, y);
*dest = t;
}编译:
linux> gcc -Og -S mstore.c汇编:
linux> gcc -Og -c mstore.c反汇编:
linux> objdump -d mstore.o下面是汇编代码:
multstore:
pushq %rbx
movq %rdx, %rbx
call mult2
movq %rax, (%rbx)
popq %rbx
ret3.关于格式的注解
- 所有以
.开头的行都是指导汇编器和链接器工作的伪指令。我们通常可以忽略这些行。 - 对千一些应用程序,程序员必须用汇编代码来访问机器的低级特性。一种方法是用汇编代码编写整个函数,在链接阶段把它们和 C 函数组合起来。另一种方法是利用 GCC 的支持,直接在C程序中嵌入汇编代码。
3.3 数据格式
Intel 用术语”字(word)" 表示 16 位数据类型。因此,称 32 位数为“双字(double words)”,称 64 位数为“四字(quad words)”。

大多数GCC生成的汇编代码指令都有一个字符的后缀,表明操作数的大 小。例如,数据传送指令有四个变种: movb(传送字节)、 movw(传送字)、 movl(传送双 字)和 movq(传送四字)。
后缀 'l'用来表示双字,因为 32 位数被看成是“长字(long word)" 。
汇编代码也使用后缀'l'来表示 4 字节整数和 8 字节双精度浮点数。这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。
版权申明
本文系作者 @xiin 原创发布在To Future$站点。未经许可,禁止转载。
暂无评论数据