_start()在C中有什么用途?
我从我的同事那里学到了不用编写_start()在C中有什么用途?,c,gcc,startup,C,Gcc,Startup,我从我的同事那里学到了不用编写main()函数就可以编写和执行C程序。可以这样做: my_main.c /* Compile this with gcc -nostartfiles */ #include <stdlib.h> void _start() { int ret = my_main(); exit(ret); } int my_main() { puts("This is a program without a main() function!");
main()
函数就可以编写和执行C程序。可以这样做:
my_main.c
/* Compile this with gcc -nostartfiles */
#include <stdlib.h>
void _start() {
int ret = my_main();
exit(ret);
}
int my_main() {
puts("This is a program without a main() function!");
return 0;
}
使用以下命令运行它:
gcc -o my_main my_main.c –nostartfiles
./my_main
什么时候需要做这种事情?在现实世界中,这是否有用?虽然从程序员的角度来看,
main
是程序的入口点,但从操作系统的角度来看,\u start
是通常的入口点(从操作系统启动程序后执行的第一条指令)
在典型的C语言中,尤其是C++程序,在执行进入主程序之前已经做了大量的工作。特别是全局变量的初始化。您可以找到一个很好的解释,说明在
\u start()
和main()
之间以及在main再次退出之后发生的一切(参见下面的注释)。这方面的必要代码通常由编译器编写者在启动文件中提供,但使用标志
–nostartfiles
基本上告诉编译器:“不要麻烦给我标准启动文件,让我从一开始就完全控制正在发生的事情”
这有时是必要的,通常用于嵌入式系统。例如,如果您没有操作系统,并且在初始化全局对象之前必须手动启用内存系统的某些部分(例如缓存)。符号
\u start
是程序的入口点。也就是说,该符号的地址是程序启动时跳转到的地址。通常,名为\u start
的函数由名为crt0.o
的文件提供,该文件包含C运行时环境的启动代码。它设置一些东西,填充参数数组argv
,计算有多少个参数,然后调用main
。在main
返回后,调用exit
如果程序不想使用C运行时环境,它需要为
\u start
提供自己的代码。例如,Go编程语言的参考实现就是这样做的,因为它们需要一个非标准的线程模型,这需要堆栈的一些魔力。当您想要编写非常小的程序或执行非常规操作的程序时,提供自己的\u start
也很有用
什么时候需要做这种事情
当您想要自己的程序启动代码时
main
不是C程序的第一个条目,\u start
是幕后的第一个条目
Linux中的示例:
_start: # _start is the entry point known to the linker
xor %ebp, %ebp # effectively RBP := 0, mark the end of stack frames
mov (%rsp), %edi # get argc from the stack (implicitly zero-extended to 64-bit)
lea 8(%rsp), %rsi # take the address of argv from the stack
lea 16(%rsp,%rdi,8), %rdx # take the address of envp from the stack
xor %eax, %eax # per ABI and compatibility with icc
call main # %edi, %rsi, %rdx are the three args (of which first two are C standard) to main
mov %eax, %edi # transfer the return of main to the first argument of _exit
xor %eax, %eax # per ABI and compatibility with icc
call _exit # terminate the program
在现实世界中,这是否有用
如果您的意思是,实施我们自己的\u start
:
是的,在我使用过的大多数商用嵌入式软件中,我们需要根据特定的内存和性能要求实现我们自己的\u start
如果您的意思是,请删除main
函数并将其更改为其他内容:
不,我看不出这样做有什么好处 很好地概述了在main
之前程序启动期间发生的情况。特别是,它表明从操作系统的角度来看,\u start
是程序的实际入口点
它是程序中开始计数的第一个地址
那里的代码调用一些C运行时库例程只是为了做一些内务处理,然后调用main
,然后关闭并调用exit
,返回任何退出代码main
一幅画胜过千言万语:
附言:这个答案是从SO那里移植的,SO作为这个答案的副本关闭了它。远程相关:演示程序如何启动的一些内部工作原理的经典文章:。这本书讨论了
\u start()
和main()
之外的其他内容的一些细节。C语言本身没有提到\u start
,也没有提到除main
之外的任何入口点(入口点的名称是为独立(嵌入式)实现定义的)请注意,此\u start
不安全,在调用my_main
时违反了ABI;您告诉编译器这是一个普通函数,但实际上它是在堆栈指针已经对齐的情况下输入的(例如,在x86-64上,RSP%16==0),而不是像在推送8字节返回地址的调用之后进入普通函数时那样的RSP%16==8。您可以使用\uu attribute\uuuuuuu((强制对齐参数指针))
为\u start
修复此问题,以告诉GCC堆栈指针在进入该“函数”时可能“未对齐”,如现代Linux发行版中所示,如果my\u main
使用scanf或printf(或任何可变函数),这将导致崩溃使用floar
或double
FP arg。另一个例子是Linux的动态链接器/加载器,它定义了自己的“启动”。@BlueMoon但是\u start
也来自对象文件crt0.o
。@ThomasMatthews标准没有指定\u start
;实际上,它根本没有指定在调用main
之前会发生什么,它只是指定调用main
时必须满足哪些条件。更像是一种约定,入口点是\u start
,可以追溯到过去。“Go编程语言的参考实现之所以这样做,是因为它们需要一个非标准线程模型”crt0.o是特定于C的(crt->C运行时)。没有理由期望它被用于任何其他语言。Go的线程模型是完全标准的compliant@SteveCox许多编程语言都构建在C运行时之上,因为这样更容易实现语言。去是不行的