KEIL MDK 分散加载的结构

KEIL MDK 分散加载的结构

1、我们先来解剖一只麻雀

    很多人会说我做项目时没用过分散加载啊,可能有些人甚至都不知道它的存在。事实上,开发环境会默认生成一个分散加载文件(或者叫链接器描述文件),你使用的可能就是这个默认的分散加载文件,先来看一下Keil默认生成的分散加载文件,使用LPC54608随便找了一个示例代码用Keil生成了一个,如下图所示:

    

    这个分散加载是keil自己生成的分散加载,可以说是最简单的分散加载,简单到RO、RW、ZI基本都是随意摆放的;里面红色字体的是各个段的起始地址以及大小,这些段的起始地址以及大小是由下图的红框框定的部分决定的,你可以把上图以及下面这张图合起来看,地址是一致的。

    

这个分散加载文件的基本意思如下图:

这里面Flash以及SRAM的地址以及大小都是可以修改的,其他的也可以修改,但起始地址以及大小都要在芯片真实存在的有效物理地址上,这部分需要参看芯片的用户手册里面的Memory MAP一节的内容,如下图就是LPC54608的Memory MAP,参看分散加载里面的地址,Flash以及SRAM的起始地址以及大小都落在有效的空间上了。如果你定义的Flash起始地址在0x40000000,那么肯定会出错,因为与AHB总线地址冲突了。

2、分散加载的基本结构

我们举个例子来说明分散加载文件的基本机构,如下:

LOAD_ROM_1 0x0000              【加载域描述】这段是要告诉链接器,你的程序是存在哪里?我从哪里去找需要执行的代码。
{                                                                        
    EXEC_ROM_1 0x0000           【运行域描述】这段是要告诉链接器,你的程序在哪里执行,在ARM Cortex-M系列的绝大多
    {                                                                    数MCU中加载域以及运行域是在同一个空间上的,即片内Flash。
        program1.o (+RO)            【输入节描述】就是告诉链接器,具体把哪一个以及怎么把这一个obj文件放到运行域里面
    }
    DRAM 0x18000 0x8000        【运行域描述】这里指的是RAM空间的运行域,下面会解释为什么这里会有两个运行域
    {
        program1.o (+RW,+ZI)     【输入节描述】告诉链接器,去哪里找执行程序是需要使用的变量以及数据
    }
}

LOAD_ROM_2 0x4000                【另一个加载域描述】同一个工程可以有多个加载域,就好像同一台电脑可以装几个操作系统
{
    EXEC_ROM_2 0x4000             【另一个运行域描述】
    {
        program2.o (+RO)             【另一个输入节】
    }
    SRAM 0x8000 0x8000            【另一个运行域描述】
    {
        program2.o (+RW,+ZI)      【另一个输入节】
    }
}
    其实Keil的官方帮助文档里面有官方的对分散加载的全面介绍与使用指导,但是里面的东西语言太官方了,搞了一大堆定义,然后又例子又很少,一大堆的专业术语,小编我最开始学这部分内容就是啃的这部分,真是想死的心情停不了啊~。好吧,下面我尽量多举例子,尽量少扯那些乱七八糟的术语,下面我们开始:

你可能会问,这个分散加载文件是用什么语言编写的?是一种脚本语言,不是C语言也不是汇编,所以分散加载不能调试,它是一种叫做BNF的东东,官方文档里面把这东西描述的极其神秘,反正我是没太看懂这个所谓的BNF到底是个啥东东(据说是一个符号推导语言之类的一般存在于各种专业论文里面用于装B的东西),但是经过多个工程的磨练,小编我也基本弄明白了这东西该怎么用了,至于理论层面我没有深究,这个东东貌似做分散加载的描述脚本有些大材小用了,它能做的事情远不止于此,当然其他的跟我们没关系啦。

    对于上面这个例子的几点说明:
     <1>分散加载的根本功能是指定程序在存储空间上面的存储分配以及运行空间的分配~,所有要有加载域和运行域来分别指定程序存储空间以及程序运行空间。一般来说程序的运行空间是在芯片的ROM类存储器里面,在Cortex-M里面基本就是芯片内部的Flash空间;
    <2>运行域就有意思了,由于MCU内部的Flash(几乎都是Nor-Flash)是可以运行代码的,但是不能用于变量也就是RW与ZI的加载,主要原因是变量需要经常修改,几个小时就可能连续改变几十万次,但是目前Flash工艺的写寿命介于10万次~100万次之间,如果把RW和ZI放在Flash上,那就是灾难,Flash会因为写次数的限制很快就会挂掉,而且Flash只能按块操作,开销太大,所以一般都是放到SRAM里面,所以你会看到在这个例子里面,运行域分成两个部分,RO数据段放在内部Flash里面,RW与ZI放到片内SRAM中去执行。这点与电脑是不同的,电脑的硬盘是完全不能执行程序的,所以如果你把电脑看成MCU的话,用Keil来编写程序的话,那么电脑的RO、RW、ZI段都是放到内存上执行的,也就是说电脑实际上只有一个执行域就在内存上,可以类似理解为MCU的片内SRAM上。其实很多市面上的A7、A8、A9、A53等内核的应用处理器运行Linux与Android也可以类比为电脑,所有的东西都要加载到RAM上运行。

<3>所以分散加载可以简单理解为的最基本结构就是至少3个域(这个事实上不对,但是对于大多数Cortex-M系列MCU的分散加载可以这样简单理解):至少一个加载域、建议两个运行域(一个RO运行域、一个RW+ZI运行域),就是你要告诉链接器至少3个信息,即:从哪里加载程序(至少一个域)、在哪里运行程序(至少一个域)、在哪里读写程序运行中用到的变量(至少一个域,实际上也可以跟运行程序的域在一起,但强烈建议分开)。如果你自己编写分散加载文件,先把这把这3个结构写出来,我们再来看之前的麻雀:

LR_IROM1就是【加载域】,指定了用户程序存储在0x00000000起始大小为0x80000的地址上,用户程序从这个区域内加载;

ER_IROM1就是【运行域】,是RO的运行域,因为LPC54608内部的Flash可以运行代码,所以用户代码可以从这个区域内运行;

RW_IRAM1就是【运行域】,是RW+ZI的运行域,这里指向的是片内SRAM的地址。

这样一解构,整个分散加载的基本结构就比较清晰了,下面我们再来看一个复杂一点的,同样的LPC54608的工程的分散加载

这个大家仔细看下这个结构,基本上上面所说的3个域结构的扩展。这里有几点不同的独特地方,我们解释下:

1、USB单独搞了两个运行域出来是干嘛的?

是这样的,USB由于要大量的数据吞吐,单独开辟一块SRAM作为数据BUFFER,所以你看到加载域2和加载域3的地址是在片内SRAM上,你可以对照一下上面的LPC5460的Memory MAP就会发现这两块地址是在片内SRAM上的。

2、分散加载还可以指定堆栈????

没错,确实可以,上面这个例子就在分散加载里面指定了堆栈其中:

ARM_LIB_HEAP域ARM_LIB_STACK是两个编译器之前就定义好的标号(Symbol),用于处理堆栈分配。当然堆栈也可以在启动代码里面指定分配,这是两种不同的方式,上面这个例子是在分散加载中指定堆栈。

关于分散加载,我们要讲的远不止于此,接下来,我们还会用几篇文档的篇幅来深入探讨这部分的技术。

(0)

相关推荐

  • 【连载】(堆栈和递归函数)乐创DIY C语言讲义——4.5节

    4.5 堆栈和递归函数 堆栈这个概念,最早学习微机原理的时候就学过,它表示的是一种在汇编语言调用子程序时候保存现场的存储空间,它所具有的数据结构属性就是先进后出,这个是我们之前学习计算机硬件时候讲述的 ...

  • KEIL MDK 分散加载的结构-2-语法

    KEIL MDK 分散加载的结构-2-语法 语法.枯燥的.烦人的语法--,但是有些时候木有办法,我本来也不想写这些东西,但确实绕不过去,我认为把它当成一种工具比较合适,了解大概结构以及基本的语法,一些 ...

  • KEIL MDK 分散加载示例2-代码加载到片内SRAM中运行&部分规则

    KEIL MDK 分散加载示例2-代码加载到片内SRAM中运行&部分规则 小编我一向主张在实战中学习,不主张直接去去学习规则&定义,太枯燥,在实际应用中去摸索,才会真正理解具体的技术细 ...

  • KEIL MDK 分散加载示例1-更改程序运行基址

    KEIL MDK 分散加载示例1-更改程序运行基址     小编我一向主张在实战中学习,不主张直接去去学习规则&定义,太枯燥,在实际应用中去摸索,才会真正理解具体的技术细节,下面我们就通过实际 ...

  • Keil sct分散加载文件

    首先介绍几个概念: 1.ARM映像文件 ARM映像文件是一个层次性结构的文件,其中包含了域(region).输出段(output section)和输入段(input section).各部分关系如下 ...

  • (转)KEIL下分散加载文件 **.sct文件

    在keil中编译的程序通过了,但是debug的时候会出现一些错误:*** error 65: access violation at 0x4C000018 : no 'write' permissio ...

  • ARM Cortex-M底层技术(十三)手把手教你写分散加载

    ARM Cortex-M底层技术(十三)手把手教你写分散加载 还记得之前教大家写的启动代码吗?木看过滴,出门左转,第四篇[编写自己的启动代码],当然仅仅能编写自己的启动代码怎么够,说了辣么多分散加载的 ...

  • 分散加载-堆栈与预处理器

    分散加载-堆栈与预处理器 在分散加载中处理堆栈: 分散加载机制提供了一种方法,用于指定如何在映像中放置代码和静态分配数据. 应用程序的堆栈和堆是在 C 库初始化过程中设置的. 通过使用特别命名的ARM ...

  • 分散加载原理的简单介绍

    分散加载原理的简单介绍     分散加载我自己在最初学习这部分内容的时候在网上找吐血了都没找到很靠谱的深入的文章,基本看之前不懂,看完了就更不懂了,后来只能硬着头皮自己慢慢摸索,也花了很多功夫,这里跟 ...

  • 关于显示加载动态链接库模块及卸载的问题

    问题起因是,在一次模块卸载后,程序运行异常.遂对动态链接库做一些测试. 动态库加载方式有两种,隐式加载和显示加载,隐式加载包含xxx.lib导入库,在程序执行之前由动态加载器完成所有加载:显示加载则使 ...