CSAPP

第3章 程序的机器级表示

  • IA32 是 x86-64 的 32 位前身。

3.1 历史观点

  • 摩尔定律:集成电路上可容纳的晶体管数量,大约每经过26个月便会翻一番。

3.2 程序编码

gcc命令调用一整套的程序,将源代码转化成可执行代码。

C预处理器扩展源代码,插入所有用#include命令指定的文件,并扩展所有用#define声明指定的宏;编译器产生源文件的汇编代码(.s文件);汇编器将汇编代码转化成二进制目标代码(.o文件);链接器将目标代码与实现库函数的代码合并,产生最终的可执行代码文件(.exe文件)。

1.机器级代码

  • 两种抽象

    1. 指令集架构(ISA),将程序的行为描述成好像每条指令都是按顺序执行的。
    2. 虚拟地址,认为程序使用的内存模型是一个非常大的字节数组。
  • 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
    ret

3.关于格式的注解

  • 所有以.开头的行都是指导汇编器和链接器工作的伪指令。我们通常可以忽略这些行。
  • 对千一些应用程序,程序员必须用汇编代码来访问机器的低级特性。一种方法是用汇编代码编写整个函数,在链接阶段把它们和 C 函数组合起来。另一种方法是利用 GCC 的支持,直接在C程序中嵌入汇编代码。

3.3 数据格式

Intel 用术语”字(word)" 表示 16 位数据类型。因此,称 32 位数为“双字(double words)”,称 64 位数为“四字(quad words)”。

2025-12-06T13:23:09.png

大多数GCC生成的汇编代码指令都有一个字符的后缀,表明操作数的大 小。例如,数据传送指令有四个变种: movb(传送字节)、 movw(传送字)、 movl(传送双 字)和 movq(传送四字)。

后缀 'l'用来表示双字,因为 32 位数被看成是“长字(long word)" 。

汇编代码也使用后缀'l'来表示 4 字节整数和 8 字节双精度浮点数。这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。

分类: CS-Basics 标签: CSAPP

评论

暂无评论数据

暂无评论数据

目录