博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈编译过程和符号表重定位问题
阅读量:5079 次
发布时间:2019-06-12

本文共 1947 字,大约阅读时间需要 6 分钟。

对于代码的编译问题千头万绪从何说起呢,首先来说一下计算机是如何处理应用程序的,实质上应用程序是通过操作系统来应用机器指令操控硬件设施完成各种任务的,就从编译的环节开始谈起吧,众所周知,程序开发人员所写的代码实际上计算机是没有办法去认识的,那么就必须通过编译将其转换为计算机可以认识的机器指令,在有操作系统根据具体指令从硬件上分配内存处理程序段。以下从预编译,编译,汇编,链接,来简单的说一下程序的编译过程。

2.1编译预处理

在这个阶段主要是宏定义的展开,以及头文件的递归处理,即展开所有的以#开头的编译命令。

2.2编译阶段

将程序代码段按字符流格式进行切割,处理,主要是词法分析,语法分析,语义分析等阶段,编译完成后生成中间代码。

2.3汇编

将编译后的中间代码通过汇编器模块生成计算机能够识别的机器指令用以操控硬件设施生成目标代码(可重定位目标代码)。

2.4链接

通过链接器模块将各种目标代码以及库文件(*.lib文件),资源文件(*,rec)进行链接处理最终生成可以执行的*.exe文件。

2.5重定位问题

通过一个例子来看:假如我们有两个头文件和两个源文件分别叫做function1.h和function2.h以及function1.cpp和function2.cpp文件其中function1.h内容如下

 

Function1.h

#ifndef   _FUNCTION1_H

#define   _FUNCTION1_H

Int g_val;

Int Add(int m, int n);

#endif

 

Function1.cpp

g_val=10;

Int Add(int m, int n)

{

Return m+n;

}

Function2.cpp其中包含了main函数内容如下

#include “function1.h”

Int main()

{

Int  l_valfri=3;

Int  l_valsec=4;

g_val=14;

Int result=Add(l_valfri,l_valsec);

Return 0;

}

对于这样的代码编译器在编译function2.cpp时对于外部符号g_val 和外部函数Add该如何决议呢,这里又会涉及到可重定位文件中的符号表问题。

其实在可重定位目标文件之中会存在一个用来放置变量和其入口地址的符号表,当编译过程中能够找到该符号的定义时就将该符号入口地址更新到符号表中否则就对该符号的地址不做任何决议一直保留到链接阶段处理。通过两个例子来看符号表的结构。

在编译过程中function1.cpp文件的可重定位目标文件中的符号表如下

变量名

内存地址

g_val

0x100

Add

0x200

 

 

为什么可以做到对于符号g_val和Add分配内存地址呢,因为在编译阶段就能够在function1.cpp文件中找到他们的定义,所以能够进行明确的内存地址分配。

再来看看function2.cpp所生成的可重定位目标文件的结构:

变量名

内存地址

g_val

0x00

Add

0x00

为什么会出现这样的状况。因为在编译阶段虽然可以看到这些符号变量的声明,但却找不到他们的定义所以编译器陷入了一个决而未决的境地。

将包含文件展开时,function2.cpp大概会是这个样子很明显只有符号变量的声明但是没有定义。

#ifndef   _FUNCTION1_H

#define   _FUNCTION1_H

Int g_val;

Int Add(int m, int n);

#endif

 

 

Int main()

{

Int  l_valfri=3;

Int  l_valsec=4;

g_val=14;

Int result=Add(l_valfri,l_valsec);

Return 0;

}

 

先将他们存放在符号表中但却不去为他们进行内存关联一直等到链接阶段在进行处理。

重定位发生于目标代码链接阶段,在链接阶段链接器就会查找符号表,当他发现了function2.cpp的符号表之中任然有没有决议的内存地址时,链接器就会查找所有的目标代码文件,一直到他找到了function1.cpp所生成的目标代码文件符号表时发现了这些没有决议的符号变量的真正内存地址,这是function2.cpp所生成的目标代码文件就会更新它的符号表,将这些尚未决议的符号变量的内存地址写进其符号表中。

更新之后的function2.obj文件符号表

变量名

内存地址

g_val

0x100

Add

0x200

 

 

 

当所有的符号变量都能够找到合法的内存地址时,链接阶段重定位完成。

转载于:https://www.cnblogs.com/malc/p/5629610.html

你可能感兴趣的文章
活用深度链接实现拉新促活,打造自己的流量池
查看>>
java多线程
查看>>
【翻译】理解 LSTM 网络
查看>>
WPF学习笔记“命令”一:命令基础
查看>>
Javascript/15-1-14
查看>>
[C/C++基础--笔试突击] 1.数组
查看>>
C#高级知识点概要(2) - 线程和并发
查看>>
artdialog关闭弹出窗口
查看>>
为用户定义的数据类型绑定规则示例.sql
查看>>
FastDFS 4.05 发布,分布式文件系统
查看>>
一次基于innobackupex备份及binlog的单表恢复操作
查看>>
HTML响应代码
查看>>
Python基础语法——(引号、字符串、长字符串、原始字符串、Unicode)
查看>>
线段树区间合并(模板)
查看>>
小程序开发流程(java后端)
查看>>
CRM 2011 开发小结 REST查询 datetime类型和 OptionSetValue 类型
查看>>
win2008设置匿名共享
查看>>
(转)mysql command line client打不开(闪一下消失)的解决办法
查看>>
构建之法阅读笔记01
查看>>
转 几款常用的Git 图形化工具
查看>>