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,计算那里有多少个参数,然后调用 mainmainreturns后调用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 已经作为这个答案的副本帮助关闭了。