C中_start()有什么用?
What is the use of _start() in C?
我从同事那里了解到,无需编写 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
是程序的入口点,但从 OS 的角度来看 _start
是通常的入口点(在您的程序之后执行的第一条指令)程序从 OS)
开始
在一个典型的C尤其是C++程序中,在执行进入main之前已经做了很多工作。 特别是全局变量的初始化之类的东西。 Here 你可以找到对 _start()
和 main()
之间以及 main 之后发生的一切的很好的解释又退出了(见下面的评论)。
必要的代码通常由编译器编写者在启动文件中提供,但是使用标志 –nostartfiles
你实际上告诉编译器:"Don't bother giving me the standard startup file, give me full control over what is happening right from the start".
这有时是必要的,并且经常用于嵌入式系统。例如。如果您没有 OS 并且您必须在初始化全局对象之前手动启用内存系统的某些部分(例如缓存)。
符号_start
是您程序的入口点。也就是说,该符号的地址是程序启动时跳转到的地址。通常,名称为 _start
的函数由名为 crt0.o
的文件提供,该文件包含 C 运行时环境的启动代码。它设置一些东西,填充参数数组 argv
,计算那里有多少个参数,然后调用 main
。 main
returns后调用exit
如果程序不想使用 C 运行时环境,则需要为 _start
提供自己的代码。例如,Go 编程语言的参考实现之所以这样做,是因为它们需要一个非标准的线程模型,这需要一些堆栈魔法。当您想编写非常小的程序或执行非常规操作的程序时,提供您自己的 _start
也很有用。
When would one need to do this kind of thing?
当您想要自己的程序启动代码时。
main
不是 C 程序的第一个入口,_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
Is there any real world scenario where this would be useful?
如果你的意思是,实现我们自己的_start
:
是的,在我使用过的大多数商业嵌入式软件中,我们需要根据我们的特定内存和性能要求实现我们自己的 _start
。
如果你的意思是,删除 main
函数并将其更改为其他函数:
不,我认为这样做没有任何好处。
Here 很好地概述了程序启动 之前 main
期间发生的情况。特别是,它表明 __start
从 OS 的角度来看, 是您程序的实际入口点。
这是 instruction pointer 在您的程序中开始计数的第一个地址。
那里的代码调用一些 C 运行时库例程只是为了做一些内务处理,然后调用你的 main
,然后把东西放下并用任何退出代码调用 exit
main
返回。
一图胜千言:
P.S:这个答案是从 another question 移植过来的,SO 已经作为这个答案的副本帮助关闭了。
我从同事那里了解到,无需编写 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
是程序的入口点,但从 OS 的角度来看 _start
是通常的入口点(在您的程序之后执行的第一条指令)程序从 OS)
在一个典型的C尤其是C++程序中,在执行进入main之前已经做了很多工作。 特别是全局变量的初始化之类的东西。 Here 你可以找到对 _start()
和 main()
之间以及 main 之后发生的一切的很好的解释又退出了(见下面的评论)。
必要的代码通常由编译器编写者在启动文件中提供,但是使用标志 –nostartfiles
你实际上告诉编译器:"Don't bother giving me the standard startup file, give me full control over what is happening right from the start".
这有时是必要的,并且经常用于嵌入式系统。例如。如果您没有 OS 并且您必须在初始化全局对象之前手动启用内存系统的某些部分(例如缓存)。
符号_start
是您程序的入口点。也就是说,该符号的地址是程序启动时跳转到的地址。通常,名称为 _start
的函数由名为 crt0.o
的文件提供,该文件包含 C 运行时环境的启动代码。它设置一些东西,填充参数数组 argv
,计算那里有多少个参数,然后调用 main
。 main
returns后调用exit
如果程序不想使用 C 运行时环境,则需要为 _start
提供自己的代码。例如,Go 编程语言的参考实现之所以这样做,是因为它们需要一个非标准的线程模型,这需要一些堆栈魔法。当您想编写非常小的程序或执行非常规操作的程序时,提供您自己的 _start
也很有用。
When would one need to do this kind of thing?
当您想要自己的程序启动代码时。
main
不是 C 程序的第一个入口,_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
Is there any real world scenario where this would be useful?
如果你的意思是,实现我们自己的_start
:
是的,在我使用过的大多数商业嵌入式软件中,我们需要根据我们的特定内存和性能要求实现我们自己的 _start
。
如果你的意思是,删除 main
函数并将其更改为其他函数:
不,我认为这样做没有任何好处。
Here 很好地概述了程序启动 之前 main
期间发生的情况。特别是,它表明 __start
从 OS 的角度来看, 是您程序的实际入口点。
这是 instruction pointer 在您的程序中开始计数的第一个地址。
那里的代码调用一些 C 运行时库例程只是为了做一些内务处理,然后调用你的 main
,然后把东西放下并用任何退出代码调用 exit
main
返回。
一图胜千言:
P.S:这个答案是从 another question 移植过来的,SO 已经作为这个答案的副本帮助关闭了。