完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
/*
* These are defined in the board-specific linker script. */ .globl _bss_start _bss_start: .word __bss_start .globl _bss_end _bss_end: .word __bss_end /* * 清BSS段 */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l mov pc, lr /* end_of clear_bss */ 也可以用C语言来实现: void clean_bss(void) { extern int __bss_start, __bss_end; int *p = &__bss_start; for (; p < &__bss_end; p++) *p = 0; } 为什么__bss_start要用&,__bss_start不是直接表示bss起始地址的值吗 |
|
相关推荐
7个回答
|
|
c语言的指针基础 看完指针你应该就明白了 在么就是看看反汇编文件
|
|
|
|
_bss_start:
.word __bss_start 上面的伪指令用C语言表示就是 word __bss_start = _bss_start; 声明一个word类型的变量 __bss_start,然后赋值为_bss_start。 你调用的时候用 int *p = &__bss_start; 完全正确啊。 这跟下面的没什么区别 int start = 0x1234; int *p = &start; |
|
|
|
嗯,我知道了,谢谢你
|
|
|
|
嗯懂得,谢谢你
|
|
|
|
我们都知道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段的结束地址。 |
|
|
|
int a[10];
int *p=a; //与前面定义的数组名a类型相同,才可以这样赋值。 int a; int *p=&a; //前面定义的a是普通变量,才可以这样赋值 |
|
|
|
又学到了 干货啊 谢谢
|
|
|
|
只有小组成员才能发言,加入小组>>
197个成员聚集在这个小组
加入小组为什么点亮LED的例子放在NORFlash上跑会出现奇怪的现象?
2181 浏览 6 评论
1983 浏览 5 评论
韦东山老师推出的《玩转ARM裸机实战》课程将帮你以上问题一扫而光!
4541 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:22 , Processed in 0.936835 second(s), Total 89, Slave 69 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号