我注意到许多汇编语言示例都是使用直接的Win32调用构建的(无C运行时依赖项)说明如何使用ExitProcess显式调用()在入口点代码的末尾结束程序。我不是在谈论使用ExitProcess()在程序中的某个嵌套位置退出。令人惊讶的是,使用RET指令退出入口点代码的例子很少。我们想到的一个例子是著名的TinyPE,其中的程序变体使用RET指令退出,因为RET指令是单字节的,使用ExitProcess()或RET似乎都可以完成这项工作。
来自可执行文件入口点的RET将EAX的值返回给KERNEL32中的Windows加载程序,后者最终将退出代码传播回NtTerminateProcess(),至少在Windows 7上是这样。在Windows XP上,我记得我看到过ExitProcess()甚至是在线程清理链的末尾直接调用的。
既然汇编语言中有许多受人尊敬的优化,它们纯粹是为了生成更小的代码而选择的,我想知道为什么更多的代码更喜欢显式调用ExitProcess(),而不是RET。
从最纯粹的意义上讲,RET指令不是比直接调用ExitProcess()更好吗?直接调用ExitProcess()似乎类似于通过从任务管理器中杀死程序来退出程序,因为这会缩短返回Windows加载程序调用入口点的正常流程,从而跳过各种线程清理操作。
我似乎找不到任何关于这个问题的具体信息,所以我希望有人能在这个主题上提供一些线索。
1条答案
按热度按时间f45qwnt81#
如果main函数是从C运行时库调用的,那么退出将导致调用ExitProcess(),进程将退出。
如果你的主函数是由Windows直接调用的,就像汇编代码的情况一样,那么退出只会导致 * 线程 * 退出。当且仅当 * 没有其他线程时,进程才会退出。现在这是个问题,因为即使 * 你 * 没有创建任何线程,Windows也可能已经为你创建了一个或多个线程。
据我所知,这种行为没有适当的文档记录,但在Raymond Chen的博客文章"If you return from the main thread, does the process exit?"中有所描述。
(我自己也在Windows 7和Windows 10上测试过这一点,并确认它们的行为如雷蒙德所描述的那样。)