预备知识
- 当过程P调用Q,会把返回值压入栈,指明当Q返回时要到Q的哪个地址继续执行;
- Q的返回地址作为P的栈帧的一部分,因为他存放的是与P相关的状态;
- 调用Q后,Q在此基础上继续扩展自己的栈帧;
- 很多过程调用不需要栈帧,只用寄存器足够;
- ret就是从栈中弹出之前的那返回地址,然后把pc设为那个返回地址;
- 局部变量放在内存中的情况:寄存器不足;局部变量使用地址运算符&,必须为他产生一个地址;某些局部变量是数组或结构,必须能够通过数组或结构被引用访问到;
- 大多栈帧都是定长的,有时也要变长的fram;
- 通过寄存器过程P最多可传6个整数值(6个指针或者整数);
- 如果需要更多参数,P可以在调用Q之前在自己的栈帧存储好这些参数;
- 在objdump中产生的反汇编callq 和 retq ,q是64位的意思;
- return返回值默认返回rax的值;
函数调用数据传送示例
解析
- 参数7位于栈顶;
- 通过栈传递参数时,所有数据大小都向8的倍数对齐;
- 参数到位后,就可以开call了;
- P调用Q时,P的代码首先把参数复制到合适寄存器;
- P的代码可访问Q返回在rax中的返回值;
- 存6个的参数在栈中,我们把第7个参数放在rsp+8中,第八个参数在rsp+16;
- 举例把第七个char a4放到%rsp+8,第八个char* a4放到%rsp+16定义为*a4p ;
- *a4p+=a4-----------翻译成:先把a4的指针放到rax,movq 16(rsp),rax;
- 然后获得a4的值movl 8(rsp),edx放到edx;
- 然后计算 addb dl,(rax);用这个取值的符号计算;
- 当时栈的分配,因为a4其实就是一个字节的char,他会放到申请的八个字节的栈帧的最后一个字节上;
栈上的局部存储
看图
第二个例子:
传参数是倒着处理,先给他多的进栈。
不多的那6个进寄存器
x86-64实际内存的分配
实际分配图像
x86-64( 又称x64,即英文词64-bit extended,64位拓展的简写)是x86架构的64位拓展,向后兼容于16位及32位的x86架构。
注意:我们可以估计64位机器的地址大小:
通过观察 1024与1000非常接近,同时
2^10 大约等于 10^3
264**-----------**(210)6**乘以16--------------**1018乘以16
内存的限制
现在64位机器只用47位地址-------也就是差不多256TB的地址
这就是为什么会出现这个地址:
0x 0000 7FFF FFFF FFFF-------最高地址
栈-存放 局部变量
栈:大小一般限制在8MB
如果去访问一个超过8Megabyte的指针,程序会报Segmentation fault
文本段-存放exe二进制代码的区域
存放可执行程序的区域—文本段
read-only
executable machine instruction
数据段-存放全局变量,静态变量,字符串常量
声明的全局变量
堆-存放malloc,new,calloc申请的变量
动态变化
回想高地址不断增长
动态链接库
printf函数…