请选择 进入手机版 | 继续访问电脑版

前馈科技

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4189|回复: 0

NuttX初始化为0的全局变量的存储

[复制链接]

97

主题

97

帖子

539

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
539
发表于 2020-3-13 14:01:27 | 显示全部楼层 |阅读模式
本帖最后由 feedforward 于 2020-3-13 14:02 编辑

近日在调试NuttX时遇到一个问题,当时的情况是:NuttX初始化时运行到注册/dev/null时进入devnull_register函数调用_inode_search函数执行到node = node->i_peer;语句时崩溃了。
21502137-9d86578fa2d7ee9e.png
事故地点


这要在命令行下调试就麻烦了,好在我有大杀器codeblocks!观察变量发现给指针node的值异常,而node是在_inode_search函数开始赋值为g_root_inode:
21502137-12f9d0a139f7b2ac.png
node指针的初始化


可是g_root_inode是一个申明时已经初始化为NULL的全局变量:
21502137-22fffc00f374309a.png
g_root_inode的初始化


观察System.map文件找到g_root_inode的地址,在程序运行的一开始设置断点并在codeblocks的内存观察窗口中观察:
21502137-1581f451e34606cc.png
g_root_inode在内存中的值


g_root_inode的值明显异常,竟然为0xeb2ccfeb,这明显超出SRAM的地址范围,必然会引发程序运行崩溃。继续观察System.map文件终于发现了点猫腻,g_root_inode竟然被分配在了.bss段:
21502137-461335b7ca8844ec.png
g_root_inode在内存中的位置


可是g_root_inode明明在申明时已经初始化过了啊,不是该分配到.data段吗?网上查询资料并查阅gcc手册才发现一个天大的公开秘密:gcc默认将出初始化为0的全局变量分配至.bss段以减小flash占用空间!GCC有一个[url=]special option[/url]控制这样的行为:
-fno-zero-initialized-in-bss
If the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS. This
can save space in the resulting code. This option turns off this
behavior because some programs explicitly rely on variables going to
the data section. E.g., so that the resulting executable can find the
beginning of that section and/or make assumptions based on that.
The default is:-fzero-initialized-in-bss.
于是乎通过sparc-gaisler-elf-gcc -v --help命令查询我所使用的sparc-gaisler-elf-gcc是否支持该命令:
21502137-822edc6493017eb8.png
sparc-gaisler-elf-gcc的bss段分配选项


出乎意料的时确实查询到了-fzero-initialized-in-bss,却没查到关闭该设置的选项-fno-zero-initialized-in-bss,姑且认为帮助信息里遗漏了该选项吧!直接在编译选项中加上该选项进行实验:
21502137-11e24ba5701b7441.png
设置-fno-zero-initialized-in-bss编译选项


重新编译后观察System.map文件发现g_root_inode变量果然被分配到.data段了:
21502137-3f9a84915fb921c5.png
g_root_inode被分配到.data段


看来-fno-zero-initialized-in-bss选项对sparc-gaisler-elf-gcc编译器同样适用。
问题虽然能解决,但这不是个好的解决方案,因为会占用过多的flash,而且有些不对劲,因为相关资料表明:.bss段在程序加载时由操作系统初始化(DSP裸机程序进入main函数前由_int00库函数初始化),而NuttX就是个操作系统,显然.bss应该由NuttX程序来初始化!看来是我少写了一段代码。参考NuttX的stm32的启动代码我才发现我问题所在,stm32的启动代码中有专门的代码来初始化.bss段:
21502137-c89f17f2069d986b.png
stm32的启动代码中.bss段的初始化


知道问题所在就好办了,参考stm32的启动代码在up_lowinit函数中添加.bss段初始化代码:
21502137-234a9a9e479eab27.png
在up_lowinit函数中添加.bss段初始化


之后去掉-fno-zero-initialized-in-bss选项重新编译以再次将g_root_inode分配至.bss段,编译后观察System.map文件如下:
21502137-7458d7c8e2298ea2.png
再次将g_root_inode分配至.bss段


在codeblocks中将nuttx.elf加载至SRAM中运行,在事故地点_inode_search函数中观察内存中g_root_inode的值:
21502137-10ef78d67b304d13.png
内存中g_root_inode的值


至此问题圆满解决!得出的两个经验:
1、gcc默认将初始化为0的全局变量分配至.bss段;
2、.bss段需要人工初始化;
3、可通过-fno-zero-initialized-in-bss选项将初始化为0的全局变量分配至.data段。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|计算机控制

GMT+8, 2024-3-28 17:49 , Processed in 0.056818 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表