运行地址与加载地址估计大部分人没弄明白~
01
单片机存储分配
在玩单片机(以stm32为例)的时候会有RAM空间和ROM空间,RAM空间主要是用于数据的访问,而ROM空间用于存放烧录的固件,当然固件也可以直接加载到RAM中运行,只是说每次上电都需要重新加载。
02
简述分散加载
03
stm32启动流程
很多刚玩MCU的朋友,都会以main函数作为程序的开始运行处,不过几乎所有的C程序在执行前都会使用汇编指令,通过汇编指令构建C语言运行环境,并运行C程序,所以在C程序执行前做了非常多的工作,其中非常重要的就是堆栈指针的设置,这也是从汇编到C运行环境一定要做的一件事了。
那么stm32的启动大致流程是怎样的?这里小哥就简述一下:
04
uboot部署Linux
往往RAM分配的地址比较高,而整个程序往往都是0地址开始执行了的,如果让存储地址与运行地址相同来进行编译,会导致最终烧录文件非常之大,并且中间有一大片地址区域是无效的。
05
位置无关指令
所以位置无关就相当于相对路径,数据的访问、函数的调用几乎都是相对的,为什么说是几乎呢?因为有些情况下访问绝对地址也是与位置关系不大的,可以把这段程序放在可以执行的任何位置,所以位置无关码的运行与链接地址也没有直接的联系。
比如跳转指令B BL等这些跳转指令采用PC+偏移量,所以为位置无关指令;而如果我们采用ldr r0, =标记,而这些标记都是实际在链接过程中确定的运行地址,所以该指令为位置有关指令;并且全局变量基本上都是位置有关,而局部变量为位置无关;所以对于位置无关代码区域,跳转一般都使用B指令,而从位置无关代码区域跳转到位置有关指令代码区域去执行就需要借助位置有关跳转指令。
06
加载与运行地址不同
07
地址的设置
大部分ARM处理器其PC都是从0地址开始执行,所以在0地址处要么是运行程序,要么就是引导程序,如果没有这两样,你的程序烧录到其他位置均无法得到运行。
对于S3C2440芯片能够支持NorFlash和NandFlash启动,其中NorFlash上可以直接运行,而NandFlash启动由于其程序无法直接在上面运行,芯片会把内部SRAM作为0地址处,并且把NandFlash前4K代码拷贝到SRAM上运行。
因为这里最终想让所有的程序都在SDRAM里面运行,考虑使用全部重定位的办法,在链接脚本中确定好程序的存储地址和运行地址。
上图是GUN linker中截取的段描述格式,来源于:
http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html
具体详细解读大家可以参考上面的链接,下面看看几个常用的。
可执行文件由各个段组成,:
1、secname段名,一般使用数据段.data段,代码段.text段等等。
2、AT(ldadr)表示该段存储地址,也就是加载地址。
3、contents表示目标文件(比如.o目标文件)中的哪些段放在本段,也可以是整个目标文件全部放在这个段内。
4、start表示本段链接(或者称为运行)的地址,如果没有使用AT(ldadr),本段存储的地址也是start,也就是说存储地址与运行地址相等。
通过上面的段描述格式就可以在链接过程中确定好程序的运行地址和载入地址,以方便后续的重定位地址的使用。
下面以一个简单的实例说明一下:
1//....格式
2SECTIONS {
3...
4secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
5 { contents } >region :phdr =fill
6...
7}
8//.....示例
9SECTIONS {
10...
11.text 0x30000 : AT ( 0x0000 )
12 { *(.text) }
13
14.data 0x3FFFF : AT ( 0xFFFF )
15 { *(.data) }
16...
17}
这样固件的代码段的存储地址为0,数据段存储地址为0xFFFF,而运行地址分别为0x30000和0x3FFFF,最终重定位部分就根据这链接脚本中的符号获得相应地址,然后把相应的部分'搬运'到运行地址处运行处,比如如果载入地址在NandFlash上,那么重定位的过程中就需要初始化NandFlash控制器,然后读取NandFlash上的数据并'搬运'到运行地址处。
在嵌入式linux中很多时候这些地址都需要我们自己确认和设置的,不然Linux内核无法启动或者加载相应程序,而在单片机开发中用惯了IDE工具,所以大部分人涉及得不多~
enjoy~
素材源于:嵌入式情报局
。仅供技术的传播和学习讨论,如涉及作品版权问题,请联系我进行删除。
最后
推荐专辑 点击蓝色字体即可跳转
☞ MCU进阶专辑
☞ “bug说”专辑
☞ 专辑|手撕C语言
☞ 专辑|经验分享