如果你是编程新手,你确信对系统栈结构有所了解吗?
首先声明这篇文章是绝对的原创,希望对新手能起到抛砖引玉的作用。
你对系统栈了解多少?__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)),由于用的极少,不在累赘,感兴趣的可以自己找资料看看。
好了就写这么多了,同时希望高手们能接续....
分享到:
相关推荐
这份系统是为计算机科学与技术专业的学生,或者对人工智能有所了解的专业人士设计的,非常适合用作毕业设计或课程作业的参考资料。它不仅包含了一个功能完善的人事管理系统,还附带了详细的开发文档和使用文档,这...
由于文档提供的内容不完整,以上总结的知识点可能不够全面,但根据所提供的内容,可以确信这些知识点是理解操作系统磁盘文件系统的数据结构及应用的重要基础。在IT领域中,深入了解文件系统对于系统管理、数据恢复、...
Java的广泛使用和成熟的生态系统为系统的后端提供了坚实的基础,而Scala的高性能和对函数式编程的友好支持,则为处理大规模数据和复杂算法的实现带来了优势。 Java源文件作为系统的主要组成部分,负责实现业务逻辑...
1. **单片机开发**:通过学习单片机开发,胡辉萍体验到了直接控制硬件的乐趣,这让他更加确信自己想要进一步了解底层技术的愿望。 2. **μC/OS的学习与移植**:胡辉萍开始研究μC/OS(一种小型嵌入式实时操作系统)...
这些芯片广泛应用在嵌入式系统、物联网设备、数字电路等多个领域,因此,CH341A编程器软件V1.34注册版可以满足广大用户对不同芯片类型的需求。 三、高效的数据校验 在编程过程中,数据的准确性至关重要。CH341A编程...
这是一课高级教程,请确信你对基本知识已经非常了解了。这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果。 23.球面映射 这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围...
每一次编程难题的解决,都是对自我能力的一次提升,每一次代码的成功运行,都让我更加确信自己能够做到更多。 回顾这条编程之路,我感慨万千。编程不仅仅是一门技术,更是一种思维训练,一种解决问题的方式,一种...
Java - 近10年来计算机软件发展过程中的传奇,其在众多开发者...嗯,这是个容易但又绝对不应该忽略的问题,你确信自己对Java感兴趣、而且又有吃苦的准备,那你才可能学好Java!如果具备这两点条件,就请继续往下看……
最后,文件名称列表详细列出了系统内部的模块和文件结构,这为理解系统架构和代码组织提供了基础。例如,ImageFunc.bas、GeneralFunc.bas、DbFunc.bas和Variable.bas等模块文件的名称暗示了它们各自的功能,如图像...
在大规模分布式系统中,尤其是那些对实时性要求较高的场景如在线教育的选课系统中,缓存技术能够显著提升系统性能和用户体验。 JBossCache3.0是一种流行的开源分布式缓存解决方案,能够支持服务层缓存和本地缓存。...
户籍管理系统是一种用于管理居民户籍信息的软件系统,其开发过程涉及数据库设计、程序编写、用户界面设计、数据安全等多个方面。本篇文档分享的内容虽然被OCR扫描识别出的文本存在一定错误,但从提供的内容片段中,...
这为用户提供了信心,表明开发人员确信所提交的系统能够正常工作,并且用户不需要深入了解复杂的编程知识即可部署和运行系统。描述还强调系统介绍的详尽性,意味着用户可以通过阅读相关文档和说明来理解系统的结构和...
应该是指“weixin java springboot”,其中“weixin”可能是指微信,这表明系统可能与微信平台有所关联,或许支持微信登录、微信支付等功能,而“java”和“springboot”则明确指出系统的技术栈。 需要注意的是,该...
在Windows 10操作系统中,虚拟内存是一种技术,它允许系统使用硬盘空间作为临时内存,以弥补物理RAM...如果你仍然希望优化系统性能,可以考虑升级物理内存,或者使用性能监控工具来更好地了解系统资源的使用情况。
在编程的世界里,深入理解和构建个人心智模型是成为一名优秀程序员的关键。心智模型是对某一领域知识的理解框架,它帮助我们组织信息,区分相关与不相关,预测未来可能的发展趋势。在编程这个快速变化的行业中,拥有...
《C++编程思想 第1卷 标准C++引导》是一部深入浅出、全面系统地讲解C++语言的著作,由Bruce Eckel所著。本书不仅涵盖了C++的基础语法,更深入探讨了面向对象编程(OOP)的核心概念,以及如何在实际开发中有效地运用...
在实际编程实现中,我们可能使用C++、Java或Python等语言,创建一个栈数据结构,然后定义一个函数来处理当前栈顶元素和新输入符号的关系。当遇到优先级较高的运算符时,我们将其压入栈中;当遇到优先级较低的运算符...
通过以上案例的学习和实践,读者可以深入了解PLC编程的基本原理和实际应用。PLC编程不仅是一项技术技能,更是一种解决问题的方法论。希望读者能够在实践中不断探索,提升自己的编程能力和解决实际问题的能力。
《邓俊辉《数据结构》第三版》是数据结构领域的一本经典教材,由著名计算机科学家邓俊辉教授编写。这本书深入浅出地讲解了数据结构的基础理论和实践应用,对于学习计算机科学的学生和专业人士来说,是必备的参考资料...