历史观点
程序编码
机器级代码
- x86-64 可见的处理器状态:
- 程序计数器PC:
%rip
,给出下一条指令的地址 - 寄存器文件:16个,储存64位的值
- 条形码寄存器:保存最近执行的算术或逻辑指令的状态信息,用来控制条件变化
- 向量寄存器:存放多个整数或浮点数值
- 程序计数器PC:
- 函数调用保存策略
-
调用者保存
-
被调用者保存
-
数据格式
访问信息
操作数
- 立即数
- $-577, $0x1F
- 寄存器
- 内存引用
- 最常用:
- 最常用:
数据传送指令
- 两个操作数不能都指向内存位置
- mov指令后缀与寄存器大小匹配
- movq指令只能以表示为32位补码数字的立即数作为源操作数,然后把这个值符号扩展得到64位的值,放到目的位置。
- movabsq指令能够以任意64位立即数值作为源操作数,并且只能以寄存器作为目的。
- 任何位寄存器生成32位值的指令都会把该寄存器的高位部分置为0
- 两操作数大小不一
- \(movz\)指令:零扩展
- 最后两个字符为大小指示符
- \(movs\)指令:符号扩展
- 最后两个字符为大小指示符
- \(cltq\) 等效于 \(movslq \quad\%eax,\%rax\)
- \(movz\)指令:零扩展
压入和弹出栈数据
pushq %rbp
popq %rax
算术和逻辑操作
加载有效地址leaq
-
有效地址计算方式与内存地址计算方式一致
-
可以做简单的加法与乘法运算
一元操作(第二组)
一个操作数:寄存器或内存位置
二元操作(第三组)
- 第一个数:源操作数
立即数,寄存器或内存位置 - 第二个数:目的操作数
寄存器或内存位置
移位操作(第四组)
- 移位量
- 立即数,或寄存器
cl
- 移位量由
cl
低\(m\)位决定,其中\(2^m = w\),\(w\)为数据值位长
- 立即数,或寄存器
特殊的算数操作
控制
条件码
- 条件码的设置
- 下图中操作都会设置条件码
cmp
和test
指令- 与
sub
和and
类似 - 不改变寄存器的值
- 与
- 下图中操作都会设置条件码
- 条件码的使用
SET
指令根据条件码的某种组合,将一个字节设置为0或者1。
jump
指令可以条件跳转到程序的某个其他的部分。
- 编码
- PC相对寻址
其中第二行:0x8 = 0x5(下一行地址) + 03(跳转指令的目标编码)
同理 第五行:0x5 = 0xd + f8
- PC相对寻址
- 编码
- 可以有条件地传送数据。
- 基于条件传送的代码比基于跳转指令的代码效率高
预测:错误则浪费时间
- 基于条件传送的代码比基于跳转指令的代码效率高
循环
用条件测试和跳转组合起来实现循环的效果。
- for, do-while, while
- switch
跳转表为数组,重复的情况使用相同标号,缺少的情况使用默认值
过程
传递控制,传递数据,分配和释放内存
运行时栈
- 栈帧,通过栈指针
%rsp
维护
转移控制
数据传送
- 寄存器(6个)
- 栈
- 传递参数时,所有数据大小都向8的倍数对齐
栈上的局部存储
局部变量不需要对齐
寄存器中的局部存储空间
- 统一的使用惯例
- 调用者保存寄存器
- 被调用者保存寄存器
- 栈保存寄存器数值
入栈保存,出栈恢复
递归过程
数组分配与访问
- 基本原则
- 地址计算
- 指针运算
- 定长数组,变长数组
异质的数据结构
- 结构
- 对齐(插入间隙)
- 联合
- 共用空间
控制与数据结合
- 指针
- 缓冲区溢出
- C对数组引用不进行边界检查:破坏栈中状态信息(gets函数)
- 防御
- 栈随机化
- 栈破坏检测(金丝雀值)
- 限制可执行代码区域
- 变长栈帧