淘宝网站建设目标是什么意思,平面设计的图,建站小程序,线上兼职的正规网站本文为【单片机步入嵌入式Linux】系列文章的第二篇#xff0c;主要是跟大家讲解一下链接过程中几个地址的区分与理解~1 单片机存储分配在玩单片机(以stm32为例)的时候会有RAM空间和ROM空间#xff0c;RAM空间主要是用于数据的访问#xff0c;而ROM空间用于存放烧录的固件主要是跟大家讲解一下链接过程中几个地址的区分与理解~1 单片机存储分配在玩单片机(以stm32为例)的时候会有RAM空间和ROM空间RAM空间主要是用于数据的访问而ROM空间用于存放烧录的固件当然固件也可以直接加载到RAM中运行只是说每次上电都需要重新加载。如上图所示ROM为FLASH地址而RAM为SRAM地址毋庸置疑生成的单片机固件会烧录到Flash上这样才能保证每次上电都有可以正常运行。对于很多初学者该有疑问了明明全局变量等等都是分配到RAM上的呀怎么说固件放到Flash上的呢其实并不矛盾程序指令中访问变量都是访问变量的地址也就是内存的地址所谓的分配到RAM上仅仅只是说相应的变量占据了对应的RAM地址并不能理解为这个变量存在于RAM里面。可能你还会继续问 : 暂且认同上面的说法那对这些变量的初值该如何解释呢可以肯定的是这些全局变量的初值并不是来源于RAM因为RAM掉完电以后数据就丢失了而在程序正常运行过程中不管怎么上下电其初值都是我们程序中规定的也就是在编译中确定的。所以这些初值要保存只可能存在ROM中这中间肯定有这样一种机制 : 在上电以后把ROM中存储的这些变量初值来重新初始化到对应的RAM地址以便后续程序指令访问这种机制通常叫分散加载。2 简述分散加载上图是一种简单的分散加载机制映像文件由不同的段组成通常都有代码段.text、已初始化数据段.data、未初始化及初始化为0的数据段.bss等等而且他们具有不同的属性RORWZI等等。为了便于大家理解整个系统的存储区分为ROM和SRAM左边Load View表示的是程序存储地址空间分布情况也就是程序烧录到ROM以后的空间分配情况。固件烧录到ROM区域并且分为RW区和RO区RW区域为可读可写区域而RO区域为只读区分这两个区域并不是说RW区域存储地址区域以后就用来数据的读写而是为了上电过程中的copy/decompress(复制或者解压)过程做好标记这个过程会把一些非零全局变量(或者静态变量等)的SRAM地址(实际的运行地址)处赋予初始值。ZI区域是零填充区域主要是.bss段的一些初始化为0或者未初始化的全局或者静态变量分布区域这些数据没有必要保存到固件中所以由加载机制自行清零即可。一切准备就绪就形成了右侧的execution View的运行空间视野由于ROM中程序运行所涉及到的全局变量等的访问都是SRAM地址的访问而这些地址恰好在程序编译链接过程中已经分配到SRAM里面经过前面的该部分地址的重新定位运行空间的程序就可以正确访问到这些变量的初值等等。3 stm32启动流程很多刚玩MCU的朋友都会以main函数作为程序的开始运行处不过几乎所有的C程序在执行前都会使用汇编指令通过汇编指令构建C语言运行环境并运行C程序所以在C程序执行前做了非常多的工作其中非常重要的就是堆栈指针的设置这也是从汇编到C运行环境一定要做的一件事了。那么stm32的启动大致流程是怎样的这里小哥就简述一下:当然还有一些小细节这里就不展开了stm32的Flash可以直接运行程序采用分散加载只需要把相应的数据区域加载到运行地址处便可以正常的访问这个与前面的所说是类似的。4 uboot部署Linux在进行Linux系统开发过程中一切从Bootloader开始而bootloader本质上就是一个单任务的裸机程序和单片机程序是一样的而在众多bootloader中最为常用和广泛的就是uboot了他就是为了部署Linux环境而生的下载、烧录、运行Linux映像、文件系统等等。uboot都可以搞定所以它对地址是非常敏感的程序、参数等等应该存储在什么地址在什么地方运行都是需要确定好的而这些地址在编译链接的过程中链接脚本已经确定好了这一切uboot的工作就是把这些固件放在编译链接所规定的运行地址处进行运行即可。比如全局变量在什么地址函数在什么地址当程序运行的过程中就会从这些确切的地址处取数据如果你把全局函数指针变量的地址分配到了NANDFlash上那么程序在访问的过程中就有可能跑飞。程序运行最重要的两个地址加载地址和运行地址。加载地址也常被大家成为存储地址即实际固件存储的位置其实该地址也只是一个相对的概念就相当于单片机中bin文件烧录在什么位置一样的道理。运行地址也叫链接地址即程序的绝对地址。全局变量等等都是以该地址为基础来确定程序的运行状态的各部分的地址布局。当然Linux以上各部分直接烧写到RAM也是也可以直接运行的不过还是那个问题一旦掉电则全部丢失所以最终每个部分都会写入到Flash上(当然在前期调试的时候可以直接下载到RAM中减少对Flash的反复擦写)但对于大部分Flash都是无法直接运行程序的即使能够运行比如Norflash也是非常的慢且不能够直接写入所以Linux内核等都会加载到RAM来运行以获得更快的执行速度那么前面介绍的那种单片机方式只重定位数据段的方式不太适用了。在嵌入式Linux平台上首先执行的就是bootloader,而它只是一个顺序执行的程序它有一个重要的工作就是把Linux内核搬运到RAM中运行由于我们的内核兼容不同的单板uboot也会传递给内核一些配置参数以配置内核。往往RAM分配的地址比较高而整个程序往往都是0地址开始执行了的如果让存储地址与运行地址相同来进行编译会导致最终烧录文件非常之大并且中间有一大片地址区域是无效的。那么有什么办法来解决这个无效区域以缩小我们的固件大小呢先了解下位置无关指令。5 位置无关指令既然有位置无关指令就有位置有关指令简单的说所执行的指令是不是与位置相关才能达到目的。可以类比与绝对路径与相对路径相对路径你可以把程序放在任何文件夹下面编辑器均可以根据工程文件路径找到其他每一个文件而绝对路径却不行一旦文件夹换了基本上就是定位不到具体的每个文件了。所以位置无关就相当于相对路径数据的访问、函数的调用几乎都是相对的为什么说是几乎呢因为有些情况下访问绝对地址也是与位置关系不大的可以把这段程序放在可以执行的任何位置所以位置无关码的运行与链接地址也没有直接的联系。比如跳转指令B BL等这些跳转指令采用PC偏移量所以为位置无关指令而如果我们采用ldr r0, 标记而这些标记都是实际在链接过程中确定的运行地址所以该指令为位置有关指令并且全局变量基本上都是位置有关而局部变量为位置无关所以对于位置无关代码区域跳转一般都使用B指令而从位置无关代码区域跳转到位置有关指令代码区域去执行就需要借助位置有关跳转指令。6 加载与运行地址不同当存储地址与链接地址不同时多数情况下由于采用位置有关指令会出问题最常见的就是PC指针取的绝对地址而此时该绝对地址处无存储导致程序飞掉。既然有了位置无关的程序那么我们就可以把其当作一个搬运工放在位置有关部分的后面一旦需要运行位置有关码那么就会通过位置无关码把有关部分拷贝到运行地址处然后跳转执行即可这样整个的程序就可以做得非常的连续且中间几乎没有无效区域该搬运的过程就是常说的重定位。 7 地址的设置大部分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、ATldadr表示该段存储地址也就是加载地址。3、contents表示目标文件(比如.o目标文件)中的哪些段放在本段也可以是整个目标文件全部放在这个段内。4、start表示本段链接或者称为运行的地址如果没有使用ATldadr本段存储的地址也是start也就是说存储地址与运行地址相等。通过上面的段描述格式就可以在链接过程中确定好程序的运行地址和载入地址以方便后续的重定位地址的使用。下面以一个简单的实例说明一下: 1//....格式2SECTIONS {3...4secname start BLOCK(align) (NOLOAD) : AT ( ldadr )5 { contents } region :phdr fill6...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~素材源于:嵌入式情报局版权归原作者所有。仅供技术的传播和学习讨论如涉及作品版权问题请联系我进行删除。推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈