哪个机制知道程序的入口点是 main()

Which mechanism knows the entry point of a program is main()

应用程序如何知道其入口点是 main() 函数?

我知道应用程序不知道它的入口点是 main() -- 它通过语言规范指向 main() 函数。

此时,规范实际声明在哪里?例如在 C 中,入口点应为 main() 函数。这个机制是谁给程序提供的?操作系统或编译器?

我在反汇编 Visual Studio 中的一个规范的简单 "Hello World" 示例后提出了这个问题。

这段代码只有几行和一个函数main()

但是反汇编后内存中有很多定义和宏space并且main()不是唯一的声明和定义

下面是拆解部分的截图。我也知道在语言定义中有一个严格的规则,只有一个 main() 函数必须被定义并存在。

总结一下我的问题:我想知道哪种机制将 main() 函数引导或设置为应用程序的入口点。

应用程序不知道main() 是入口点。首先,不管你的图片如何,我们在这里假设 C 而不是 C++。

对于 C,“C”入口点是 main()。但是你不能在那里开始执行,因为我们在 C 中有假设,不仅如此,还有规则,例如 .data 需要初始化并且 .bss 归零。

unsigned x = 1;
unsigned int y;

我们预计当 main() 被命中时 x=1。并且 most 人假设,也许当时指定 y = 0,我不会做那个假设,但无论如何。

我们还需要一个栈指针,需要处理argc/argv。如果是 C++,则必须完成其他工作。即使对于 C 依赖。

应用程序通常不知道这些。您可能正在使用 C 库,并且该库 is/should 负责 main() 之前的 bootstrap 代码以及链接器的链接器脚本,因为 bootstrap 和链接器脚本密切相关有关的。有人可能会根据一些实现争论 C 库与工具链是可分离的,因为我们知道使用 gnu 你可以从不同的库中选择 ose,而 those 有不同的 bootstraps和链接描述文件。但我敢肯定有很多是密切相关的,还有库和操作系统的关系,因为很多 C 库调用最终会导致一个或无数个系统调用。

你设计了一个操作系统,假设它支持操作系统设计的一部分 运行time loadable applications 是操作系统加载器支持的文件格式,操作系统加载器想要支持的功能以及它们如何与文件格式重叠,对于 OS 定义文件格式并不罕见,但是对于 elf 和其他人(毫无疑问,不是 accidentally/independently 创建的),您有机会获得新的 OS 使用像 elf 这样的现有容器。 OS 设计及其加载器决定了很多事情,而与所有这些相匹配的 C 库必须遵循所有 ose 规则,如果集成到编译器中,则编译器具有一起玩

应用程序不知道它是系统设计的一部分,应用程序只是所有这些的奴隶,当您在该平台上为该平台编译时,所有这些规则和关系都在起作用,您只是拼图的一小部分,其余部分已经到位,支持哪些文件格式,每种格式需要哪些信息,compiler/library 解决方案必须提供哪些规则。系统设计决定了 .data 和 .bss 是由加载程序还是由应用程序清零,我的意思是 bootstrap 而不是程序的用户部分,你不能 bootstrap C 在C 因为那个 C 需要一个 bootstrap 并且如果那个 bootstrap 在 C 中那么 C 将需要一个 bootstrap 等等。

int main ( void )
{
    return 0;  
}

当您编译该程序时,后台会发生很多事情,而不仅仅是实现该代码可能需要的几条指令。

在 windows 和 Linux 和 mac 上编译该程序,每个版本的每个版本都有不同的编译器或 C 库,每个版本都有不同的版本,等等。还有什么您应该期望看到的是,即使是相同的目标 ISA,甚至是同一台计算机,一定比例的组合可能会选择 ose 相同的几条函数指令,它所包含的内容可能是相似的但不一样。如果某些实现彼此非常不同,也没有理由感到惊讶。

这就是将程序加载到 ram 和 运行 的成熟操作系统的全部内容,对于嵌入式的东西,如果差异更大也不要感到惊讶。在一个完整的 os 中,您会期望看到一个 mmu,并且应用程序至少会为 .text、.data、.bss 获得一个可能基于零的地址 space,因此所有解决方案都可能有一个最喜欢的在二进制文件中以相同的顺序放置或喜欢多个部分,但每个部分的大小可能特定于实现。 order/size 可能因 C 库版本或编译器版本等而异。

神奇之处在于系统设计。那不是魔法,那是设计。 main() 不能直接输入,语言的各个部分仍然像 .data 和 .bss init 一样工作,堆栈指针可以在输入之前解决,但是 .data 和 .bss 的方式和位置是特定于应用程序的,因此无法处理通过从 OS.

到 main 的简单分支

您的工具链的链接器可以通过多种方式告知,入口点可以是 assumed/dictated tool/target 或命令行选项或链接器脚本选项,或一些特殊的你放在标签上的符号或设计师选择的任何东西ose。 main 被假定为 C 入口点,尽管这实际上并不意味着它之前可能有一些 C 代码,但通常有一定数量的 asm(不能 bootstrap C with C)然后main() 的一个或多个步骤。