在C语言中编译并运行没有main()的程序

我试图编译和运行下面的程序没有main()函数在C 。 我已经使用以下命令编译了我的程序。

 gcc -nostartfiles nomain.c 

编译器给出警告

 /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340 

好吧,没问题。 然后,我运行可执行文件(a.out), printf语句都成功打印,然后出现分段错误

所以,我的问题是, 成功执行打印语句后为什么分段错误?

我的代码:

 #include <stdio.h> void nomain() { printf("Hello World...\n"); printf("Successfully run without main...\n"); } 

输出:

 Hello World... Successfully run without main... Segmentation fault (core dumped) 

注意:

在这里, -nostartfiles gcc标志防止编译器在链接时使用标准启动文件

让我们来看看你的程序生成的程序集:

 .LC0: .string "Hello World..." .LC1: .string "Successfully run without main..." nomain: push rbp mov rbp, rsp mov edi, OFFSET FLAT:.LC0 call puts mov edi, OFFSET FLAT:.LC1 call puts nop pop rbp ret 

注意ret语句。 您的程序入口点被确定为不是nomain ,一切都很好。 但是,一旦函数返回,它将尝试跳转到未被填充的调用堆栈中的地址。 这是一个非法的访问和分段错误如下。

一个快速的解决scheme是在你的程序结束时调用exit (假设C11我们可能把_Noreturn标记为函数):

 #include <stdio.h> #include <stdlib.h> _Noreturn void nomain(void) { printf("Hello World...\n"); printf("Successfully run without main...\n"); exit(0); } 

实际上,现在你的函数performance得像一个常规的main函数,因为从main返回后,exit函数被调用main的返回值。

在C中,当调用函数/子程序时,堆栈被填充为(按顺序):

  1. 论点,
  2. 退货地址,
  3. 局部variables, – > 栈顶

main()作为开始点,ELF以这样的方式构造程序,无论指令先到哪里,都会先被推送,在这种情况下,printfs是。

现在,程序被截断了,没有返回地址或者__end__ ,事实上它假定堆栈中的任何东西( __end__ )都是返回地址,但不幸的是它不是,所以它崩溃了。