MIT 6.S081 栈的理解

文章详细介绍了如何在xv6系统中实现backtrace函数,通过分析栈帧结构和指针关系,展示从高地址向低地址的函数调用顺序。在A()->B()->C()的例子中,说明了栈帧的动态变化,并通过实例解释了return地址和前一个栈帧指针的获取。最后,通过打印返回地址展示了内核调用过程,如uservec->usertrap->syscall->sys_write。
摘要由CSDN通过智能技术生成

在lab4中,我们要做一个backtrace的函数,来打印出函数调用的过程。 

这是xv6 栈的布局,fp为栈帧指针,sp为栈底指针。栈是从高地址向低地址扩张,整个调用过程的第一个函数在高地址,最近的函数在低地址。如A()->B()->C(),则A在高地址,C在低地址。

注意:每一个栈帧的大小是不固定的,和具体调用函数有关(局部变量不同)。但是每一个栈帧中往下0x8是返回地址,往下0x10是上一个函数对应的栈帧指针,这是固定的。

注意:分清楚栈和栈帧的概念,栈中有多个栈帧

(借用一下知乎大佬的图)

backtrace代码:

 

 关于这两行代码,实则是为了解引用取出返回值和上一个栈帧的地址。(curr_fp本来就是一个地址,所以我们通过偏移加解引用)

将整数值转换为指针并解引用也就是取该地址的值

uint64 ret = *(pte_t *)(curr_fp - 0x8);
uint64 prev_fp = *(pte_t *)(curr_fp - 0x10);

 打印一下fp看看是不是从低地址往高地址走。(因为入栈是从高地址开始向低地址扩张,现在进行返回则是相反的)

 可以看出当前fp在低地址,它的前一个fp在高地址

那么我们返回地址都是些什么呢,这实际上就是ecall调用的过程,以公开课的write函数为例

 在进入内核后,调用过程为uservec->usertrap->syscall->sys_write,我们打印返回地址一看究竟:

可以看到是符合我们预期的,栈底是sys_sleep,往上依次是syscall、usertrap 

终于搞懂了函数调用的过程了,开心!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值