目录
《深入理解计算机系统》第三章笔记
寄存器
- 程序计数器(PC,下一条待处理的指令的地址)
- 条件码寄存器(比如CF、ZF、SF、OF)
- 整数寄存器(16个)
数据格式
C声明 | 占用字节 | 汇编代码后缀 |
char | 1 | b (byte) |
short | 2 | w (word) |
int | 4 | l (long word) |
long | 8 | q (quad word) |
char* | 8 | q (quad word) |
操作数的寻址模式
- 操作数的三种类型--立即数($开头) 寄存器 内存引用
常见指令
- 数据传送指令 mov movz movs
- 入栈出栈 push pop
- 算术和逻辑操作
- 加载有效地址 leaq
- 一元操作 inc dec neg not
- 二元操作 add sub imul and or xor
- 移位操作 sal sar shl shr
控制
- 修改条件码寄存器的方式
- 算术和逻辑操作
- cmp和test指令
- 条件码的使用方法
- 根据条件码的某种组合,将一个字节置零或置一 set指令
- 条件跳转到程序某个地方 jump指令
- 有条件地传送数据 cmov指令
- 条件分支
- 用条件控制jump实现条件分支
- 用条件传送comv实现条件分支
- 循环
- do-while
- while
- for --> while
过程
- 运行时栈
- 转移控制
- call 下面一条指令的地址入栈,PC修改为跳转的地址
- ret 刚才入栈的指令的地址出栈,PC修改为那个地址
- 数据传递
- 参数传递
- 6个参数以内通过寄存器传递 %rdi %rsi %dx %cx %r8 %r9
- 超出6个的部分通过栈传递,入栈顺序从右向左,所有参数的地址向8的倍数对齐
- 返回值
- %rax传递返回值
- 参数传递
- 栈上的局部存储(有时局部数据必须放在内存中,情况如下)
- 寄存器不足以存放所有数据
- 对一个局部变量使用地址运算符&(因为寄存器不能产生地址)
- 局部变量是数组或结构体(类似情况2,数组名或结构体名即代表数组起始地址)
- 寄存器中的局部存储
- 一个函数调用另一个函数,通过寄存器传递参数,有时希望寄存器中的值被保存下来
- 如果需要保存的值在6个以内,通过寄存器保存 %rbx %r15 %r14 %r13 %r12 %rbp
- 超出6个的部分存储在栈上
结构体
-
结构体内部需要注意数据对齐--任何K字节的基本数据类型的地址必须是K的倍数
-
结构体本身也要注意数据对齐--结构体本身的起始地址必须是内部最长字段的倍数
指令周期
- 取指令(fetch)
- 从内存取出指令字节,按顺序计算下一个指令的地址
- 译码(decode)
- 从寄存器文件或其他阶段的数据获取最多两个操作数
- 执行(execute)
- 执行算术或逻辑操作,并更新条件码寄存器
- 为访存阶段计算内存引用的有效地址 mov指令
- 增加或减少栈指针 push/pop, call/ret
- 访存(memory)
- 读内存或写内存
- 写回(write back)
- 最多写两个结果到寄存器文件
- 更新PC(PC update)
- 将PC设置为下一条指令的地址(下面的一条指令,或者跳转的指令)
GDB调试器
- 通过gcc生成.out文件,并启用gdb
- gcc -g -o test.out test.c
- gdb test.out
- 常用命令
- 在第i行设置断点 break i
- 删除第一个断点 break 1
- 从断点处继续执行 continue
- 查看所有断点 info break
- 查看变量x print x