数据段,BSS段的内存初始化问题

风卷残云 2012-08-22 12:07:29

请问下下面的结论对不?
1 C51单片器、ARM7:编译器连接后会自动添加部分代码将数据段,BSS段的初始化信息(可能包括BSS段的清零)加在代码段中,代码在ROM中运行时会先分配初始化数据段及bss段。

2 ARM9同样如上,bootloader程序会加载镜像文件(只有代码段,数据段和BSS段的初始化在代码段中)到RAM,系统运行在RAM中时才会根据代码段中的初始化来分配数据段,BSS段并初始化。

3 PPC的gcc编译器将代码段,数据段,BSS段(并不给该段的数据分配空间,只是记录数据所需空间的大小)已经分段好,bootrom可以选择将代码段、数据段(基于ROM镜像) 或 只代码段(rom驻留型镜像)加载到ram中,像代码段(usrInit.c)中手动添加了BSS段的清零代码。

谢谢!

...全文
1050 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
风卷残云 2012-08-23
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]
以gcc来说,它是可以指定段的分配的。
[/Quote]
gcc指定段的分配既是说编译器自动将数据区划分出来的,就是说我问题中的第3个是对的
风卷残云 2012-08-23
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]
以gcc来说,它是可以指定段的分配的。
[/Quote]
gcc指定段的分配既是说编译器自动将数据区划分出来的,就是说我问题中的第3个是对的
帅得不敢出门 2012-08-23
  • 打赏
  • 举报
回复
以gcc来说,它是可以指定段的分配的。
风卷残云 2012-08-23
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
关于.bss,这里有一个最简单的例子,可以参考一下。
x.sct(ArmLinker链接脚本,基于MDK IDE):

C/C++ code
; Load Region 1: and also the only load region for us
LR_EWROM 0x08000000 NOCOMPRESS 0x02000000 {
; Execute Region 1: ……
[/Quote]

按照这里说的ARM对应的编译器应该是由编译器来添加了各个段的分配程序
风卷残云 2012-08-23
  • 打赏
  • 举报
回复
感谢大家回答!
可能这里我写的宽泛不具体。比如以PPC上的vxWorks系统为例,我们生成的image文件有几种,其中
基于ROM的bootloader将其代码段和数据段都拷贝到RAM中
基于ROM驻留型的image文件bootloader只将其数据段拷贝到RAM中
image文件分为三部分text,data,bss(不占空间,在运行C程序中扩展为全零),这些空间的分配是由编译器分开的吧?
因为C程序中只管定义一些全局变量等等,不会有空间分配之说
各位老师请先明确的给出对,或不对,或不全对的判断。
其他几个芯片的编译器可以也先给出判断再回答,我先做个初步的区别
谢谢!
风卷残云 2012-08-23
  • 打赏
  • 举报
回复
这里我可能需要认真研究下代码才能深入理解,收获不少,都是链接器进行的地址分配,感谢各位,结贴!
赵4老师 2012-08-23
  • 打赏
  • 举报
回复
个人意见楼主不学汇编是不可能弄懂这个问题的。
JiMoKuangXiangQu 2012-08-23
  • 打赏
  • 举报
回复
附带.bss的清0代码:
ldr	r0, =__bss_start
ldr r1, =__bss_end
sub r1, r0
bl ClearMem
JiMoKuangXiangQu 2012-08-23
  • 打赏
  • 举报
回复
另外有一段我曾使用过的arm-eabi-ld.exe链接器的脚本:
x.ld

SEARCH_DIR(c:/xxx/xxx/lib) /* 这里是具体的搜索目录 */

MEMORY {

rom : ORIGIN = 0x08000000, LENGTH = 32M
iwram : ORIGIN = 0x03000000, LENGTH = 32K
ewram : ORIGIN = 0x02000000, LENGTH = 256K
dram : ORIGIN = 0x18990000, LENGTH = 400K
}

__text_start = ORIGIN(rom);
__eheap_end = ORIGIN(ewram) + LENGTH(ewram);
__iwram_start = ORIGIN(iwram);
__iwram_top = ORIGIN(iwram) + LENGTH(iwram);
__dram_start = ORIGIN(dram);
__dram_top = ORIGIN(dram) + LENGTH(dram);
__sp_irq = __iwram_top - 0x060;
__sp_usr = __sp_irq - 0x0a0;
__irq_flags = 0x03007ff8;

SECTIONS
{
. = __text_start;
.init :
{
KEEP (*(.init))
. = ALIGN(4);
} >rom =0xff

.plt :
{
*(.plt)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom

.text : /* ALIGN (4): */
{
*(EXCLUDE_FILE (*.iwram* *.dram*) .text)
*(.stub .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0xff

__text_end = .;
.fini :
{
KEEP (*(.fini))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom =0

.rodata :
{
*(.rodata*)
*all.rodata*(*)
*(.roda)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >rom
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >rom
__exidx_end = .;

.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0

.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0


.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0

.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >rom = 0

.pattern ALIGN(0x80000) :
{
__pattern_start = ABSOLUTE(.) ;
. += 64 ;
*(.pattern)
__pattern_end = ABSOLUTE(.) ;
} >rom = 0x00

__iwram_lma = .;

.iwram __iwram_start : AT (__iwram_lma)
{
__iwram_start = ABSOLUTE(.) ;
*(.iwram)
*iwram.*(.text)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__iwram_end = ABSOLUTE(.) ;
} >iwram = 0xff

__data_lma = __iwram_lma + SIZEOF(.iwram) ;

.bss ALIGN(4) (NOLOAD) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__bss_end = ABSOLUTE(.) ;

} AT>iwram

__bss_end__ = __bss_end ;

.data ALIGN(4) : AT (__data_lma)
{
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
} >iwram = 0xff

__preinit_lma = __data_lma + SIZEOF(.data);

PROVIDE (__preinit_array_start = .);
.preinit_array : AT (__preinit_lma) { KEEP (*(.preinit_array)) } >iwram
PROVIDE (__preinit_array_end = .);

__init_lma = __preinit_lma + SIZEOF(.preinit_array);

PROVIDE (__init_array_start = .);
.init_array : AT (__init_lma)
{
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
} >iwram
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);

__fini_lma = __init_lma + SIZEOF(.init_array);

.fini_array : AT (__fini_lma)
{
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
} >iwram
PROVIDE (__fini_array_end = .);

__jcr_lma = __fini_lma + SIZEOF(.fini_array);
.jcr : AT (__jcr_lma) { KEEP (*(.jcr)) } >iwram

__data_end = ABSOLUTE(.);
__iwram_overlay_lma = __jcr_lma + SIZEOF(.jcr);

__iwram_overlay_start = . ;

OVERLAY ALIGN(4) : NOCROSSREFS AT (__iwram_overlay_lma)
{
.iwram0 { *(.iwram0) . = ALIGN(4);}
.iwram1 { *(.iwram1) . = ALIGN(4);}
.iwram2 { *(.iwram2) . = ALIGN(4);}
.iwram3 { *(.iwram3) . = ALIGN(4);}
.iwram4 { *(.iwram4) . = ALIGN(4);}
.iwram5 { *(.iwram5) . = ALIGN(4);}
.iwram6 { *(.iwram6) . = ALIGN(4);}
.iwram7 { *(.iwram7) . = ALIGN(4);}
.iwram8 { *(.iwram8) . = ALIGN(4);}
.iwram9 { *(.iwram9) . = ALIGN(4);}

}>iwram = 0xff

__iwram_overlay_end = . ;
__end = . ;

__ewram_lma = __iwram_overlay_lma + (__iwram_overlay_end - __iwram_overlay_start) ;

__iheap_start = . ;

__ewram_start = ORIGIN(ewram);
.ewram __ewram_start : AT (__ewram_lma)
{
*(.ewram)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
}>ewram = 0xff

__pad_lma = __ewram_lma + SIZEOF(.ewram);

.sbss ALIGN(4)(NOLOAD):
{
__sbss_start = ABSOLUTE(.);
*(.sbss)
. = ALIGN(4);
__sbss_end = ABSOLUTE(.);
} AT>ewram

__ewram_end = __sbss_end ;
__eheap_start = __sbss_end;
__end__ = __sbss_end;

/* EZF Advance strips trailing 0xff bytes, add a pad section so nothing important is removed */
.pad ALIGN(4) : AT (__pad_lma)
{
LONG(0x52416b64)
LONG(0x4d)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} = 0xff

__sdram_lma__ = __pad_lma + SIZEOF(.pad);

.cdram 0x18990000 : AT (__sdram_lma__)
{
__dram_start = . ;
*(.dram)
. = ALIGN(32);
__dram_end = . ;
} >dram


__rom_end__ = __sdram_lma__ + SIZEOF(.cdram);

/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.stack 0x80000 : { _stack = .; *(.stack) }
/* These must appear regardless of . */
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}
JiMoKuangXiangQu 2012-08-23
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]
感谢大家回答!
可能这里我写的宽泛不具体。比如以PPC上的vxWorks系统为例,我们生成的image文件有几种,其中
基于ROM的bootloader将其代码段和数据段都拷贝到RAM中
基于ROM驻留型的image文件bootloader只将其数据段拷贝到RAM中
image文件分为三部分text,data,bss(不占空间,在运行C程序中扩展为全零),这些空间的分配是由编译器分开的吧?……
[/Quote]
准确的讲是由Linker来分配的,但怎样分配,对于标准格式如a.out,.exe,Linker有一个默认的输入Script.
满足ELF规范或者PE等规范的Executable又有一些标准的段,如.bss,.text,.data,.init,.fini等.每个
满足ELF规范或者PE等规范的Linker实现的默认的输入Script会产生标准格式的输出,如a.out,.exe等.
编译器产生的文件是作为Linker的输入.

另外,lz提出问题描述有点含混不清,似乎不好对你的结论对错做出判断.
JiMoKuangXiangQu 2012-08-22
  • 打赏
  • 举报
回复
关于.bss,这里有一个最简单的例子,可以参考一下。
x.sct(ArmLinker链接脚本,基于MDK IDE):
; Load Region 1: and also the only load region for us
LR_EWROM 0x08000000 NOCOMPRESS 0x02000000 {
; Execute Region 1: Root Region, We put all read-only data, read-only code here
EWROM 0x08000000 0x02000000 {
boot.o(INIT, +FIRST)
* (+RO)
}

; Execute Region 2: We put all R/W, ZI data here
EWRAM 0x02000000 UNINIT 0x00020000 {
* (+RW,+ZI)
}
}


.bss 初始化代码片段:
         ldr		r0, =|Image$$EWRAM$$ZI$$Base|
ldr r1, =|Image$$EWRAM$$ZI$$Length|
bl __memclr
JiMoKuangXiangQu 2012-08-22
  • 打赏
  • 举报
回复
这些细节和具体的编译器和链结器有关系.
通常做嵌入式开发的人需要了解这些细节.
要了解这些细节,需要学习:
. ELF规范(ABI: Application Binary Interface);
ELF规范又分3个层次:
a. 芯片架构相关的ELF规范;
b. 通用层,可参考文档 《Executable and Linking Format (ELF) Specification》;
c. 操作系统接口层.
. 编译器原理,Linker & Loader原理;
编译器的参考书籍很多,龙书什么的。
Linker & Loader的参考书籍有《Linkers and Loaders》。
这些书都是对编译器以及Linker & Loader通用理论的介绍,实际当中
还要参考具体编译器材和Linker的手册。
. 学习Linker Script。如gld的Script,比较流行。另外还有ArmLinker的Script.
. 结合工具如readelf, objdump等来分析.obj,.elf的段结构。
至于你描述的.bss等什么,都可以通过Linker Script来控制。
至于.bss的初始化什么的,是程序代码做的事情,通常是结果Linker导出的符号进行.bss的初始化。
而这些代码通常都封装到了bootloader之类的东西里面。

如果的PC平台大多数平台都支持ELF规范,而Windows平台则支持PE32和最新的PE64。
titer1 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]
《C++反汇编与逆向分析技术揭秘》第3章 认识启动函数,找到程序入口
[/Quote]
赵老师说的这本书 适合什么人看? 学c++有必要看汇编吗
赵4老师 2012-08-22
  • 打赏
  • 举报
回复
《C++反汇编与逆向分析技术揭秘》第3章 认识启动函数,找到程序入口
赵4老师 2012-08-22
  • 打赏
  • 举报
回复
楼主如果从创建进程开始,一直单步跟踪到进入该进程main函数之前,我猜就会豁然开朗了。
hlhua 2012-08-22
  • 打赏
  • 举报
回复
没接触过这方面的知识呢
风卷残云 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
这个跟芯片无关的
而是跟操作系统(linux/win ==),运行文件的格式(a.out ELF PE)相关
gcc编译出的ELF , bss并不占用磁盘空间的。
全局变量的初始化,是在main函数之前开始的。

1 51单片机木有操作系统,它的程序有木有分段,如何分,不清楚。
2 bootloader加载的内核镜像是kernel,所以它又有所不同,它分的段比较多, 如模块的__ini……
[/Quote]

--感谢回答

我是想知道这几种芯片对应的编译器对数据段、代码段等的初始化处理,是如何最终在RAM中分配好各自的段的过程?与操作系统也有关系?
比如编译了基于ROM的vxWorks映像文件,此时代码数据段已经有编译器分配好,我们bootload加载到正确的RAM地址中就直接到RAM中运行代码,不会再分配数据段等操作了吧?
再比如ARM应用中,使用keilC编译不带操作系统的文件a.out,在rom中运行,数据段的分配初始化等是由编译器添加到a.out中后,运行a.out时再分配的数据段地址?
问题仍旧如上
帅得不敢出门 2012-08-22
  • 打赏
  • 举报
回复
这个跟芯片无关的
而是跟操作系统(linux/win ==),运行文件的格式(a.out ELF PE)相关
gcc编译出的ELF , bss并不占用磁盘空间的。
全局变量的初始化,是在main函数之前开始的。

1 51单片机木有操作系统,它的程序有木有分段,如何分,不清楚。
2 bootloader加载的内核镜像是kernel,所以它又有所不同,它分的段比较多, 如模块的__init 区,
个人人为其bss的原理应该是与ELF的一致。
3 bootrom没有用过, 也不清楚其原理, 但是它的功能是可以实现的。

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧