SECTIONS bss段初始化分析

发布时间:2022-06-27 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了SECTIONS bss段初始化分析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

SECTIONS bss段初始化分析

都知道bss段需要初始化,但是这是为什么呢?

 通过浏览资料,都会发现,bss段是不会出现在程序下载文件(*.bin *.hex)中的,因为全都是0。如果把出现在程序下载文件中,会增加程序下载文件的大小。实际应用中,通常只需要把bss段的起始地址和结束地址保存起来,而不需要将程序下载文件中出现bss段(一堆0)将来真正运行程序的时候,再根据这两个数据进行bss段的初始化就行了。

       以上这段文字是网上的资料说的。但是,可不可以让bss段出现在程序下载文件中呢?如果这样可以的话,当程序由存储器(例如nandflash)拷贝到内存中时,捎带着会把bss段像data段那样初始化。

       实际上是可以这样做的。看下边的两个链接脚本。

链接脚本一:

SECTIONS {     . = 0x00000000;     .init : AT(0){ head.o init.o nand.o}     . = 0x30000000;     .text : AT(4096) { *(.text) }     .rodata ALIGN(4) : AT((LOADADDR(.text)+SIZEOF(.text)+3)&~(0x03)) {*(.rodata*)}      .data ALIGN(4)   : AT((LOADADDR(.rodata)+SIZEOF(.rodata)+3)&~(0x03)) { *(.data) }     __bss_start = .;     .bss ALIGN(4)  : { *(.bss)  *(COMMON) }     __bss_end = .; }

链接脚本二:

SECTIONS {     . = 0x00000000;     .init : AT(0){ head.o init.o nand.o}     . = 0x30000000;     .text : AT(4096) { *(.text) }     .rodata ALIGN(4) : AT((LOADADDR(.text)+SIZEOF(.text)+3)&~(0x03)) {*(.rodata*)}      .bss ALIGN(4)  : AT((LOADADDR(.rodata)+SIZEOF(.rodata)+3)&~(0x03)){ *(.bss) }     .data ALIGN(4) : AT((LOADADDR(.bss)+SIZEOF(.bss)+3)&~(0x03)) { *(.data) } }

链接脚本一,把bss段放在最后边,arm-linux-gcc编译器默认的会把bss段给忽略掉,也即不会让bss段出现在程序下载文件中(可以通过Jlink软件查看编译后的bin文件)。这种链接脚本也是通常见到的方式。

链接脚本二,把bss段放在了rodata段和data段中间,这个时候,arm-linux-gcc编译器并不会把bss段在程序下载文件中删除,也即会把bss段保留下来,最终出现在程序下载文件中。考虑原因可能是这样的:编译后的地址rodata段、bss段、data段是连续的,也即程序运行时这几个段是连续的;倘若把bss段在程序下载文件中删除,那么程序下载文件中rodata段后边紧接着的是data段;这就要求程序的这两个段需要分别处理,而不能一次性将连续拷贝过去。

链接脚本二的方法可以让bss段出现在程序下载文件中。但是,通常都不会这样做,这里之所以这样深钻,只不过是在探究bss段初始化的必要性。通常采用的链接脚本一,由于最终程序下载文件中没有bss段,所以必须在应用程序运行前,根据bss段的起始地址和结束地址将bss段初始化。

下边,着重讲一下链接脚本中与初始化bss段相关的几句话。

    (1) __bss_start = .;     (2).bss ALIGN(4)  : { *(.bss)  *(COMMON) }     (3)__bss_end = .;

实际上句(1)是在bss段的起始地址处定义了一个int类型的全局变量__bss_start。虽然,bss段的起始地址处肯定是一个未初始化的全局变量,但是这里算是编译器又在这个位置上又重新定义了一个全局变量。就是说,一个地址有两个名字,都能访问这个地址空间。句(3)的解释同句(1)。

    接着再看一下用C语言写的初始化bss段的程序。

 (1)void clean_bss(void) (2){ (3)   extern int __bss_start, __bss_end; (4)   int *p = &__bss_start; (5)  (6)   for (; p < &__bss_end; p++) (7)     *p = 0; (8)}

首先,句(3)对编译器产生的两个全局变量进行声明。句(4)通过__bss_start取出bss段的起始地址,句(6)通过__bss_end取出bss段的结束地址。

 

参考链接:

https://www.cnblogs.com/amanlikethis/p/3384743.html

脚本宝典总结

以上是脚本宝典为你收集整理的SECTIONS bss段初始化分析全部内容,希望文章能够帮你解决SECTIONS bss段初始化分析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: