0

他们说main()是一个与任何其他函数一样的函数,但“标记”为二进制文件中的入口点,操作系统可能会找到(不知道如何)并从那里启动程序的入口点。因此,我正在尝试了解有关此功能的更多信息。我做了什么?我创建了一个简单的 .C 文件,其中包含以下代码:

int main(int argc, char **argv) {
     return (0);
}

我保存了文件,安装了 GCC 编译器(在 Windows,MingW 环境中)并创建了一个批处理文件,如下所示:

gcc -c test.c -nostartfiles -nodefaultlibs -nostdlib -nostdinc -o test.o
gcc -o test.exe -nostartfiles -nodefaultlibs -nostdlib -nostdinc -s -O2 test.o
@%comspec%

我这样做是为了获得一个非常简单的编译器和链接器,没有库,没有头文件,只有编译器。因此,编译顺利,但链接停止并出现此错误:

test.c:(.text+0xa): undefined reference to '___main'
collect2.exe: error: Id returned 1 exit status

我认为主要功能是由链接器导出的,但我相信您不需要任何包含有关它的附加信息的库。但它看起来确实如此。就我而言,我认为它必须是标准的 GCC 库,所以我下载了它的源代码并打开了这个文件:libgcc2.c 现在,我不知道这是否是构建 main 函数的文件由 GCC 链接。其实我不明白 GCC 是怎么使用 main 函数的。为什么链接器需要 gcc 标准库?想知道主线呢?我希望这使我的问题非常具体和明确。谢谢!

4

2 回答 2

5

当 gcc 将所有对象文件 (test.o) 和库放在一起形成二进制文件时,它还会预先添加一个小对象(通常是 crt0.o 或 crt1.o),它负责调用您的main(). -v当您在命令行中添加时,您可以看到 gcc 在做什么:

$ gcc -v -o test.exe test.o

crt0/crt1 进行一些设置,然后调用 main。但是链接器最终负责根据操作系统构建可执行文件。-v您还可以看到目标系统的一个选项。就我而言,它适用于 Linux 64 位:-m elf_x86_64. 对于您的系统,这将类似于-m windowsor -m mingw

于 2012-11-06T09:02:04.293 回答
1

发生错误是因为您使用了以下两个选项:-nodefaultlibs -nostdlib

这些告诉 GCC 它不应该将您的代码链接到libc.a/c.lib包含真正调用的代码main()。简而言之,每个操作系统都略有不同,其中大多数都不关心 C 和main(). 每个都有自己特殊的方式来启动一个进程,并且大多数都与 C API 不兼容。

因此 C 开发人员的解决方案是将“胶水代码”放入libc.a包含操作系统期望接口的 C 标准库中,创建标准 C 环境(设置内存分配结构,以便malloc()映射操作系统的内存管理功能,设置up stdio 等)并最终调用main()

对于 C 开发人员来说,这意味着他们可以获得libc.a适用于他们的操作系统(以及编译器二进制文件)的版本,并且他们不需要关心设置的工作方式。

另一个混淆来源是参考的名称。在大多数系统上,main()is的符号名称_main(即一个下划线),__main而是由设置代码调用的内部函数的名称,最终调用真正的main()

于 2012-11-06T09:00:35.503 回答