一个堆栈设置引发的血案, 顺便总结BSS, COMMON, DATA, TEXT等的知识

来源:互联网 发布:淘宝卖家申请直播条件 编辑:程序博客网 时间:2024/06/07 17:25

项目上, 上层发现call 驱动接口去得到usb插拔的g_hp_msg, 会得到非法的值. 由于我们驱动这边会有test case去测我们的接口, 却发现case没有问题.


分析过程:

这是个没有初始化的全局数组, 如果初始化的话, 就没这个问题.

这个的区别就是未初始化的变量放在COMMON段, 初始化的变量是放在bss段的.
分析map文件, 发现项目上COMMON段是最后的那个段, 和别的项目不一样, 别的项目是AV_section是最后的段.
怀疑是堆栈压到了这个COMMON段导致的.

证实过程:

这是个结构体数组, 把这个数组所有的成员的值都打印出来, 发现最后的那个成员中会有TaskStartStk

这个数组的地址(根据map查找得到). 而且在main函数的堆栈中显式的创建一个特殊的变量, 赋予特殊的值.
在dump这个g_hp_msg的数组的时候, 也会看到这个特殊的值.
所以很确定是堆栈的问题.

修改过程:

检查项目的map文件, 会发现_ap_stack_base和top是同一个地址.


COMMON         0x00000000804eea4c      0x200 D:\tmp\Lilac\config_prj\dvbc\concerto\lilac\kingvon\lilac_kingvon\lilac_kingvon\..\..\..\..\..\..\..\lib\lib_concerto\lib_usb.a(hotplug.o)

                0x00000000804eea4c                g_hp_msg_temp

 COMMON         0x00000000804eec4c       0x14 D:\tmp\Lilac\config_prj\dvbc\concerto\lilac\kingvon\lilac_kingvon\lilac_kingvon\..\..\..\..\..\..\..\lib\lib_concerto\libcore_jasmine.a(mt_ehci_concerto.o)

                0x00000000804eec4c                g_usb_psd_msg

 *(.COMMON_section)

                0x00000000804eec60                . = ALIGN (0x8)
                0x00000000804eec60                _freemem = .
                0x00000000804eec60                _ap_stack_base = .
                0x00000000804eec60                . = (. + 0x0)
                0x00000000804eec60                . = (. + 0x0)
                0x00000000804eec60                . = ALIGN (0x8)
                0x00000000804eec60                _ap_stack_top = .

                0x00000000804eec60                . = ALIGN (0x8)
                0x00000000804eec60                _end = .

去看lds文件, 发现base和top之间没有任何间隔
    _freemem = .;
    _ap_stack_base = .;
    . = . + 00000;   //这边应该有个数字, 表示stack的大小, 驱动的test case项目中, 这边是有值的
    .   =  ALIGN(8) ;    
    _ap_stack_top = .;

修改后, 问题解决. 正好顺便发现mips的堆栈是往地址小的方向生长的.


顺便总结一下TEXT, DATA, BSS, COMMON 之类的知识:


bss段:
BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。BSS段属于静态内存分配。
特点是:可读写,在系统启动时BSS段会一般都会自动清0。

data段:
数据段(datasegment)通常是指用来存放程序中已初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配。

text段:
代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。

rodata段:
只读数据区, 比如字符串常量和const修饰的变量等.

在诸如MIPS这样地址偏移量受限的RISC系统中,还有.sbss和.scommon区段,即小的BSS和公共块,有利于小的对象组合到单个可以直接寻址的区域(使用短指针(near)寻址)。

对于全局变量来说,如果初始化了不为0的值,那么该全局变量则被保存在data段,如果初始化的值为0,那么将其保存在bss段(不确定是不是一定这样),如果没有初始化,则将其保存在common段,等到链接时再将其放入到BSS段。关于第三点不同编译器行为会不同,有的编译器会把没有初始化的全局变量直接放到BSS段。在编译阶段,还可以通过-fno-common选项来禁止将未初始化的全局变量放入到common段。


关于BSS和COMMON的区别, 可以参考http://blog.chinaunix.net/uid-23629988-id-2888209.html

如果定义冲突, 但是BSS中是强符号, COMMON中是弱符号, GCC会用强符号覆盖弱符号.

0 0
原创粉丝点击