如果你是编程新手,你确信对系统栈结构有所了解吗?

如果你是编程新手,你确信对系统栈结构有所了解吗?

 

首先声明这篇文章是绝对的原创,希望对新手能起到抛砖引玉的作用。

你对系统栈了解多少?__cdecl,__stdcall,__thiscall与栈有什么直接的联系?

汇编对你的工作兴许没什么帮助,但我还是请求你看完下面的示例,看看下面的分析,你会从中看懂你应该懂得的东西。

 

代码段一、

#include <iostream>

using namespace std;

int __cdecl fun(int a,int b)  //如果这里换成__stdcall又会怎么样?

{

    cout<<"Show a value:"<<a<<" Show b value:"<<b<<endl;

    return a;

}

int _tmain(int argc, _TCHAR* argv[])

{

     __asm

   {

       push 1  //__cdecl的调用约定,1入栈等同于b=1

       push 2  //接着是2入栈,等同于a=2

       call fun //能不能直接换成jmp fun呢?

       add esp,8 //为何添加此条语句

  }

   cout<<"Thank you!"<<endl;

    return 0;

}

一段典型的c/c++内嵌汇编的代码,为了分析更直观,先请有编译器的新手们在机器上运行一下,当然运行的结果并不会令你惊奇!程序输出了2和 1,thank you! 我们并不能把脚步停留在这表面的东西,还有很多的东西需要我们来挖掘。带着我代码中的疑问,go on...

换成__stdcall的调用约定,代码显示2和1后就直接崩溃了,why?这是因为,被__stdcall修饰的函数自行会调整栈结构,等到函数fun return返回时,esp所指的位置已经还原成main函数起初的位置,而再次对其施加指令add esp,8无非是画蛇添足了,这就叫"我用的我还原"; 而_cdecl对栈结构的维护不同,叫"我用你还原",因此,上述代码_stdcall和__cdecl修饰的fun函数最大的差别在于,在内嵌的汇编代码中写不写add esp,8这句代码。可能有的新手会故意把这条代码写成add esp,4 可是一运行发现不管用的是__stdcall还是__cdecl,代码都会崩掉,why? add esp,8 不是随便写的,内存的汇编代码中不是有push 1 ,push 2,两句代码嘛。这表示程序运行的栈结构中多了8个字节,一个是1,一个是2。说到这里,可能有的新手还是不死心,于是写下了sub esp ,8 对不起代码还是崩了。why?为何是加上8而不是减8呢,如果你假设的win32系统栈的成长方向是由低到高,恭喜你sub esp,8是正确的,可偏偏是win32系统栈的成长方向是由高到低。因此,最先压栈的东西占领了更高的地址位,讲到这里或许都认为问题已经明了化了,no,no...我们还得go on...

call fun指令能不能换成jmp fun呢?从功能上来说,call 是由一系列的push指令和一条jmp指令组成的因此,无论如何就指令的运行效率来说,jmp肯定相对call更高效。但是这里用jmp替换call指令是绝不可以的,答案很简单,call指令会对栈进行必要的维护其中必有的隐含指令是push eip ,看到没有call指令被调用后,必须把指令指针压入栈中,call在给自己留后路(必须记得是谁调用了我,我还得回家). jmp是那种绝不做任何停留勇往直前,也绝不回头。因此,在换成jmp指令后,根本就看不到thank you的输出了。

另外,如果你看到这里还没有睡着的话,那我们就讲讲_cdecl和__stdcall另外的一些区别,__stdcall函数一般不允许函数以变参声明,像这样 int __stdcall fun(int a,...) ,这种声明是__cdecl独有的,是c/c++语言独有的,以__stdcall声明不定参数的函数形式必定给栈结构带来毁灭性的灾难!

最后谈谈__thiscall,这是c/c++类中成员函数的调用约定,他在形参个数固定的情况下等同于__stdcall,个数不定是等同于__cdecl,还有几个特殊的调用约定(__fastcall,__declspec(naked)),由于用的极少,不在累赘,感兴趣的可以自己找资料看看。

好了就写这么多了,同时希望高手们能接续....

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值