系列文章目录
程序的机器级表示:
CSAPP第三章的目录
- 历史观点
- 程序编码
- 数据格式
- 访问信息
- 算数和逻辑操作
- 控制
- 过程
- 数组分配和访问
- 异质的数据结构
- 在机器级程序中奖控制与数据结合起来
- 浮点代码
九曲阑干的课程目录:
- 机器级代码(至书的3.4.1)
- 数据传送指令
- 条件码寄存器
- 跳转指令以及bomblab_ev
- 过程
- 多维数组与结构体
- 缓冲区溢出
文章目录
参考
这里将参考列出来:
这一章和上一章有所不同,上一章主要是一些数学公式,概念理解记忆。而这一章的实操性要求极高也是课程的核心部分。也对应了bomb lab。我决定这一章的笔记的主体还是按照九曲阑干的来,加以辅助重点解读,如果二者有些许不同则以CMU的课程为准
一、导读
基本概念:
-
Instructure Set Architecture: 指令集架构 (包括指令规格,寄存器等),简称ISA,它是软硬件之间的“合同”
-
Mircoarchitecture: 指令集架构的具体实现方式 (比如流水线级数,缓存大小等),它是可变的
-
Machine Code: 机器码,也就是机器可以直接执行的二进制指令
-
Assembly Code: 汇编码,也就是机器码的文本形式 (主要是给人类阅读)
编译过程:
重要思想: 程序就是一系列(被编码了的)字节序列 (看上去和数据一模一样),这就是所谓的冯诺依曼结构计算机,即程序存储型计算机
二、寄存器
2.1 理解寄存器
理解机器码就必须理解寄存器!!!
总共有16个整数寄存器
对于机器级编程来说,其中有两个抽象尤为重要:
- ISA来定义机器级程序的格式和行为
- 机器级程序使用的内存地址是虚拟内存地址,提供了一个看上去是一个非常大的字节数组。
在本书中用得是ATT(AT&T)的汇编代码格式,区别于Intel的汇编代码格式。这里做一个说明:
寄存器大小在历史上的演化,逐渐由16位走向到了64位;寄存器的数量也由原来的8个增加到了16个:
2.2 不同寄存器所扮演的角色
有一组标准的编程规范控制着如何使用寄存器来管理栈、传递函数参数、从函数的返回值、以及存储局部和临时数据。
这里先解释一下什么是调用者(caller)和被调用者(callee):
再来解释一下调用者保存和被调用者保存
-
调用者保存
-
被调用者保存
这里其实在程序中经常见到的是这样的汇编语句:
push %rbx
这里就是将这里面的值压入栈中,作一个临时性的保存,不能将原来的值破坏。等要用到的时候再把它拿出来pop %rbx
三、数据格式
这里先明确一个概念值的大小,所占寄存器中的位数:
字节:byte,8位;字:word,16位;双字:double words,32位;四字:quad words,64位。
对应的指令后缀:movb, movw, movl, movq。
这里说的都是整数,浮点数使用一组完全不同的指令和寄存器。
四、操作数指示符(Operand Specifiers)
指令的操作数有三种类型:立即数,寄存器,内存引用
- 立即数(immediate),用来表示常数值,例如$-577
- 寄存器,表示某个寄存器的内容,16个寄存器的低位1字节,2字节,4字节或8字节中的一个作为操作数。
- 内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置
4.1 不同类型操作数的格式
上面图展示了各种不同类型操作数的格式,操作数可以直接表示立即数(即具体数值)、寄存器值或者内存地址中的值。下面是每种操作数格式的详细解释:
-
立即数 (Immediate)
- 格式:
$Imm
- 含义: 这表示立即数(即常数值)本身。例如,
$0x108
表示数字0x108
。
- 格式:
-
寄存器 (Register)
- 格式:
r_a
- 含义: 直接使用寄存器中的值。例如,
%rax
用来访问寄存器rax
中存储的值。
- 格式:
-
绝对内存地址 (Absolute)
- 格式:
Imm
- 含义: 访问内存中给定绝对地址的内容。例如,
0x104
指的是内存地址0x104
中的内容。
- 格式:
-
间接寻址 (Indirect)
- 格式:
(r_a)
- 含义: 使用寄存器
r_a
中的值作为地址,访问该地址处的内存内容。例如,(%rax)
表示访问%rax
寄存器中存储的地址对应的内存内容。
- 格式:
-
基址加偏移 (Base + Displacement)
- 格式:
Imm(r_b)
- 含义: 使用
r_b
寄存器的值加上一个立即数偏移量作为地址,访问内存中该地址的内容。例如,4(%rax)
访问从%rax
中存储的地址开始,向上偏移4个单位的内存地址的内容。
- 格式:
-
索引寻址 (Indexed)
- 格式:
(r_b, r_i)
- 含义: 使用基址寄存器
r_b
和索引寄存器r_i
的值的和作为地址,访问内存中该地址的内容。例如,(%rax, %rdx)
使用%rax
和%rdx
寄存器中的值的和作为地址。
- 格式:
-
比例索引寻址 (Scaled Indexed)
- 格式:
(
,r_i
,s)
- 含义: 使用索引寄存器
r_i
的值乘以一个比例因子s
(可以是1、2、4或8)作为地址。例如,(, %rdx, 4)
使用%rdx
寄存器的值乘以4作为地址。
- 格式:
-
比例基址加索引 (Scaled Indexed with Base)
- 格式:
Imm(r_b, r_i, s)
- 含义: 使用基址
r_b
、索引r_i
和比例因子s
的组合作为地址。例如,260(%rcx, %rdx)
使用%rcx
加上%rdx
乘以260作为地址。
- 格式:
通过这些不同的寻址方式,可以灵活地在程序中指定和访问内存或寄存器的数据。
4.2 练习题
说实话,我刚学这个有点懵逼,还是来看一道练习题吧:
最终填表如下:
弄懂这幅图就行了,本质上就是去内存地址取数,告诉我内存地址在哪就行(寻址公式):
为什么s要求1,2,4,8,因为在数组中去寻址,那几种数据类型的大小都是1,2,4,8。
总结
这章主要简单介绍了:
- 指令集和虚拟内存的概念
- 寄存器:
- 历史演化,由此就会联想到数据格式(size of data type: b, w, l, q)体现在操作的后缀上
- 每个通用寄存器的作用,包括调用者和被调用者保存,等等
- 历史演化,由此就会联想到数据格式(size of data type: b, w, l, q)体现在操作的后缀上
- 操作数:1. 立即数;2.寄存器;3.内存引用
- 掌握好寻址公式