【问题标题】:where goes the ret instruction of the mainmain 的 ret 指令在哪里
【发布时间】:2018-04-30 08:58:52
【问题描述】:

我在“从头开始编程”一书中了解了汇编 (x86) 的全局工作原理。 在本书中,每个程序都以退出的中断调用结束。

但是,在 C 编译程序中,我发现程序以 ret 结尾。这假设有一个要弹出的地址,这将导致程序结束。

所以我的问题是: 这个地址是什么? (那里的代码是什么?)

【问题讨论】:

  • 它们不以ret 结尾。 mainret 结尾,但这不是二进制文件中的完整代码,运行时 C 库具有启动/拆卸代码,并且调用 main 并在之后正确退出。 (您可以在链接期间检查编译器开关以查看所有参数,以查看添加了哪些库以及真正的入口点在哪里)
  • C 程序包含在一个包装器中,它设置数据等,并将参数提供给main(int argc, char *argv[])。所以退出的系统调用来自包装器。
  • 有一些启动代码在调用main() 之前为它设置环境(例如初始化标准输入、输出、错误文件流)。 main() 末尾的 ret 返回到该代码,这通常相当于 exit(main(argc, argv, environ));。 (environ 实际上很常见,但不是标准强制要求的。)
  • 是的 - 它通常被命名为“crt”(C 运行时),并以一种或另一种方式链接到您的编译代码。在非平凡操作系统上运行时,crt 将在 main() 返回后进行系统调用/中断以终止进程。
  • 那里的代码非常特定于操作系统,可能还有版本,因为它是操作系统将程序加载到 ram 中并“调用”它,程序从该程序返回一个 ret 到操作系统放置调用它的代码。你读的书很可能是基于dos程序,在哪里可以得到“os”来清理你,称为exit。但即使有一个编译器也可以在编译器提供的引导程序中退出,以便 main 简单地返回。编译器必须针对其目标、操作系统和指令集进行调整

标签: c assembly x86 return


【解决方案1】:

您通过要求 OS 将控制权传递给程序的 start_start 函数来启动程序,方法是跳转到你的代码。在 C 程序中,start 函数来自 C 库,并且(正如其他人之前已经说过的)执行一些特定于平台的环境初始化。然后 start 函数调用你的 ma​​in 并且控制权是你的。从 ma​​in 返回后,它会将控制权交还给 C 库,该库会正确终止程序并执行特定于平台的 系统调用 以将控制权交还给 操作系统

所以地址 main pops 是来自 C 库的标签。如果你想检查它,它应该在 stdlib.h (cstdlib) 中,你会看到它调用 exit 来进行清理。

它的作用是在程序终止或线程终止(C++11)时销毁静态对象(当然是C++)。在 C 的情况下,它只是关闭流、刷新它们的缓冲区、调用 atexit 函数并执行系统调用

我希望这是您寻求的答案。

【讨论】:

  • 实际上 _start 来自 libc(从某种意义上说,它与 libc 一起提供),但静态链接到您的可执行文件(与其他 CRT 启动代码一起)。所以它驻留在你的可执行文件中,如果你反汇编,你会在那里看到它(例如objdump -drwC -Mintel a.out | less
  • 你完全正确,只是这个词选错了。谢谢。
  • 在 x86-64 Linux 上的 glibc 中,__libc_start_main 使用普通的 call 指令 (call rax),然后分别以 main 的返回值调用 exitpush OFFSET exit / jmp rax 不起作用,因为 main 将其返回值保留在 eax 中,但 exit()edi 中查找其 arg。一些 ISA(如 ARM)使用调用约定,其中返回值寄存器也是第一个 arg 传递寄存器,但通常的 x86 调用约定都不是这样,因此 CRT 在call exit 之前需要一个mov edi,eax。跨度>
  • re:exit 完成的工作:它只为 static 对象运行析构函数。它还运行atexit 注册的任何函数,因此在 C 程序中您可以获得类似析构函数的功能。但这主要是吹毛求疵。
【解决方案2】:

它是特定于实现的。

在 Linux 上,maincrt0 调用,_start 入口点正在分析内核设置的初始call stack,解释可执行程序的execve(2) 系统调用。从main 返回时,crt0 的结尾部分正在处理atexit(3) 注册函数并刷新stdio

FWIW, crt0 是由您的 GCC 编译器提供的,也许是您的 C 标准库。所有这些(使用 Linux 内核)都是 Linux 发行版上的免费软件。

每个程序都以退出的中断调用结束。

不是真的。它是system call(请参阅syscalls(2) 获取他们的列表),而不是interrupt。另见this

【讨论】:

    猜你喜欢
    • 2017-09-04
    • 2013-04-05
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2012-12-15
    • 2021-10-23
    • 1970-01-01
    相关资源
    最近更新 更多