他们说 main()是一个像任何其他函数一样的函数,但是“标记”为二进制内部的入口点,操作系统可能会找到一个入口点( Don不知道如何)并从那里开始程序。所以,我试图找到更多关于这个功能的信息。我做了什么?我用这个代码创建了一个简单的.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 现在,我不知道这是否是构建主要功能以通过GCC链接的文件。事实上,我不明白GCC如何使用主要功能。为什么链接器需要gcc标准库? 要知道什么是主?我希望这使我的问题非常具体和明确。谢谢!
答案 0 :(得分: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 windows
或-m mingw
。
答案 1 :(得分:1)
发生错误是因为您使用以下两个选项:-nodefaultlibs -nostdlib
这些告诉GCC,它不应该将您的代码与包含真正调用libc.a
的代码的c.lib
/ main()
相关联。简而言之,每个操作系统都略有不同,大多数操作系统都不关心C和main()
。每个都有自己特殊的方式来启动一个过程,其中大多数都与C API不兼容。
因此,C开发人员的解决方案是将“粘合代码”放入C标准库libc.a
,其中包含操作系统期望的接口,创建标准C环境(设置内存分配结构,以便{ {1}}将映射操作系统的内存管理功能,设置stdio等)并最终调用malloc()
对于C开发人员来说,这意味着他们获得了main()
的操作系统(以及编译器二进制文件),他们不需要关心设置的工作方式。
混淆的另一个原因是参考的名称。在大多数系统上,libc.a
的符号名称为main()
(即一个下划线),而_main
是由设置代码调用的内部函数的名称,最终调用真实{{1} }}