【发布时间】:2015-06-24 00:44:44
【问题描述】:
我从同事那里了解到,无需编写 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
什么时候需要做这种事情?是否有任何现实世界的场景可以使用它?
【问题讨论】:
-
经典文章,展示了程序如何启动的一些内部工作原理:A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux。这是一本很好的读物,讨论了
_start()的一些细节以及main()之外的其他内容。 -
C 语言本身没有提及
_start或除main之外的任何入口点(除了入口点的名称是为独立(嵌入式)实现定义的)。 -
注意这个
_start是不安全的,调用my_main时违反了ABI;你告诉编译器这是一个普通函数,但实际上它是在堆栈指针已经对齐的情况下输入的(例如在 x86-64 上,RSP % 16 == 0),而不是像在进入普通函数之后那样的 RSP % 16 == 8一个call,它推送一个 8 字节的返回地址。你可以用__attribute__((force_align_arg_pointer))来解决这个问题,_start告诉 GCC 堆栈指针可能在进入那个“函数”时“未对齐”,如 Get arg values with inline asm without Glibc? 所示 -
在现代 Linux 发行版上,如果
my_main完全使用 scanf 或带有floar或doubleFP 参数的 printf(或任何可变参数函数),这将导致崩溃。 glibc scanf Segmentation faults when called from a function that doesn't align RSP