没有了 main 函数,程序还能跑吗?
Posted Li-Yongjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了没有了 main 函数,程序还能跑吗?相关的知识,希望对你有一定的参考价值。
刑天
刑天,是中国远古神话传说人物,手使一柄巨斧和盾牌,身强力壮,体型巨大的上古巨人,炎帝手下大将,和黄帝争位,被斩去头颅,失了首级后,以双乳为眼,肚脐为口,再战黄帝。
刑天没有了头仍然可以战斗,程序没有了 main 函数,还能跑吗?
答案是:可以的。
代码
nomain.c
#include <stdio.h>
#include <stdlib.h>
void nomain()
{
printf("hello world\\n");
exit(0);
}
编译
$ gcc -nostartfiles nomain.c -o nomain.out
/usr/bin/ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000001050
忽略警告
-nostartfiles 选项是让链接器在链接时不使用标准启动文件
运行
$ ./nomain.out
hello world
探索
我们使用 -S 参数将 c 程序编译成汇编,一探究竟
$ gcc -S -nostartfiles nomain.c
liyongjun@Box:~/project/c/C_study/others/ld$ cat nomain.s
.file "nomain.c"
.text
.section .rodata
.LC0:
.string "hello world"
.text
.globl nomain
.type nomain, @function
nomain:
.LFB6:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %edi
call exit@PLT
.cfi_endproc
...
可以看到程序的入口点确实是 nomain,所以我们的程序可以正常运行。
疑问
如果代码里有两个函数,程序该选择哪个作为入口呢?
#include <stdio.h>
#include <stdlib.h>
void nomain()
{
printf("hello world\\n");
exit(0);
}
void nomain_2()
{
printf("hello world 2\\n");
exit(0);
}
$ gcc -nostartfiles nomain.c -o nomain.out
/usr/bin/ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000001050
$ ./nomain.out
hello world
从执行的结果可以看到程序选择了 nomain() 函数作为了程序入口点,看下汇编的内容:
$ gcc -S -nostartfiles nomain.c
liyongjun@Box:~/project/c/C_study/others/ld$ cat nomain.s
.file "nomain.c"
.text
.section .rodata
.LC0:
.string "hello world"
.text
.globl nomain
.type nomain, @function
nomain:
.LFB6:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %edi
call exit@PLT
.cfi_endproc
.LFE6:
.size nomain, .-nomain
.section .rodata
.LC1:
.string "hello world 2"
.text
.globl nomain_2
.type nomain_2, @function
nomain_2:
.LFB7:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC1(%rip), %rdi
call puts@PLT
movl $0, %edi
call exit@PLT
.cfi_endproc
...
显然,在 c 程序中,nomain 函数在 nomain_2 函数之前,编译成汇编后,nomain 依然在前面,就被选择作为了程序的入口点。如果我们把 nomain_2 写在前面,那么 nomain_2 就会被选为函数的入口点,验证如下:
#include <stdio.h>
#include <stdlib.h>
void nomain_2()
{
printf("hello world 2\\n");
exit(0);
}
void nomain()
{
printf("hello world\\n");
exit(0);
}
$ gcc -nostartfiles nomain.c -o nomain.out
/usr/bin/ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000001050
$ ./nomain.out
hello world 2
指定
在不改变代码的情况下,我们可以使用 gcc 的 -e 选项来指定程序的入口函数
#include <stdio.h>
#include <stdlib.h>
void nomain_2()
{
printf("hello world 2\\n");
exit(0);
}
void nomain_3()
{
printf("hello world 3\\n");
exit(0);
}
void nomain()
{
printf("hello world\\n");
exit(0);
}
$ gcc -nostartfiles -e nomain_3 nomain.c -o nomain.out
$ ./nomain.out
hello world 3
就像换挡,指定一个挡位作为动力运行点。
以上是关于没有了 main 函数,程序还能跑吗?的主要内容,如果未能解决你的问题,请参考以下文章