在C中_start()有什么用?

时间:2015-04-17 08:52:54

标签: 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

何时需要做这种事情?有没有真实世界的场景,这会有用吗?

4 个答案:

答案 0 :(得分:91)

符号_start是程序的入口点。也就是说,该符号的地址是程序启动时跳转到的地址。通常,名为_start的函数由名为crt0.o的文件提供,该文件包含C运行时环境的启动代码。它设置一些东西,填充参数数组argv,计算有多少参数,然后调用mainmain返回后,系统会调用exit

如果程序不想使用C运行时环境,则需要为_start提供自己的代码。例如,Go编程语言的参考实现是这样做的,因为它们需要一个非标准的线程模型,这需要一些神奇的堆栈。当您想编写非常小的程序或执行非常规事物的程序时,提供自己的_start也很有用。

答案 1 :(得分:43)

虽然从程序员的角度来看main是程序的入口点,_start是OS操作系统的常用入口点(从OS启动程序后执行的第一条指令) )

在典型的C,尤其是C ++程序中,在执行main之前已经完成了很多工作。 特别是像全局变量初始化这样的东西。 Here你可以找到_start()main()之间发生的所有事情的良好解释,以及在main再次退出之后(见下面的评论) 它的必要代码通常由编译器编写者在启动文件中提供,但是使用标志–nostartfiles,你基本上告诉编译器:“不要打扰给我标准的启动文件,让我完全控制什么从一开始就发生了“。

这有时是必要的,并且经常在嵌入式系统上使用。例如。如果您没有操作系统,则必须在初始化全局对象之前手动启用内存系统的某些部分(例如缓存)。

答案 2 :(得分:1)

  

什么时候需要做这种事情?

当您想要自己的程序启动代码时。

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
  

在现实世界中,这是否有用?

如果您是故意的,请实施我们自己的_start

是的,在我使用过的大多数商业嵌入式软件中,我们都需要针对自己的特定内存和性能要求实施自己的_start

如果您的意思是,请放下main函数并将其更改为其他内容:

不,我认为这样做没有任何好处。

答案 3 :(得分:-1)

_start()是由特殊标头指向的函数,仅供计算机理解。但是这很重要,因为我们应该了解计算机背面的情况。