c语言如何自动生成main函数,C语言main函数生成可执行法 -电脑资料

1、define预处理指令

这种方式很简单,只是简单地将main字符串用宏来代替,或者使用##拼接字符串,

#include

#define begin main

int begin(void)

{

printf("Hello, World!\n");

return 0;

}

#include

#define begin m##a##i##n

int begin(void)

{

printf("Hello, World!\n");

return 0;

}

严格来说,这种方式只算是一种技巧......

2、_start函数

_start函数是C程序的入口函数,会调用main函数。在调用main函数之前,会先执行_start函数分配必要的资源,然后再调用main函数。但是在用gcc编译程序时可以使用-nostartfiles选项来重写_start函数。示例程序如下:

#include

#include

_start(void) {

printf("Hello, World!\n");

exit(0);

}

编译上面的程序的命令为:

gcc -nostartfiles _start.c -o a.out

反汇编生成的可执行程序,如下所示:

a.out: file format elf64-x86-64

Disassembly of section .plt:

0000000000400320:

400320: ff 35 ea 01 20 00 pushq 0x2001ea(%rip) # 600510

400326: ff 25 ec 01 20 00 jmpq *0x2001ec(%rip) # 600518

40032c: 0f 1f 40 00 nopl 0x0(%rax)

0000000000400330:

400330: ff 25 ea 01 20 00 jmpq *0x2001ea(%rip) # 600520

400336: 68 00 00 00 00 pushq $0x0

40033b: e9 e0 ff ff ff jmpq 400320

0000000000400340:

400340: ff 25 e2 01 20 00 jmpq *0x2001e2(%rip) # 600528

400346: 68 01 00 00 00 pushq $0x1

40034b: e9 d0 ff ff ff jmpq 400320

Disassembly of section .text:

0000000000400350 :

400350: 55 push %rbp

400351: 48 89 e5 mov %rsp,%rbp

400354: bf 68 03 40 00 mov $0x400368,%edi

400359: e8 d2 ff ff ff callq 400330

40035e: bf 00 00 00 00 mov $0x0,%edi

400363: e8 d8 ff ff ff callq 400340 exit@plt

上面的结果是完整的反汇编结果,我们可以看到_start函数中只有我们调用printf和exit函数相关的一些指令,并且.txt段中只有_start函数,没有看到main函数。如果将源代码中的_start替换为main,重新编译程序,反汇编的结果中会看到_start函数会调用到main。

另外还有一点需要注意,因为这里重写了_start函数,所以gcc为默认的main函数准备的清理动作就没用上,所以如果退出的时候直接使用return,会导致程序崩溃。所以这里要使用exit()来退出程序。具体的原因可以参见这篇文章。

3、gcc的-e选项

示例程序如下:

#include

#include

int nomain(int i, int j, int k) {

printf("Hello, World!\n");

exit(0);

}

将上面的程序保存为m.c,编译命令如下所示:

gcc -nostartfiles -e nomain m.c -o a.out

继续使用objdump反汇编生成的可执行程序,结果如下:

a.out: file format elf64-x86-64

Disassembly of section .plt:

0000000000400320:

400320: ff 35 f2 01 20 00 pushq 0x2001f2(%rip) # 600518

400326: ff 25 f4 01 20 00 jmpq *0x2001f4(%rip) # 600520

40032c: 0f 1f 40 00 nopl 0x0(%rax)

0000000000400330:

400330: ff 25 f2 01 20 00 jmpq *0x2001f2(%rip) # 600528

400336: 68 00 00 00 00 pushq $0x0

40033b: e9 e0 ff ff ff jmpq 400320

0000000000400340:

400340: ff 25 ea 01 20 00 jmpq *0x2001ea(%rip) # 600530

400346: 68 01 00 00 00 pushq $0x1

40034b: e9 d0 ff ff ff jmpq 400320

Disassembly of section .text:

0000000000400350:

400350: 55 push %rbp

400351: 48 89 e5 mov %rsp,%rbp

400354: 48 83 ec 10 sub $0x10,%rsp

400358: 89 7d fc mov %edi,-0x4(%rbp)

40035b: 89 75 f8 mov %esi,-0x8(%rbp)

40035e: 89 55 f4 mov %edx,-0xc(%rbp)

400361: bf 75 03 40 00 mov $0x400375,%edi

400366: e8 c5 ff ff ff callq 400330

40036b: bf 00 00 00 00 mov $0x0,%edi

400370: e8 cb ff ff ff callq 400340

从上面我们可以看到指定的nomain函数位于.text段的开始位置,同样在函数结束的时候没有gcc为main函数准备的清理动作,所以在这里也只能使用exit()来退出程序,而不能使用return,C语言main函数生成可执行法》(https://www.unjs.com)。

4、nostartfiles选项

前面已经多次使用了该选项,不过都是配合其他选项使用的,这个选项也可以单独使用,其含义为"Do not use the standard system startup files when linking"。

示例程序如下:

#include

#include

void func() {

printf("I am func....\n");

}

int nomain1(int i, int j, int k) {

func();

printf("%s: Hello, World!\n", __func__);

exit(0);

}

上面的程序保存为k.c,然后使用下面的命令编译:

[root@CentOS_190 ~]# gcc -nostartfiles p.c

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

在单独使用nostartfiles选项时会报警告,生成的可执行程序可以执行,但是会产生段错误,去掉对func()函数的调用就不会产生段错误了。将生成的可执行程序反汇编,和使用前面的方法生成可执行程序的反汇编结果比较,发现除了函数名不一样外,没有其他区别,不知道为什么会产生段错误。知道的麻烦告知一声,拜谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值