编译链接原理

32位计算机虚拟地址空间与程序运行原理

虚拟地址空间

      32位计算机,每个程序都有4G的虚拟地址空间。首先虚拟地址空间分为两大块,一个是用户空间,一个是内核空间。用户空间占3G的大小,并且它是每个进程所独有的,它的开头128M存放的是我们无法访问的地方。

.text:C语言的编译后执行语句都编译成机器代码,保存在.text段;

.data:已初始化的全局变量和局部静态变量都保存在.data段;

.bss:为未初始化的全局变量和局部静态变量预留值;

.堆:堆内存是我们在c语言中用malloc申请或者在c++中用new来申请的一端可能不连续的内存,堆是由低地址向高地址申请的。

.栈:栈中存放我们的局部变量,特性是先进后出,并且它是由系统自动开辟以及释放。并且内存是连续的,栈是高地址向低地址扩展的连续内存,栈的大小一般是2M。

编译(生成可重定位的二进制文件)

.c/.cpp文件首先会进行预编译,完成后生成(.i文件):

具体内容:

(1)、#indefine宏定义替换

(2)、#include展开头文件(递归)

(3)、#if #endif 删除预编译指令

(4)、删除注释/*…*/

(5)、添加行号文件标识

(6)、保留#progma

在预编译完成之后,进行编译,完成后生成(.s文件):

具体内容:

(1)、词法分析

(2)、语法分析

(3)、语义分析

(4)、代码优化(生成指令代码,汇编代码)

在编译完成之后,进行汇编,完成后生成(.o)文件

具体内容:

(1)、指令代码转化成二进制(可重定位的二进制文件)

链接(生成可执行文件)

具体内容:将有关的目标文件彼此链接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义链接起来,是的所有的这些文件成为一个能够让操作系统装入执行的统一整体,可分为动态链接和静态链接,

(1)、合并段和符号表

(2)、符号解析

(3)、分配地址和空间

(4)、符号的重定位

强弱符号:

强符号:已初始化的全局变量;

弱符号:未初始化的全局变量;

强弱符号的规则:

1、两个强符号,重定义

2、一个强符号一个弱符号,选强符号

3、两个弱符号,选字节长的

程序运行原理:

1、创建虚拟地址空间和物理内存的映射。

2、加载指令和数据。

3、第一行指令的地址写入PC寄存器。

 

 

 

 

代码编译链接是将高级语言代码转换为可执行程序的重要过程,下面详细介绍其原理: ### 编译原理 编译是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后产生相应的汇编代码文件的过程,是构建整个程序的核心且复杂的部分。在编译阶段,编译器会对源代码进行逐行扫描,识别其中的词法单元,检查语法是否正确,分析代码的语义,并进行优化,最后生成汇编代码。例如在程序模块`main.c`中使用`func.c`模块中的函数`foo()`,编译编译`main.c`时因每个模块单独编译,不知道`foo`的函数地址,所以暂时搁置调用`foo()`指令的目标地址,等待链接时由链接器修正,这种地址修正过程称为“重定位(relocation)”,要修正的地方称为“重定位入口” [^3]。 ### 链接原理 链接编译过程中的重要阶段,负责将多个目标文件合并成一个可执行文件或库文件。其主要作用是处理各个模块之间互相引用的部分,使各个模块能正确相互衔接 [^1][^2]。 链接步骤如下: 1. **段合并**:将所有目标文件的各个段进行合并,如`main.o`的`.text`段和`sum.o`的`.text`段合并,`main.o`的`.data`段和`sum.o`的`.data`段合并,`main.o`的`.bss`和`sum.o`的`.bss`段合并 [^4]。 2. **符号解析**:合并后进行符号解析,对于链接阶段符号为`UND`(符号引用)的,都需要找到该符号定义的地方。若没找到则为符号未定义,找到多个定义则为符号重定义,找到定义后将其解析成具体的`.text`、`.data`等段 [^4]。 在链接过程中,还涉及强弱符号规则。例如在编译阶段,未初始化的变量是弱符号,汇编后暂时存放在`*COM*`模块中,不确定其他文件中强符号的位置。在链接阶段根据强弱符号规则,确定该符号是放在`.bss`段还是放在`*COM*`模块中 [^5]。 ### 示例代码说明 假设存在两个文件`main.c`和`func.c`: ```c // main.c #include <stdio.h> extern void foo(); int main() { foo(); return 0; } // func.c #include <stdio.h> void foo() { printf("Hello from foo!\n"); } ``` 编译`main.c`和`func.c`会分别生成`main.o`和`func.o`目标文件,编译`main.c`时,编译器不知道`foo()`的地址,会搁置调用`foo()`指令的目标地址。链接时,链接器将`main.o`和`func.o`合并,进行段合并和符号解析,找到`foo()`的定义并修正`main.o`中调用`foo()`指令的目标地址,最终生成可执行文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值