编译过程中的链接地址对最终编译镜像文件的影响

MDK和交叉编译工具编译时都会指定程序的下载的地址(其实就是告诉程序它将在那个地址上开始执行),这有什么意义吗?

  其实这么设计有原因的,因为这里涉及到全局变量和全局函数指针的地址问题,加入当你在编译时指定编译器这段程序会在0x0c000000地址上运行,因此全局变量和全局函数指针就会从0x0c000000上开始分配地址,此时如果你把这段程序烧录到0x0c000000地址上运行,变量的访问和指令存取不会有人任何问题,但是如果你将程序下载到0x00000000上运行时,在程序会在访问全局变量时,实际上这个变量地址分配的地址是0x00000001但是,因为你编译是连接地址不是0x00000000所以程序会到0x0c000001去读取这个变量,此时就会读到一个错误的值。对于函数指针也是相同的道理,但此时指令就跑飞了。

ARM处理器上的用处(相对跳转和绝对跳转)

绝对跳转:就是执行了这一条指令之后就会跳转到绝对跳转的指令中的地址去执行。
相对跳转:从当前地址偏移一定的偏移地址去执行一个程序。
将被编译到0xC0000000地址的代码放到0x00000000地址开始执行,如果它们只使用顺序执行或者相对跳转执行方式就可以正常运行(未使用全局变量和全局函数指针),但如果使用了绝对寻址,那么程序就跑飞了。
我们参照下面这段伪代码来说明这个情况。

指令编号
指令功能
指令1 :顺序执行
指令2 :顺序执行
指令3 :相对跳转到指令5
指令4 :顺序执行
指令5 :顺序执行
指令6 :绝对跳转到指令8
指令7 :顺序执行
指令8 :顺序执行

在编译、链接的时候,这段程序被告知放在0xC0000000地址空间,编译后烧录到0x00000000结果在存储设备中的存放结果为(每条指令以4字节计算):

指令地址        指令编号    指令功能            下条指令地址

0x00000000     指令1:    顺序执行            当前地址+4
0x00000004     指令2:    顺序执行            当前地址+4
0x00000008     指令3:    相对跳转到指令5      当前地址+8
0x0000000C     指令4:    顺序执行            当前地址+4
0x00000010     指令5:    顺序执行            当前地址+4
0x00000014     指令6:    绝对跳转到指令8      0xC000001C
0x00000018     指令7:    顺序执行            当前地址+4
0x0000001C     指令8:    顺序执行            当前地址+4      

程序从0x00000000开始运行直到第五条指令都是不会出错的,但是当执行完指令6后程序就会跑飞了,因为指令6是一条绝对跳转的指令但0xC000001C空间没有代码,这样程序就跑飞了。但当这段程序被放在0xC0000000起始空间时,开始执行指令1,然后采用相对寻址的方法就可以运行到指令6,在指令6执行时执行绝对寻址的方法从0xC0000014正确跳转到指令8所在的0xC000001C位置,这段代码运行正常。(参考博客:http://blog.sina.com.cn/s/blog_908da74601011bg6.html)

如图:

MDK编译后的STM32工程 map文件简单分析

只看map文件中有用的部分:

Code为程序代码部分
RO-data 表示 程序定义的常量const temp;
RW-data 表示 已初始化的全局变量
ZI-data 表示 未初始化的全局变量

Program Size: Code="18248" RO-data=320 RW-data=260 ZI-data=3952

Code, RO-data,RW-data ............flash
RW-data, ZIdata...................RAM (内存)

存储Size:

RO size: Code + RO_data

RW size: RW_data + ZI_data

ROM (minimum)size = Code + RO_data + RW_data (即烧/下载程序到FLASH/ROM时,所占用的最小空间)

Total ROM Size (Code + RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。为什么Rom中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在Rom中的,为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。

RAM size: RW Data + ZI Data (即程序运行的时,RAM使用的空间)

一个ARM程序包含3部分:RO段,RW段和ZI段
RO是程序中的指令和常量
RW是程序中的已初始化变量
ZI是程序中的零初始化的变量
由以上3点说明可以理解为:
RO就是readonly,
RW就是read/write,
ZI就是zero

完事,今天好冷哎!

原文地址:https://www.cnblogs.com/w-smile/p/10073790.html

时间: 2024-08-30 05:09:30

编译过程中的链接地址对最终编译镜像文件的影响的相关文章

编译过程中,termcap.h 文件找不到路径 licli.a终于生成

编译过程中,termcap.h      文件找不到路径 查看是linux  源码下找不到termcap.h文件 安装了所有关于*cap*的源码包也不起作用 今天终于解决了这个问题,搜termcap.h  发现一篇文章,如下 ----------------------------------------------------------------------------------------- 安装minicom2.3出现termcap.h错误解决方法 2010-05-06 17:12:

CUDA程序编译过程中产生警告的解决方法

有时候经常使用别人用Tabhost+其它的实现demo.单纯利用Tabhost该如何使用呢? 下面看例子: public class MainActivity extends TabActivity { public TabHost tabHost; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取对象 tabHost = getTabH

PHP编译过程中常见错误信息的解决方法

PHP编译过程中常见错误信息的解决方 checking for BZip2 support- yes checking for BZip2 in default path- not found configure: error: Please reinstall the BZip2 distribution Fix: yum install bzip2-devel checking for cURL support- yes checking if we should use cURL for

LAMP系列之PHP编译过程中常见错误信息的解决方法

LAMP系列之PHP编译过程中常见错误信息的解决方法 在CentOS编译PHP5的时候有时会遇到以下的一些错误信息,基本上都可以通过yum安装相应的库来解决.以下是具体的一些解决办法: ******************************************************************************* checking for BZip2 support- yes checking  for BZip2 in default path- not foun

关于s5pv210的配置、编译过程中相关文件的分析(Makefile、config.mk、mkconfig)

uboot为用户提供两种编译方式,一种是在uboot当前目录下进行编译,第二种方式就是将编译生成的文件输出到指定的目录下. 1) Add O= to the make command line # 'make O=/tmp/build all' # # 2) Set environement variable BUILD_DIR to point to the desired location # 'export BUILD_DIR=/tmp/build' # 'make' # # The se

nginx源码编译以及源码编译过程中遇到的问题

原帖地址:https://www.cnblogs.com/operationhome/p/8964191.html 本文主要讲nginx安装以及安装过程中遇到的问题. 谈到nginx 必须聊聊它的起源和发展. nginx是由俄罗斯工程师Igor Sysoev 用C语言开发的一个免费开源的Web服务器软件,于2004年发布,聚集轻量级.高并发.高性能.低消耗等一系列优点.目前Nginx是互联网上仅次于Apache的第二流行的Web服务器软件. 接下来我们开始安装nginx,我们下面是以centos

深入研究:对变量以及指针重新赋值过程中原本的地址是否会改变。(按值传递机制的深入)

在研究按值传递机制时,发现一些模糊的概念.就是在对一个原本的(指针)变量重新给定另外一个值时,会不会改变这个变量原本所在的内存位置(即地址).因此,决定深入研究一下.而且这也是必要的. 给一个变量重新赋值时,地址的变化 1 //验证变量在被赋值(以及被重赋值)时原本分配的内存地址是否会改变. 2 3 #include <stdio.h> 4 5 int main(void) 6 { 7 int a;//声明a,即已经给a分配一个内存地址 8 printf("声明a时的地址:%p\n&

rgbdslam_v2编译过程中引起的needed by错误

Ubuntu16.04,ROS kinectic 报错信息为" make[2]: *** No rule to make target '/home/william/slam/g2o/lib/libg2o_csparse_extension.so', needed by '/home/william/catkin_ws/devel/lib/rgbdslam/rgbdslam'. Stop.CMakeFiles/Makefile2:5881: recipe for target 'rgbdslam

Jenkins编译过程中出现ERROR_ Failed to parse POMs错误

一.在使用jenkins编写过程中突然出现以下问题 Parsing POMs Established TCP socket on 59407 [java] $ java -cp /var/lib/jenkins/plugins/maven-plugin/WEB-INF/lib/maven35-agent-1.12-alpha-1.jar:/usr/local/apache-maven-3.5.4/boot/plexus-classworlds-2.5.2.jar:/usr/local/apach