如果我是技术面试官,我会问你这个问题!

下面内容不合适Java等高级语言程序员,如果你是Java等高级语言程序员,觉得这个问题很没有意义是正常的。

#include <iostream>
#include   <unistd.h>
using namespace std;

void goodToreturn(){

 long x=0;
 long* xp=&x;//地址+1
 for(x=6;x<10;x++)
 cout<<"index of "<<x<<" : "<<*(xp+x)<<endl;
 x=4+1; //局部变量和返回地址之间需要保存调用者寄存器相关信息地址+4,通过察看汇编代码可知正确
 cout<<"Old Return Address:"<<*(xp+x)<<endl;//拥有错误的返回地址
 *(xp+x)=reinterpret_cast<long>(&goodToreturn);
 cout<<"Current Return Address"<<*(xp+x)<<endl;//纠正返回地址
 sleep(5);
}


int main()
{
  long array[10]={20,21,22,23,24,25,26,27,28,29};
  goodToreturn();
  return 0;
}

在Intel CPU,ubuntu x64,GCC编译器下,这段代码会产生多次递归,然后挂掉。适当修改X的数值可以在window平台GCC编译器下递归多次。

请特别注意:在其他操作系统,或其他编译器,或其他CPU都有可能导致本代码行为改变。

对于为什么产生递归?是因为函数原来的返回地址,被修改为自身函数指针了。C/C++允许你这样乱搞。

----------------------------------------

在window平台,栈帧结构为

函数参数                      地址:高

返回地址

保存原有寄存器

局部变量                      地址:低

-----------------------------------------

在Linux平台,栈帧结构为

返回地址                       地址:高

保存原有寄存器

局部变量

函数参数                      地址:低

-----------------------------------------

通过函数的局部变量地址,加上一个offset就可以访问函数的返回指令地址。但此法在mac os上多次测试无效。


我们还可以发现另一个问题,Old Return Address逐渐从20增加,每次加1。为什么是20,21,22,23...呢,是不是有点眼熟呢,没错就是main函数中的数组,那么如何解释?

函数返回时,栈帧上移一次,每次移动一个指针的长度,64位操作系统指针8个字节,long型正好也是8个字节。随着栈帧的不断上移就会移动到main函数的栈帧里,破坏main函数原有的数据。


对于更详细的参考和学习,请你去读一下图书。

《深入理解计算机系统》

《Unix内核剖析》

《征服C指针》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值