汇编
通用寄存器使用惯例
rbp 栈帧指针寄存器,用于标识当前栈帧的起始位置
rsp 栈指针寄存器,通常指向栈顶位置,堆栈的pop和push操作就是通过改变rsp的值即移动堆栈指针位置来实现的
rax 结果寄存器,通常用于存储函数调用的返回结果,同时也用于乘法和除法指令中。
[](https://zhuanlan.zhihu.com/p/27339191)
![](http://pic.aipp.vip/20200104165359.png)
EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。
ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.
EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:
函数的调用
子函数调用时,调用者与被调用者的栈帧结构如下图所示:
![](http://pic.aipp.vip/20200105034810.png)
在子函数调用时,执行的操作有:父函数将调用参数从后向前压栈 -> 将返回地址压栈保存 -> 跳转到子函数起始地址执行 -> 子函数将父函数栈帧起始地址(%rpb) 压栈 -> 将 %rbp 的值设置为当前 %rsp 的值,即将 %rbp 指向子函数栈帧的起始地址。
函数的返回
![](http://pic.aipp.vip/20200105034946.png)
函数返回时,我们只需要得到函数的返回值(保存在 %rax 中),之后就需要将栈的结构恢复到函数调用之差的状态,并跳转到父函数的返回地址处继续执行。由于函数调用时已经保存了返回地址和父函数栈帧的起始地址,要恢复到子函数调用之前的父栈帧,我们只需要执行以下两条指令:
### 指令和运算
#### 计算机指令
#### 指令跳转
#### 函数调用
stack overflow
栈空间溢出,通常两个原因
1.调用层级过多,导致stack无法容纳
2.栈上分配了过大的数据
优化方式
1.编译器自动优化,增加-O参数进行函数内联
#### ELK和静态链接
目标文件
#### 程序内存装载
查看内存页大小
$ getconf PAGE_SIZE
#### 动态链接
采用共享链接库方式公用大量公共库,减少内存使用,二来还可以动态编译
有两种方式实现动态链接
1.PLT(Procedure Link Table)+GOT(Global Offset Table)
#### 二进制编码
正数的原码、反码和补码都相同。
负数原码和反码的相互转换:符号位不变,数值位按位取反。
负数原码和补码的相互转换:符号位不变,数值位按位取反,末位再加1。