CSAPP学习笔记 -- 第三章 程序的机器级表示(上)
3.1 历史观点
IA32是x86-64的32位前身
每个处理器的设计都是向后兼容的
3.2 程序编码
编译选项 -0g告诉编译器使用会生成符合原始C代码整体结构的机器代码的优化级别。
机器级编程的两种抽象
第一种抽象:ISA定义了机器级程序的格式和行为——处理器状态,指令的格式,以及每条指令对状态的影响。
第二种抽象:机器级程序使用的内存地址是虚拟地址,提供的内存模型看上去是一个非常大的字节数组。
程序计数器 - PC - %rip - 将要执行的下一条指令在内存中的地址
整数寄存器文件 - 16个 - 存储地址或者整数数据
条件码寄存器 - 保存最近执行的算术或逻辑指令的状态信息
一组向量寄存器可以存放一个或多个整数或浮点数值
程序内存包含:程序的可执行机器代码、操作系统需要的一些信息、用来管理过程调用和返回的运行时栈、以及用户分配的内存块(比如说用malloc库函数分配)
一条机器指令只执行一个非常基本的操作
值得注意的关于机器代码和他的反汇表示的特性值得注意:
x86-64的执行长度从1到15个字节不等,常用指令以及操作数少的指令所需要的字节数少,而那些不太常用或操作数较多的指令所需字节数多
设计指令格式的方式是,从某个给定位置开始,可以将字节唯一的解码成机器指令
反汇编器只是基于机器代码文件中的字节序列来确定汇编代码,他不需要访问该程序的源代码或汇编代码
反汇编器使用的指令命名规则与GCC生成的汇编代码使用的有写席位的差别。
汇编代码中,所有以‘.’开头的行都是知道汇编器和链接器工作的伪指令。
在C语言中插入汇编代码的方法有两种:
1. 编写完整的函数放进一个独立的汇编代码文件中,让汇编器和链接器把它和用C语言书写的代码合并起来
2. 使用GCC的内联汇编他行,用asm伪指令可以在C程序中包含简短的汇编代码,这种方法的好处是减少了与机器相关的代码量
3.3 数据格式
Intel用术语“字word”表示16位数据类型
大多数GCC生成的汇编代码指令都有一个字符的后缀,表明操作数的大小
3.4 访问信息
一个x86-64的CPU包含一组16个存储64位值的通用目的寄存器,用来存储整数数据和指针
- %rax 返回值
- %rbx 被调用者保存
- %rcx 第4个参数
- %rdx 第3个参数
- %rsi 第2个参数
- %rdi 第1个参数
- %rbp 被调用者保存
- %rsp 栈指针
- %r8 第5个参数
- %r9 第6个参数
- %r10 调用者保存
- %r11 调用者保存
- %r12 被调用者保存
- %r13 被调用者保存
- %r14 被调用者保存
- %r15 被调用者保存
当这些指令以寄存器作为目标时,对于生成小于8字节结果的指令,寄存器处理剩下字节遵循两个原则
- 生成1/2字节数字的指令会保持剩下的字节不变
- 生成4字节数字的指令会把高四位字节置0
大多数指令有一个或多个操作数,指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。操作数分为三类
- 立即数
- 在AT&T格式的汇编代码中,立即数的书写代码是‘$’后面跟一个用标准C表示法表示的整数
- 不同的指令允许的立即数范围不同
- 寄存器
- 用符号 ra 来表示任意寄存器a
- 用引用 R[ra] 来表示他的值
- 内存引用
- 根据计算出来的地址(通常称为有效地址)访问某个内存位置
- 用符号 Mb[Addr] 表示对存储在内存中从地址Addr开始的b字节的引用,为了简便通常省去下标b
寻址模式
最简单形式的数据传送指令——MOV类
- MOV类由四条指令组成:movb、movw、movl、movq
- 这些指令把数据从源位置复制到目的位置,不作任何变化
- x86-64有一条限制,传送指令的两个操作数不能都是指向内存位置
- 寄存器部分的大小(两者取小)必须与最后一个字符指定的大小匹配
- MOV指令只会更新目的操作数指定的那些寄存器字节或内存位置,除了movl指令的目的寄存器的高位四字节置0
- movabsq能够以任意64位立即数值作为源操作数,并且只能以寄存器作为目的
-
- 拓展——P123 - MOVZ类、MOVS类
- MOVZ 零扩展
- MOVS 符号扩展
栈
- 按照惯例,栈是倒过来画的
- 栈顶元素的地址是所有栈中元素地址中最低的
- 栈指针%rsp保存着栈顶元素的地址
3.5 算术和逻辑运算
操作指令分为四组
加载有效地址指令
- 加载有效地址指令实际上是mov指令的变形
- 他的指令形式是从内存读取数据到寄存器,但实际上它根本没有引用内存,而是将有效地址写入到目的操作数,C语言的取址符可以解释这种运算
- 这条指令可以为后面的内存引用产生指针
- 另外还可以简洁的描述普通的算术操作
一元操作
- 只有一个操作数,既是源操作数,又是目的操作数
- 这个操作数可以是寄存器或者内存位置
二元操作
- 第一个操作数是源,可以是立即数、寄存器和内存位置
- 第二个操作数既是源操作数,又是目的操作数,可以是寄存器或者内存位置
- 当第二个操作数是内存位置时,处理器必须从内存位置读出值,执行操作,再把结果写回内存
移位操作
- 第一操作数是移位量,可以是立即数或者单字节寄存器%cl中的值(特定寄存器)
- 第二操作数是目的操作数,可以是寄存器或内存位置
- SAL是算术左移,右边补0
- SHL是逻辑左移,右边补0
- SAR是算术右移,左边补符号位
- SHR是逻辑左移,左边补0
特殊的算术操作
- Intel把16字节的数称为 八字
- 理解--除法

浙公网安备 33010602011771号