一、程序是怎么被执行的
1.在程序中,由引导代码去调用程序中得main函数,而这个过程由链接器完成,链接器将引导代码链接到我们的应用程序构成可执行文件。
2.程序运行需要通过操作系统的加载器来实现,加载器是操作系统中的程序,当执行程序时,加载器负责将此应用程序加载内存中去执行。
3.如何向main函数传参?
argc 和 argv 传参是如何实现的呢?譬如./app arg1 arg2,这两个参数 arg1 和 arg2 是如何传递给应用程序的 main 函数的呢?
当在终端执行程序时,命令行参数(command-line argument)由 shell 进程逐一进行解析,shell 进程会将这些参数传递给加载器,加载器加载应用程序时会将其传递给应用程序引导代码,当引导程序调用 main()函数时,再由它最终传递给 main()函数,如此一来,在我们的应用程序当中便可以获取到命令行参数了。
二、程序是如何结束的
程序结束其实就是进程终止,程序结束可以分为正常和异常两种,且方式多样。例如
(1)通过程序结尾return语句返回来终止
(2)调用exit()或其他终止函数
(3) 异常终止有调用abort()函数和通过信号杀死进程
三、进程的基本概念
1.进程:进程就是一个可执行程序的实例。可执行程序就是一个可执行文件,所以可执行程序的实例就是可执行文件被运行。
进程是一个动态过程,而非静态文件,它是程序的一次运行过程,当应用程序被加载到内存中运行之后它就称为了一个进程,当程序运行结束后也就意味着进程终止,这就是进程的一个生命周期。
2.进程号:Linux 系统下的每一个进程都有一个进程号(processID,简称 PID),进程号是一个正数,用于唯一标识系统中的某一个进程。
查看进程号:ps -aux
3.进程的环境变量
- 每一个进程都有一组与其相关的环境变量,这些环境变量以字符串形式存储在一个字符串数组列表中,把这个数组称为环境列表。譬如在 shell 终端下可以使用 env 命令查看到 shell 进程的所有环境变量。
- 应用程序中也可以获取当前进程的环境变量。事实上,进程的环境变量是从其父进程中继承过来的,譬如在 shell 终端下执行一个应用程序,那么该进程的环境变量就是从其父进程(shell 进程)中继承过来的。新的进程在创建之前,会继承其父进程的环境变量副本。
4.进程的内存布局
在 Linux/x86-32 体系中进程内存布局
5.进程的虚拟地址空间
Linux 系统下,应用程序运行在一个虚拟地址空间中,所以程序中读写的内存地址对应也是虚拟地址,
并不是真正的物理地址。
为什么需要引入虚拟地址呢?
如果使用实际物理地址会出现诸多问题:
1.内存使用效率低
2.进程地址空间不隔离
3.无法确定程序的链接地址