CSAPP
机器级表示
汇编
两个抽象
- 硬件 指令集 ISA 的抽象
- 虚拟内存 大数组
汇编与高级语言的区别
暴露的可操作
- 程序计数器 rip
- 条件寄存器
整数寄存器
ATT 汇编与 intel 汇编区别
- intel 省略了 指示大小的后缀
- Intel省略了 寄存器前的 %
- Intel 有很多不同的方法 描述内存的位置
- 多个操作数 Intel 列出的操作数 是相反的
访问信息
不同类型操作数
- 寄存器
- 立即数
- 内存引用
表
数据传送
- mov S , D
入栈出栈
push
- sub %rsp; mov xxx (%rsp)
pop
- mov %rsp xxx , add %rsp
pic
lea
load effective addr
- 加载有效地址
lea s , d -> d=&s
控制
条件码寄存器
- CF 进位标志
- ZF 零标志
- SF 符号标志
- OF 溢出标志
访问条件码
可以依据条件码的某种组合,将一个字节设置成0或1
SET 指令
- setne D -> D=~ZF
可以条件跳转到程序的其他部分
- 可以有条件的传送数据
跳转指令
无条件跳转
jmp
直接跳转
- 跳转目标是作为指令的一部分编码
间接跳转
- 跳转目标是从寄存器或内存位置读出
有条件跳转
例子
- jnz
- jz
- jne
条件跳转只能 直接跳转
跳转指令的编码
跳转指令有几种不同的编码,最常用的是 PC相对的
PC-relative
地址偏移量编码为 1 2 4字节
- 指令编码很简洁
- 目标代码可以不做改变就移到内存不同的位置
绝对地址
- 4个字节直接指定目标
分支、循环、switch
过程
概念
- 用指定的一组参数和可选的返回值实现某种功能
转移控制
过程
压栈,设置%rip ; 弹出地址,设置%rip
跳转
- 直接跳转
- 间接跳转
传递数据
寄存器传参
- rdi rsi rdx rcx r8 r9
超过6个参数
- 栈上传参
分配和回收内存
栈上的局部存储
- 变量取地址
- 结构
寄存器局部存储
寄存器保存惯例
被调用者保存寄存器
rbp rbx r12~r15
- %rbp 是栈帧指针,用于标识当前栈帧的起始位置
leave 指令来实现两条命令
- movq %rbp, %rsp
- popq %rbp
实现基础
运行时栈
- 过程需要的存储空间超出寄存器大小,在栈上分配的数据称栈帧
结构与数组
数组
- movl (%rdx , %rcx , 4) , %rax
结构
- 通过首地址的相对偏移
过程的详细解释
1 | void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p ) |
栈描述
1 | int main() |
gdb 调试
1 | void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p ) |
call proc后, 这个过程会push main的调用地址的下一处,在proc里面也会push rbp, 通过打印内存的值,可以看到 rsp上 存储的变量信息, 选用的数字比较有规则,比如 0x12345678 , 0x 66666666 如下图: