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
- push
- lea
- load effective addr
- 加载有效地址
- lea s , d -> d=&s
- load effective addr
控制
- 条件码寄存器
- CF 进位标志
- ZF 零标志
- SF 符号标志
- OF 溢出标志
- 访问条件码
- 可以依据条件码的某种组合,将一个字节设置成0或1
- SET 指令
- setne D -> D=~ZF
- SET 指令
- 可以条件跳转到程序的其他部分
- 可以有条件的传送数据
- 可以依据条件码的某种组合,将一个字节设置成0或1
- 跳转指令
- 无条件跳转
- jmp
- 直接跳转
- 跳转目标是作为指令的一部分编码
- 间接跳转
- 跳转目标是从寄存器或内存位置读出
- 直接跳转
- jmp
- 有条件跳转
- 例子
- jnz
- jz
- jne
- 条件跳转只能 直接跳转
- 例子
- 跳转指令的编码
- 跳转指令有几种不同的编码,最常用的是 PC相对的
- PC-relative
- 地址偏移量编码为 1 2 4字节
- 指令编码很简洁
- 目标代码可以不做改变就移到内存不同的位置
- PC-relative
- 绝对地址
- 4个字节直接指定目标
- 跳转指令有几种不同的编码,最常用的是 PC相对的
- 无条件跳转
- 分支、循环、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
- 结构
- 通过首地址的相对偏移
过程的详细解释
代码语言:javascript复制void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p )
{
*a1p = a1;
*a2p = a2;
*a2p = a3;
*a4p = a4;
}
int main()
{
long a1 = 0x12345678;
long*a1p = &a1;
int a2 = 0x66666666;
int* a2p = &a2;
short a3 = 0x3333;
short* a3p = &a3;
char a4 = 0xFE;
char* a4p = &a4;
proc( a1 ,a1p , a2, a2p, a3, a3p,a4 , a4p );
a1 = 0x11112222;
a2 = 0x66669999;
return 0;
}
栈描述
代码语言:javascript复制int main()
{
400565: 55 push %rbp
400566: 48 89 e5 mov %rsp,%rbp
400569: 48 83 ec 40 sub $0x40,%rsp
long a1 = 0x12345678;
40056d: 48 c7 45 d8 78 56 34 movq $0x12345678,-0x28(%rbp)
400574: 12
long*a1p = &a1;
400575: 48 8d 45 d8 lea -0x28(%rbp),%rax // 先构造了一些 局部变量
400579: 48 89 45 f8 mov %rax,-0x8(%rbp)
int a2 = 0x66666666;
40057d: c7 45 d4 66 66 66 66 movl $0x66666666,-0x2c(%rbp)
int* a2p = &a2;
400584: 48 8d 45 d4 lea -0x2c(%rbp),%rax
400588: 48 89 45 f0 mov %rax,-0x10(%rbp)
short a3 = 0x3333;
40058c: 66 c7 45 d2 33 33 movw $0x3333,-0x2e(%rbp)
short* a3p = &a3;
400592: 48 8d 45 d2 lea -0x2e(%rbp),%rax
400596: 48 89 45 e8 mov %rax,-0x18(%rbp)
char a4 = 0xFE;
40059a: c6 45 d1 fe movb $0xfe,-0x2f(%rbp)
char* a4p = &a4;
40059e: 48 8d 45 d1 lea -0x2f(%rbp),%rax
4005a2: 48 89 45 e0 mov %rax,-0x20(%rbp)
proc( a1 ,a1p , a2, a2p, a3, a3p,a4 , a4p );
4005a6: 0f b6 45 d1 movzbl -0x2f(%rbp),�x // 通过寄存器和栈 传参
4005aa: 0f be f8 movsbl %al,�i
4005ad: 0f b7 45 d2 movzwl -0x2e(%rbp),�x
4005b1: 44 0f bf d0 movswl %ax,%r10d
4005b5: 8b 55 d4 mov -0x2c(%rbp),�x
4005b8: 48 8b 45 d8 mov -0x28(%rbp),%rax
4005bc: 4c 8b 4d e8 mov -0x18(%rbp),%r9
4005c0: 48 8b 4d f0 mov -0x10(%rbp),%rcx
4005c4: 48 8b 75 f8 mov -0x8(%rbp),%rsi
4005c8: 4c 8b 45 e0 mov -0x20(%rbp),%r8
4005cc: 4c 89 44 24 08 mov %r8,0x8(%rsp)
4005d1: 89 3c 24 mov �i,(%rsp)
4005d4: 45 89 d0 mov %r10d,%r8d
4005d7: 48 89 c7 mov %rax,%rdi
4005da: e8 11 ff ff ff callq 4004f0 <proc>
gdb 调试
代码语言:javascript复制void proc(long a1, long*a1p , int a2 , int* a2p, short a3, short* a3p , char a4, char* a4p )
{
4004f0: 55 push %rbp
4004f1: 48 89 e5 mov %rsp,%rbp
4004f4: 48 89 7d f8 mov %rdi,-0x8(%rbp)
4004f8: 48 89 75 f0 mov %rsi,-0x10(%rbp)
4004fc: 89 55 ec mov �x,-0x14(%rbp)
4004ff: 48 89 4d e0 mov %rcx,-0x20(%rbp)
400503: 44 89 c2 mov %r8d,�x
400506: 4c 89 4d d8 mov %r9,-0x28(%rbp)
40050a: 8b 45 10 mov 0x10(%rbp),�x
40050d: 66 89 55 e8 mov %dx,-0x18(%rbp)
400511: 88 45 d4 mov %al,-0x2c(%rbp)
*a1p = a1;
400514: 48 8b 45 f0 mov -0x10(%rbp),%rax // 寄存器 能传递6个参数
400518: 48 8b 10 mov (%rax),%rdx
40051b: 48 8b 45 f8 mov -0x8(%rbp),%rax // 其余的参数可以相对 rbp 获取
40051f: 48 01 c2 add %rax,%rdx
400522: 48 8b 45 f0 mov -0x10(%rbp),%rax
400526: 48 89 10 mov %rdx,(%rax)
*a2p = a2;
400529: 48 8b 45 e0 mov -0x20(%rbp),%rax
40052d: 8b 10 mov (%rax),�x
40052f: 8b 45 ec mov -0x14(%rbp),�x
400532: 01 c2 add �x,�x
400534: 48 8b 45 e0 mov -0x20(%rbp),%rax
400538: 89 10 mov �x,(%rax)
call proc后, 这个过程会push main的调用地址的下一处,在proc里面也会push rbp, 通过打印内存的值,可以看到 rsp上 存储的变量信息, 选用的数字比较有规则,比如 0x12345678 , 0x 66666666 如下图: