为什么写C程序在结束时不需要系统调用exit?

为什么写C程序在结束时不需要系统调用exit?

一、系统调用exit

众所周知,一个程序的执行和结束,都是需要发起系统调用。

调用execve系统调用,让操作系统加载该程序,调用exit系统调用,表示程序要退出,让操作系统清理空间。

写过汇编语言的都知道,一般都会使用下面的语句来(以Intel汇编为例)发起系统调用exit:

mov	eax,1
int	0x80

这是发起系统调用exit,用于程序退出。

但是,在C语言中,却没有这样系统调用退出的代码。

?你说这个东西太偏了,没用?

接着看下面的代码。

二、gcc链接和ld链接

有一段下面的代码:

// main.c
int main(void)
{
    return 0;
}
1. gcc编译链接

使用gcc编译链接,然后运行是没有任何问题的:

gcc -c main.c -o main.o -m32 # 编译
gcc main.o -o main -m32 # 链接
./main # 执行
  • 我这里使用参数-m32表示生成32位的程序,是因为32位的简单,容易分析。

  • 这里我把编译和链接分开写的,先用-c参数,编译,生成.o目标文件;然后生成可执行文件

运行如下图,没有任何问题:

image-20210608165846021

但是如果在链接时使用ld呢?

2. gcc编译,ld连接

gcc在链接时还是使用的ld,但是对ld进行了封装。

同样上面的代码main.c,使用gcc编译,ld链接,然后执行:

gcc -c main.c -o main.o -m32 # 编译
ld -m elf_i386 main.o -o main -e main # 链接
./main

使用ld链接时,使用-e表示程序的入口,这里使用指名main函数为程序入口

运行如下图:

image-20210608171320110

此时出现了,大名鼎鼎的 segmentation fault (core dumped)。

为什么会出现这样的错误呢?

3. 为什么会报错呢?

一般segmentation fault (core dumped)都是非法访问了没有权限访问的内存空间,所以dump了。

那么我的程序这么简单,就一个return 0,怎么会非法访问呢?

// main.c
int main(void)
{
    return 0;
}

就是在于,这个程序没有退出,没有执行系统调用exit,导致执行到其他地方的代码去了,然后非法访问。

3.1 如果手动添加系统调用exit

下面我自己使用内联汇编,手动添加一个系统调用exit退出:

void sys_exit(void)
{
	asm(\
	"mov $1, %eax;\
    int $0x80;"
	);
}
int main(void)
{
	sys_exit();
}

然后同样的使用gcc编译,使用ld链接,执行:

image-20210608172212462

上图可以看出,程序完美执行,不会segmentation fault了。

三、为什么使用gcc编译链接C程序不用添加系统调用exit?

上面的程序可以看到,C程序使用gcc编译,使用ld链接,因为没有系统调用exit,所以出错,这才符合我们的想法:程序退出时要调用exit系统调用。

但是,我们在写C程序时,直接用gcc编译链接,运行并没有问题,为什么呢?

就是因为gcc在链接时,做了点封装,让用户看不到exit系统调用的执行。

简单地讲,使用gcc链接C程序时,入口默认是_start函数,然后_start会调用main(这个应该多多少少听过)。

_start在执行时,会做下面的事情:

  • 初始化环境
  • 调用main函数
  • 调用系统调用exit结束运行

这就解决了下面的问题:

  • 为什么C程序不需要系统调用exit来结束运行
    • 是因为使用gcc链接时,默认的程序入口是_start函数。
    • _start函数会调用main函数,main函数结束后,由**_start函数来调用系统调用exit**结束,
    • 所以对于用户来说,不用在C程序代码里编写系统调用exit。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值