目录
1、为什么要清除 .bss 段
.bss 段保存的是 未被初始化 或者 初始化为0 的全局/静态变量。在编译器看来,这些东西是多余的,实际并不会给他们分配空间。因此,编译生成目标文件的时候,这些东西并不会被加载到目标文件中。目的是降低目标文件所占空间大小。
万一我们用到了这些未被初始化的全局变量(如自增),因为没有被初始化,可能会引发一些问题。这里清除 .bss 段其实就是在给 .bss 段中的变量清零,相当于给那些没有被初始化的变量赋予初值。
存储器会记下 bss 段的起始位置 __bss_start 和结束位置 __bss_end,以便于清零,等到运行程序的时候,bss 段会被加载到内存。
2、使用汇编清除 .bss 段
记录 bss 段的起始/结束位置
裸机开发时,我们可以在 lds 链接脚本中记录bss 段的起始位置和结束位置,以便于在 C 文件或者汇编文件中使用。下面的解析参考:lds 链接脚本的基本语法
- SECTIONS
- {
- . = 0x87800000;
- .text :
- {
- obj/start.o
- *(.text)
- }
- .rodata ALIGN(4) : { *(.rodata) }
- .data ALIGN(4) : { *(.data) }
- . = ALIGN(4); /* 地址四字节对齐 */
- __bss_start = . ; /* 记录 .bss 段的起始位置 */
- .bss ALIGN(4) : { *(.bss) *(COMMON) }
- __bss_end = . ; /* 记录 .bss 段的结束位置 */
- }
使用汇编对 bss 段清零
- .global _start
-
- _start:
- /*
- 其他操作
- */
-
- ldr r0, =__bss_start @ 将lds脚本文件中的 __bss_start 加载到寄存器 r0
- ldr r1, =__bss_end @ 将lds脚本文件中的 __bss_end 加载到寄存器 r0
- mov r2, #0 @ r2 = 0(因为下面使用 stmia 不支持立即数操作)
-
- bss_loop:
- stmia r0!, {r2} @ 将r2寄存器的值写入到r0指向的地址,同时r0自增4字节
- cmp r0, r1 @ 判断是否到达 bss 段的末尾
- bne bss_loop @ 如果不等于,继续初始化
-
- /* 其他操作 */
寄存器指令参考:
评论记录:
回复评论: