没有了 main 函数,程序还能跑吗?

69 篇文章 18 订阅
4 篇文章 0 订阅

刑天

在这里插入图片描述

刑天,是中国远古神话传说人物,手使一柄巨斧和盾牌,身强力壮,体型巨大的上古巨人,炎帝手下大将,和黄帝争位,被斩去头颅,失了首级后,以双乳为眼,肚脐为口,再战黄帝。

刑天没有了头仍然可以战斗,程序没有了 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

就像换挡,指定一个挡位作为动力运行点。
在这里插入图片描述

评论 124
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li-Yongjun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值