程序是如何生成和执行与终止

一、程序的生成

程序生成的基本过程就是编译,链接。

编译大体上也分三部分,预处理,编译,汇编,因为编译过程最复杂,所以这三步一般合起来叫编译。

先说预处理,预处理中可以宏定义,完成对文本的替换。预处理还可以检查头文件是否重复包含。通过预处理还可以选择性的编译。

编译(编译器就是完成编译动作的程序)就是把.c文件生成汇编代码,mov之类的指令,汇编就是把汇编代码生成可执行的机器可识别的命令。

编译后生成目标文件,就是以 .o结尾的文件,链接就是把生成的.o文件和库链接起来,连接后必须有一个main函数的入口。有一些大型的工程可以生成.o文件,这样修改调试代码的时候,没改动的部分就不用重新生成.o文件。有一些系统库,例如lib.a是编译器默认链接的,这个库包含一些常用的函数,例如printf()。有一些库是静态链接的,例如别人写的库,会直接把这个库的目标代码与其它代码合成可执行文件,调用速度快,但是生成的可执行文件较大。一些库是动态链接的,像dll文件,只有调用的时候才去系统中调用,不与可执行文件一起,这样速度会慢但是可执行文件小。

链接就是把目标代码,和各种库按照一定顺序,链接起来生成可执行文件。

二、可执行文件a.out

a.out文件和进程的内存布局是有区别的,这里特别说明下。a.out文件中有一些文件类型标识,包含符号表的段,包含调试信息的段,包含动态链接库链接表的段等,但是这些并不装载到进程执行的程序映像中。a.out中还包括最终的数据段,和文本段。并没有bss段,只记录这bss段的大小,这样可以优化a.out文件,使之空间大大减小。数据段包括初始化后的全局变量和静态变量。其它的如局部变量并不进入a.out它们在运行时创建。

三、执行时内存布局

程序执行的时候,操作系统把指令直接从文件拷贝到内存中(一般使用mmap()系统调用)。BSS段(可以理解成"better save space",实际上是是个一汇编运算符"block started by symbol")大小可以从a.out文件中读取,并被初始化为0。

程序的存储空间从低地址到高地址分别为正文段(由exec读入),初始化数据段(exec读入),未初始化数据段(由exec初始化为0),堆(由低向高增长),栈(由高向低增长),(堆和栈之间是大片的虚拟地址空间),最上面的是命令行参数和环境变量。

四、如何执行和退出

1.启动和退出

内核使程序执行的唯一方法是调用一个exec函数(exec函数并不创建新的进程,调用后进程ID不变,exec函数只是用一个全新的程序替换了当前进程的正文、数据段、堆和栈段。fork可以创建新进程,exec可以执行新程序),然后调用一个特殊的启动例程。可执行的程序文件将此启动例程指定为程序的起始地址(连接编辑器设置的),启动例程从内核取得命令行参数和环境变量,然后这个启动例程调用main函数。

进程自愿终止的唯一方法是显示或隐式的(通过调用exit,exit首先调用各种终止处理程序(由atexit函数注册),然后按需多次调用fclose,关闭所有打开的流,在调用_exit函数)调用_exit或_Exit返回给内核,进程也可以非自愿的由一个信号使其终止。只要进程中的调用了eixt,不管是调用子函数中调用的,还是在线程中调用的,进程都要终止,都会返回内核。而且不管进程是如何的结束都要执行一段相同的代码就是用来清理内存和释放文件描述符。

2.动态链接库

程序执行的时候,在main函数被调用之前,运行时载入器把共享的数据对象载入到进程的地址空间。外部函数被真正调用之前,运行时载入器并不解析它们。所以即使链接了函数,如果没有实际调用,也不会带来额外的开销。这里的链接分为动态链接和静态链接(静态链接库.a结尾),静态链接的时候,所需的库函数被装入到可执行文件中(并不是所有的,是所需要的),而动态链接的函数(动态链接库.so结尾(share object)),只有在运行的时候才被映射到进程中。

动态链接的最大好处是可以把程序与它们使用的特定的函数库版本分离开来,取而代之我们约定由系统向程序提供一个接口,该接口保持稳定。(和C++中的多态一样,核心思想都是接口复用!)这样软件升级的时候,不用重新编译和链接,从而节省大量的工作量。

虽然单个可执行文件的启动速度会受到影响,但是动态链接可以从以下两个方面来提高效率:1.生成的可执行文件小,能够节约磁盘空间和虚拟内存(内存使用大的时候会影响操作系统的整体速度)。2.所有动态链接到某个特定函数库的可执行文件在运行时共享该函数库的一个单独拷贝。操作系统内核保证映射到内存中的库函数可以被所有使用它们的进程共享。这样就提高了I/O和交换空间的利用率,节省了内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值