编译链接运行原理---编译链接运行过程

一个.c/.cpp源程序文件要最后变成.exe(windows)或者.out(Linux)可执行文件,要经过编译和链接过程。

四个步骤:预编译,编译,汇编,连接

(一)预编译:处理以“#”开头的预编译指令,比如#include,#define等,规则如下:

(1)删除所有的#define,并展开所有的宏替换(文本替换);

(2)处理所有的条件预编译指令,如#if,#endif,#elif,#else,#ifdef;

(3)处理#include预编译指令,将被包含的文件插入到该预编译指令的位置,当一个头文件包含其他文件,则递归展开头文件;

(4)删除所有注释,“//”和“/**/”;

(5)添加行号和文件名标识,如#2 "hello.c" 2,便于编译时编译器产生调试用的行号信息,以及用于编译时产生编译错误或警告是能够显示行号;

(6)保留#pragma编译器指令,因为编译器需要使用。

(二)编译:把预处理完的文件进行一系列如下操作产生相应的汇编代码文件

(1)词法分析 :使用一种叫做lex的程序实现词法扫描,它会按照用户之前描述好的词法规则将输入的字符串分割成一个个记号。产生的记号一般分为:关键字、标识符、字面量(包含数字、字符串等)和特殊符号(运算符、等号等),然后他们放到对应的表中。

(2)语法分析 :语法分析器根据用户给定的语法规则,将词法分析产生的记号序列进行解析,然后将它们构成一棵语法树。对于不同的语言,只是其语法规则不一样。用于语法分析也有一个现成的工具,叫做:yacc。

(3)语义分析:根据上下文来推断

(4)代码优化;

(5)生成相应的汇编代码(指令)

(6)符号汇总

(三)汇编:将汇编代码转变为机器可执行的指令,生成可重定位的二进制目标文件

因为我们任何一个源文件在进行编译阶段的时候会去产生我们的符号表,符号表中存放的就是我们程序所产生的符号(例如:函数名,变量名等),我们的编译阶段是不会去给我们的符号分配正确的地址,因此当我们查看.obj(.o)文件的符号表信息时就会出现下面这种情况

可以发现符号的地址都是0x00000000,这些都是保留区地址,因此计算机无法通过正确的地址去寻找到它的指令,那么计算机就无法去执行,这也就是.obj(.o)文件没有链接为何不能执行的根本原因。

(四)链接:

(1)地址和空间分配

(2)合并各个段和符号表(调整段的偏移和段长度,合并.o文件的符号表)

(3)符号绑定:也被叫做符号绑定、名称绑定、名称决议、或者地址绑定,其实就是指用符号来去标识一个地址。

(4)符号重定位:重新计算各个目标的地址过程叫做重定位。

     扫描所有的输入的.o文件,去获得它们各个段的长度,属性和位置,然后按照段的属性和段的长度合并,并且去把每个.o文件的符号全部收集起来放入同一个符号表中。在这里要注意的是在链接的时候不光是要去链接我们用户自己所写编译后的.o文件还有一些库函数中的(例如:printf.o),同时还会去链接我们的glibc的辅助库函数。

链接分为两种:

静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大;

动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。

Linux操作系统中分步完成这些操作;

预编译:gcc  -E  main.c  -o  mian.i

编译:   gcc  -S  mian.i   -o  main.s

汇编:   gcc  -C  main.s  -o  main.o

链接:   gcc  -O  main  main.o

两步完成编译链接:

gcc -c main.c

gcc -o main main.o

一步完成:

gcc -o main main.c

(五)运行

                                            

(1)建立虚拟地址空间到物理内存的映射(创建映射结构体PCB)常见页目录,页表

(2)加载指令和数据

(3)入口地址写入下一行指令寄存器(PC寄存器)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值