DSP芯片CMD文件中各段的实验验证(上)
2019-07-13 10:37发布
生成海报
上篇文章详细讲解了DSP中的CMD文件,请看:http://blog.csdn.net/qq_29545231/article/details/78175977《超详细的CMD文件讲解(DSP28035)》 。文中介绍了DSP中内存分配MEMORY以及内存存储段SECTIONS各自的功能和作用。
这节通过实验来论证上节中原理的正确性。主要是验证SECTIONS中各个段的存储及使用情况。
为了方便对照,首先把CMD文件贴出来,如下:
MEMORY
{
PAGE 0:
RAML0 : origin = 0x008000, length = 0x000800
RAML1 : origin = 0x008800, length = 0x000400
OTP : origin = 0x3D7800, length = 0x000400
FLASHH : origin = 0x3E8000, length = 0x002000
FLASHG : origin = 0x3EA000, length = 0x002000
FLASHF : origin = 0x3EC000, length = 0x002000
FLASHE : origin = 0x3EE000, length = 0x002000
FLASHD : origin = 0x3F0000, length = 0x002000
FLASHC : origin = 0x3F2000, length = 0x002000
FLASHA : origin = 0x3F6000, length = 0x001F80
CSM_RSVD : origin = 0x3F7F80, length = 0x000076
BEGIN : origin = 0x3F7FF6, length = 0x000002
CSM_PWL_P0 : origin = 0x3F7FF8, length = 0x000008
IQTABLES : origin = 0x3FE000, length = 0x000B50
IQTABLES2 : origin = 0x3FEB50, length = 0x00008C
IQTABLES3 : origin = 0x3FEBDC, length = 0x0000AA
ROM : origin = 0x3FF27C, length = 0x000D44
RESET : origin = 0x3FFFC0, length = 0x000002
VECTORS : origin = 0x3FFFC2, length = 0x00003E
PAGE 1 :
BOOT_RSVD : origin = 0x000000, length = 0x000050
RAMM0 : origin = 0x000050, length = 0x0003B0
RAMM1 : origin = 0x000400, length = 0x000400
RAML2 : origin = 0x008C00, length = 0x000400
RAML3 : origin = 0x009000, length = 0x001000
FLASHB : origin = 0x3F4000, length = 0x002000
}
SECTIONS
{
.cinit : > FLASHA PAGE = 0
.pinit : > FLASHA, PAGE = 0
.text : > FLASHA PAGE = 0
codestart : > BEGIN PAGE = 0
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
csmpasswds : > CSM_PWL_P0 PAGE = 0
csm_rsvd : > CSM_RSVD PAGE = 0
.stack : > RAMM0 PAGE = 1
.ebss : > RAML2 PAGE = 1
.esysmem : > RAML2 PAGE = 1
.econst : > FLASHA PAGE = 0
.switch : > FLASHA PAGE = 0
IQmath : > FLASHA PAGE = 0
IQmathTables : > IQTABLES, PAGE = 0, TYPE = NOLOAD
.reset : > RESET, PAGE = 0, TYPE = DSECT
vectors : > VECTORS PAGE = 0, TYPE = DSECT
}
1、先看.cinit、.bss和.ebss这三个段。.cinit是已初始化段,.bss和.ebss是未初始化段。
三个段存储内容如下:
.cinit 显式初始化的全局变量和静态变量表 代码
.bss 全局和静态变量 不超过64K长度
.ebss 长调用(far)的全局或静态变量 数据中的任何地方
.cinit: 全局变量和静态变量的C初始化记录,包含未用const声明的外部(extern)或静态(static)数据表。
.bss: 为全局变量和局部变量保留的空间,在程序上电时.cinit空间中的数据复制出来并存储在.bss空间中。
.ebss:为使用大寄存器模式时的全局变量和静态变量预留的空间,在程序上电时,cinit空间中的数据复制出来并存储在.ebss中,与.ebss不同的是.bss分配范围被限制在低64K 16位数据区,而.ebss的分配范围是4M 22位数据区
因为.bss和.ebss基本上是一样的,所以这里只验证.cinit和.ebss。
实验开始:
在main程序中定义未初始化的变量:全局变量global、全局静态变量g_static、局部静态变量local_static。
定义初始化的变量:全局变量g_init、全局静态变量g_static_init、局部静态变量local_static_init。
并把它们相应的存储位置标注在代码后面。
编译后,查看map文件,如下(注:为了方便分析,下面的map文件是经过裁剪的,后面的map都是一样。):
分析:
可以看到初始化全局变量g_init和未初始化全局变量global都在.ebss段中,地址是8c03和8c05。但是没有看到static变量。
在.cinit段中有存储0c个长度的变量,.ebss中有06个长度的变量,更奇怪的是下面的initialized data中显示是12,uninitialized data显示是6?这是为什么?
现在一个一个解答,从上面程序可以看到我们一共定义了6个变量,在前面已经说了.cinit是存放已初始化的变量的段,.ebss是存放未初始化变量的段,且程序上电后会自动把.cinit上的变量复制并存储到.ebss中。就是说.ebss应该有6个变量才对,所以上面的.ebss显示06,uninitialized data显示是6就很好理解了。
那.cinit段中有存储0c个长度的变量以及initialized data中显示是12怎么理解?
看看手册资料,如下:
原来.cinit段变量存储的情况是(3+n)word,即一个变量存储在.cinit中最少占用4个word。
程序中我们一共定义了3个已初始化的变量,也就是3*4 = 12,即0c。所以上面的疑问也得到解答了。
就是说.cinit中存放了3个变量,就是我们定义的那3个已初始化变量。
还有一个问题,如何查看static变量呢?在map文件中无法显示static变量,我们转到程序仿真上查看变量的地址。如下图
可以看到程序所定义的static变量都存放在0x00008c00开始的地址上,而这个地址就是.ebss的起始地址。
现在我们来验证外部(extern)变量或外部静态(static)变量是不是也是存放在.cinit段中的。
在main程序中,访问3个extern变量。如下:
新建test.c文件并定义一个初始化全局变量extern_g、一个初始化静态全局变量extern_static_g,
一个子函数void test(void),函数内定义一个初始化局部静态变量extern_func_v。
编译程序时出错,如下。说main文件中有2个变量extern_func_v,extern_static_g未定义。
把main文件的第8行和第9行代码注消。重新编译程序。编译通过了。
细心的人可能注意到了,刚才在main程序中对test.c中的3个变量进行访问,其中报错的是两个static变量,而变量extern_g却没报错,能够通过编译。
这说明了:被static修饰的变量,只限于当前文件或函数访问,外部文件或外部函数是不能够访问的。
现在,来看一下map文件。参考上面的分析,从红 {MOD}框出的部分可以得出结论。
接下来仿真调试程序,单步运行程序,结果如下,extern_g的值被修改为10了。说明在main文件中是可以访问test.c文件的全局变量extern_g的。
同时也看到了两个static变量的地址都是在08c00上的。
结论:
.cinit存放的是已经初始化的全局变量和已经初始化的static变量(变量表)。程序上电后会复制并存储到.ebss或.bss中。(相当于下图的.data)
.ebss或.bss存放的是未初始化的全局变量和static变量(变量表)。(相当于下图的.bss)
程序、变量的一般存储方式图:
2、验证.text段存储的是可执行代码和常数
在main文件上调用了两个函数,如下:
编译后查看map文件,可以看到main函数和test函数都是存放在.text段上的。
3、验证.stack段
我们都知道局部变量都是放在栈上的。所以在main文件的test函数内定义一个局部变量。并观察变量的存储位置。如下图:
因为.stack上的变量在map文件是无法体现的,需要运行程序后变量才会存在。
编译并运行程序后,如下图,可以看到i变量是存放在0x00000057的地址上的。而从上面的CMD文件可以看到
RAMM0 : origin = 0x000050, length = 0x0003B0
.stack : > RAMM0 PAGE = 1
也就是说i变量是存放在.stack段上的。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮