我正在使用fasm学习汇编,我在函数调用后无法从main返回。使用空程序,我可以使其正常工作
format PE console
entry start
include 'win32a.inc'
section '.text' code executable
start:
push ebp
mov ebp, esp
leave
ret
section '.rdata' data readable
format_str db '%d', 10, 0
section '.idata' data readable import
library msvcrt, 'msvcrt.dll'
import msvcrt, printf, 'printf'
但是如果我添加一个函数调用(在这种情况下是printf)就像这样
format PE console
entry start
include 'win32a.inc'
section '.text' code executable
start:
push ebp
mov ebp, esp
push esp
push format_str ;set to '%d',10,0 in the data section
call [printf]
add esp, 2*4
leave
ret
section '.rdata' data readable
format_str db '%d', 10, 0
section '.idata' data readable import
library msvcrt, 'msvcrt.dll'
import msvcrt, printf, 'printf'
程序将成功打印但无法退出程序并崩溃
函数调用中发生什么导致我的return语句失败,我该如何纠正呢?
答案 0 :(得分:2)
进程中的初始线程基本上如下所示:
call LdrLoadAllTheThings ; Might call TLS callbacks etc
call pe_entrypoint ; Your function
push somenumber
call ExitThread ; Exit this thread and possibly the process
一个进程将在所有线程退出后结束,只是返回将适用于非常简单的程序但是只要有人调用CreateThread
或其中一个线程池函数,当你刚刚返回时,进程将不再结束,只要有其他线程正在工作/等待,它就会坚持下去。在旧版本的Windows上,控制台程序通常可以返回,但正如您所发现的,它只能起作用,因为被调用的函数没有创建新线程(依赖于内部实现细节)。在GUI程序中,它更不可能工作并且难以调试,因为点击标准UI元素时PlaySound
之类的东西可能会创建一个线程。
如果使用Microsoft工具链构建C / C ++应用程序并与其运行时库链接,那么主函数不是真正的入口点,真正的入口点是mainCRTStartup,它基本上是这样的:
__declspec(noreturn) void __cdecl mainCRTStartup()
{
int code;
char*argv;
int argc = parse(GetCommandLine(), &argv);
call_constructors();
code = main(argc, argv); // Your main function
call_destructors_and_atexit_callbacks();
ExitProcess(code); // End this thread and all other threads
}