站在C语言的肩膀上学汇编(2):栈
C语言函数的局部变量保存在栈上;
C语言函数的调用信息保存在调用栈上;
C语言可以利用栈溢出攻击;
C语言中很多概念都跟运行时栈相关,但它对C层是透明的,要想真正了解这些概念, 就需要去汇编层了解“运行时栈”的实现。
2. C语言函数的调用信息保存在调用栈上
#include<stdio.h>int func2(){ return 0;}int func(){int funcValue1 = 3; int funcValue2 = 4; func2(); return 0;}int main(){ int mainValue1 = 1; int mainValue2 = 2; func(); return 0;}
这个函数的运行时栈示意图为:
当程序执行main函数体代码时,rbp(base pointer)指向0x7fffffffe180, rsp(stack pointer)指向0x7fffffffe170, 也就是rbp指向main函数运行时栈的栈底, rsp指向main函数运行时栈的栈顶。
当程序执行func函数体代码时,rbp(base pointer)指向0x7fffffffe160, rsp(stack pointer)指向0x7fffffffe150, 也就是rbp指向func函数运行时栈的栈底, rsp指向func函数运行时栈的栈顶。
由此可知,rbp 一直指向当前运行时函数的栈底,rsp一直指向当前运行时函数的栈顶。
当func函数执行完退出到main函数体时,rbp(rsp)需要重新指向main函数运行时栈的栈底(顶),所以需要把main函数的运行时栈的栈底存储在栈上,也就是地址为0x7fffffffe160内存里存0x7fffffffe180。
由于func函数执行完后,需要执行main函数体的return 0语句; 所以需要把return 0;语句的代码地址保存到栈上,也就是地址0x7fffffffe160内存里保存的内容0x0040053f。
具体的执行过程见下图
函数的汇编代码
每行汇编代码执行完,rsp, esp里对应的值
对应汇编代码的含义
callq 会先把下行代码压入栈,然后再跳转到对应的函数处执行;leaveq movq %rbp, %rsp; popq %rbp;retq 弹出栈顶元素,跳转到栈顶元素所指地址处;
结论
C语言函数调用栈的内存布局为: