我正在学习x86汇编。我试图了解"退出程序"在 x86 上的工作原理。我们有一个代码:
push ebp
mov ebp,esp
//Some stuff here
mov esp, ebp
pop ebp
ret
当处理器执行指令"ret"时:
EIP 将具有从堆栈中弹出的值,换句话说,为 0。所以处理器将转到 0 地址并尝试执行指令......不包含程序代码/可执行代码。那么,处理器到底是怎么回事呢?是否有条件检查,例如,if EIP = 0 -> exit program?
Or if ESP out of bounds -> exit program?
"处理器如何理解此RET指令是程序的结束?
>main()
是从正常的 C 运行时初始化函数调用的。 用任何语言(包括asm(编写main
与编写任何其他函数没有什么不同。
执行从 _start
开始。 如果你编写自己的_start
,它没有什么可返回的,所以你需要进行_exit(2)
或exit_group(2)
系统调用。
(或者,当执行从代码末尾掉下来时,或者如果您尝试ret
它会将堆栈中的值弹出到程序计数器 (EIP( 中,并且可能会在从该可能无效的地址获取代码时出现段错误。
当您使用 C 编译器编译 + 链接时,它会链接在 CRT(C 运行时(启动代码中,该代码提供了一个初始化 libc 然后调用 main
的_start
。 main
返回后,调用它的 CRT 代码将运行atexit
函数,然后将 main 的返回值传递给退出系统调用。
_start
不是一个函数,而是一个进程入口点。 例如,在Linux下,在进入_start
ESP点时argc
,而不是返回地址。 (请参阅 i386 系统 V ABI。
这个问题是从不同的角度来的,但我对最近另一个问题的回答更详细。
与往常一样,使用调试器单步执行是查看正在发生的事情并测试您的理解的好方法。
该进程作系统终止。如果您看到返回指令,则在函数之前有一个("隐藏"(函数,然后返回执行。
在 Linux(32 位(环境中终止进程的一种方法是调用特定的系统调用:sys_exit
mov eax, 0 // interrupt code
mov ebx, 0 // argument, in this case: return value
int 0x80
这可能是函数之前的函数所做的事情。上面的代码将命令交回操作系统,然后操作系统退出您的进程。