调用函数时栈中信息的变化(C语言)

调用函数时栈中信息的变化(C语言)


用栈来支持过程的 嵌套调用,过程的入口参数、返回地址、被保存寄存器的值、被调用过程中的非静态局部变量等都会被压入栈中。

在代码执行过程中,每一个过程都会有自己的栈区,称为栈帧,一个栈由若干栈帧组成,每个栈帧用专门的 栈帧寄存器(EBP)指定起始位置。因此,当前栈帧的范围在栈指针 EBP和栈指针 ESP指向区域之间。

栈的地址是从高地址向低地址增长,栈底指向低地址,栈顶指向高地址,栈中每弹出一个值,栈顶指针向高地址移动,如果存储一个int型数据,则栈顶地址加4,每压栈一次,栈顶指针-4。

此处有误,中间是相差16个字节
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jM9JTz5f-1668615005742)(%E8%B0%83%E7%94%A8%E5%87%BD%E6%95%B0%E6%97%B6%E6%A0%88%E4%B8%AD%E4%BF%A1%E6%81%AF%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%88C%E8%AF%AD%E8%A8%80%EF%BC%89%2053aad5c3f5194570ac32ebd4bac1b9ed/Untitled.png)]

例如如下一段代码


#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int caller()
{
    int x = 5,y = 10;
	int sum = add(x, y);
	return sum;
}
int main()
{
	caller();
}

下面是它的汇编代码:

caller:
0x401564	push   %rbp          //保存main函数栈底地址,压栈
0x401565	mov    %rsp,%rbp     //将main函数的栈顶地址放到%rbp中,栈底移动到%rsp的位置,以便建立新栈帧
0x401568	sub    $0x30,%rsp    //%rsp中的数据减30,开辟caller函数的栈帧
0x40156c	movl   $0x5,-0x4(%rbp)//将数据0x5放入相对于栈底-4的地址
0x401573	movl   $0xa,-0x8(%rbp)//将数据0xa放入相对于栈底-8的地址
0x40157a	mov    -0x8(%rbp),%edx//将相对于栈底-8的地址中的数据放入寄存器%edx
0x40157d	mov    -0x4(%rbp),%eax//将相对于栈底-4的地址中的数据放入寄存器%eax
0x401580	mov    %eax,%ecx      //将%eax中的数据移动到%ecx
0x401582	call   0x401550 <add>//调用add 函数
0x401587	mov    %eax,-0xc(%rbp) //取出返回值放到相对于栈底-0xc的地址中(返回值规定放在eax寄存器中)
0x40158a	mov    -0xc(%rbp),%eax //将相对于栈底-0xc的地址中的数据放到%eax作为返回值
0x40158d	add    $0x30,%rsp   //栈顶地址加0x30,销毁栈
0x401591	pop    %rbp         //弹出栈顶的值,放入栈底寄存器中
0x401592	ret                 //返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EZ4C2ZBQ-1668615005745)(%E8%B0%83%E7%94%A8%E5%87%BD%E6%95%B0%E6%97%B6%E6%A0%88%E4%B8%AD%E4%BF%A1%E6%81%AF%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%88C%E8%AF%AD%E8%A8%80%EF%BC%89%2053aad5c3f5194570ac32ebd4bac1b9ed/Untitled%201.png)]

add:
0x401550	push   %rbp    //将caller的栈底地址压栈
0x401551	mov    %rsp,%rbp // 将caller栈顶的地址放入栈底寄存器中,以建立新的栈帧
0x401554	mov    %ecx,0x10(%rbp)//将第一个参数放入相对于add 的栈底为0x10地址中
0x401557	mov    %edx,0x18(%rbp)//将第二个参数放入相对于add 的栈底为0x18地址中
0x40155a	mov    0x10(%rbp),%edx //将第一个参数放到%edx中
0x40155d	mov    0x18(%rbp),%eax //将第二个参数放到%eax中
0x401560	add    %edx,%eax //将寄存器%dex的数据加上%eax中的数据放到%eax中
0x401562	pop    %rbp //弹出栈顶的值,放入栈底寄存器中,销毁栈
0x401563	ret         //返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LpHtUwAI-1668615005747)(%E8%B0%83%E7%94%A8%E5%87%BD%E6%95%B0%E6%97%B6%E6%A0%88%E4%B8%AD%E4%BF%A1%E6%81%AF%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%88C%E8%AF%AD%E8%A8%80%EF%BC%89%2053aad5c3f5194570ac32ebd4bac1b9ed/Untitled%202.png)]

当add函数运行完之后,栈顶指针ESP会被赋予caller函数的栈顶地址,栈底也会变成caller函数的栈底地址,然后销毁此add函数的栈。

函数的返回值会被规定存在寄存器eax中。

栈底的地址+8存的是调用此函数的命令的下一条命令的地址,执行完add函数之后,会弹出栈顶,以便继续执行下一条命令。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7f03gNPV-1668615005748)(%E8%B0%83%E7%94%A8%E5%87%BD%E6%95%B0%E6%97%B6%E6%A0%88%E4%B8%AD%E4%BF%A1%E6%81%AF%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%88C%E8%AF%AD%E8%A8%80%EF%BC%89%2053aad5c3f5194570ac32ebd4bac1b9ed/Untitled%203.png)]


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

17丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值