如果你是编程新手,你确信对系统栈结构有所了解吗?
首先声明这篇文章是绝对的原创,希望对新手能起到抛砖引玉的作用。
你对系统栈了解多少?__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领域中,深入了解文件系统对于系统管理、数据恢复、...
1. **单片机开发**:通过学习单片机开发,胡辉萍体验到了直接控制硬件的乐趣,这让他更加确信自己想要进一步了解底层技术的愿望。 2. **μC/OS的学习与移植**:胡辉萍开始研究μC/OS(一种小型嵌入式实时操作系统)...
这些芯片广泛应用在嵌入式系统、物联网设备、数字电路等多个领域,因此,CH341A编程器软件V1.34注册版可以满足广大用户对不同芯片类型的需求。 三、高效的数据校验 在编程过程中,数据的准确性至关重要。CH341A编程...
这是一课高级教程,请确信你对基本知识已经非常了解了。这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果。 23.球面映射 这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围...
Java - 近10年来计算机软件发展过程中的传奇,其在众多开发者...嗯,这是个容易但又绝对不应该忽略的问题,你确信自己对Java感兴趣、而且又有吃苦的准备,那你才可能学好Java!如果具备这两点条件,就请继续往下看……
在大规模分布式系统中,尤其是那些对实时性要求较高的场景如在线教育的选课系统中,缓存技术能够显著提升系统性能和用户体验。 JBossCache3.0是一种流行的开源分布式缓存解决方案,能够支持服务层缓存和本地缓存。...
户籍管理系统是一种用于管理居民户籍信息的软件系统,其开发过程涉及数据库设计、程序编写、用户界面设计、数据安全等多个方面。本篇文档分享的内容虽然被OCR扫描识别出的文本存在一定错误,但从提供的内容片段中,...
在Windows 10操作系统中,虚拟内存是一种技术,它允许系统使用硬盘空间作为临时内存,以弥补物理RAM...如果你仍然希望优化系统性能,可以考虑升级物理内存,或者使用性能监控工具来更好地了解系统资源的使用情况。
微软首席执行官比尔·盖茨曾经说过:“如果你认为你是一名真正优秀的程序员,那么就去读第一卷,并确信可以解决其中所有的问题。” 克努思的贡献不仅限于计算机科学领域,他还影响了整个软件行业。他的作品《计算机...
在编程的世界里,深入理解和构建个人心智模型是成为一名优秀程序员的关键。心智模型是对某一领域知识的理解框架,它帮助我们组织信息,区分相关与不相关,预测未来可能的发展趋势。在编程这个快速变化的行业中,拥有...
《C++编程思想 第1卷 标准C++引导》是一部深入浅出、全面系统地讲解C++语言的著作,由Bruce Eckel所著。本书不仅涵盖了C++的基础语法,更深入探讨了面向对象编程(OOP)的核心概念,以及如何在实际开发中有效地运用...
在实际编程实现中,我们可能使用C++、Java或Python等语言,创建一个栈数据结构,然后定义一个函数来处理当前栈顶元素和新输入符号的关系。当遇到优先级较高的运算符时,我们将其压入栈中;当遇到优先级较低的运算符...
通过以上案例的学习和实践,读者可以深入了解PLC编程的基本原理和实际应用。PLC编程不仅是一项技术技能,更是一种解决问题的方法论。希望读者能够在实践中不断探索,提升自己的编程能力和解决实际问题的能力。
《邓俊辉《数据结构》第三版》是数据结构领域的一本经典教材,由著名计算机科学家邓俊辉教授编写。这本书深入浅出地讲解了数据结构的基础理论和实践应用,对于学习计算机科学的学生和专业人士来说,是必备的参考资料...
在准备安装Linux系统之前,了解如何正确地进行系统分区至关重要,特别是对于Linux新手而言。Linux系统需要EXT3和SWAP格式的分区,不同于常见的FAT32和NTFS格式。EXT3是Linux的一种日志文件系统,提供了数据安全性和...
通过本资源摘要信息,我们可以了解到自动控制系统的基本控制方式、数学模型在自动控制理论中的应用、MATLAB 在自动控制系统设计中的应用、滞后校正的设计原理、传递函数在自动控制系统中的应用、MATLAB 在滞后校正...
文将对 Linux™ 程序员可以使用的内存管理技术进行概述,虽然关注的重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
通过分析上述的源代码实例,你可以逐步掌握VB编程的技巧,了解如何将理论知识应用于实际项目。每个实例都是一个小型的解决方案,它们可以帮助你理解特定的概念或技术,并激发你去探索更复杂的编程挑战。在学习过程中...
在系统分析时期,需要确保系统目标知足单位内外的治理对会计信息的需求,能完成所要承担的会计工作,要符合单位财会人员的适应,同时必需保证数据信息的靠得住性并具有必然的效率。审计内容和方式包括: 1. 确信...