【面经笔记】操作系统:编译过程

来源:互联网 发布:天天特价淘宝网毛衣 编辑:程序博客网 时间:2024/06/05 14:43

C++从源代码到可执行文件经过了哪些过程?

  • 预处理:

    将所有的#define删除,并且展开所有的宏定义
    处理预编译指令
    删除所有注释 “//”和”/* */”。
    添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
    保留所有的#pragma编译器指令,因为编译器需要使用它们。

  • 编译:

    编译过程就是把预处理完的文件生成相应汇编代码。

  • 汇编

    汇编器是将汇编代码转变成机器可以执行的命令,生成目标文件。每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单。

  • 链接

    通过调用链接器来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件


链接详细过程

链接分为静态链接动态链接

链接器的作用是分离编译,我们不需要将大型应用程序组织为巨大的源文件,可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。

链接器主要完成两个任务:

1 符号解析:将每个符号引用和符号的定义联系起来。

2 重定位:链接器生成地址从0开始的代码和数据节。把每个符号定义与一个存储位置联系起来,然后修改对符号的引用,使得它们指向这个存储位置。


符号解析:(解释static和extern)

每个可重定位目标模块m都有一个符号表:存放函数和变量的名称,地址,大小,类型等等。

不同模块或不用函数的static变量在链接过程中会被修饰为不同的符号名,编译器在.Data节(已初始化全局变量)和.bss节(未初始化全局变量)中为每个定义分配空间,并在符号表中创建一个有唯一名字的本地链接器符号。
在链接过程中,链接器上下文中有三种不同的符号:

  • 模块m定义的全局符号:非静态函数和非静态全局变量;

  • 模块m引用的其他模块定义的全局符号:extern等外部符号修饰的函数和变量; 交由链接器处理,在其他模块查找其定义。

  • 模块m定义和引用的本地符号:对于带static修饰的函数和全局变量。 编译器在.Data(已初始化全局变量)和.bss(未初始化全局变量)中为每个定义分配空间,并在符号表中创建一个有唯一名字的本地链接器符号

(符号表不包含对本地非静态局部变量的任何符号,这些符号在栈中被管理)


操作系统在运行一个程序背后会有哪些流程?

一个典型的程序的运行步骤大致如下:

1,操作系统创建进程(装载了),shell调用名为加载器的函数,它拷贝可执行文件中的代码和数据到存储器。然后将控制权交给程序的入口,即运行时库(CRT,C run-time library)的入口函数

(1)mainCRTStartup(或 wmainCRTStartup) //使用 /SUBSYSTEM:CONSOLE 的应用程序

(2)WinMainCRTStartup(或 wWinMainCRTStartup)//使用 /SUBSYSTEM:WINDOWS 的应用程序

(3)_DllMainCRTStartup //调用 DllMain(如果存在),DllMain 必须用 __stdcall 来定义

在默认情况下,如果你的程序中使用的是main()或_main()函数,这连接器会将你的使用(1)中的函数连接到你的exe中;如果你的函数是以WinWain()函数开始的则连接器使用(2)中的函数连接进exe中;如果我们写的是DLL程序这连接进DLL的是(3)中的函数。

http://tommy.blog.51cto.com/113624/1850755
http://blog.csdn.net/jofranks/article/details/8007267

2,入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造等等。

3,入口函数在完成这些初始化之后,调用main函数,正式开始执行程序的主体部分。

4,main函数执行完成后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用来结束进程。