目录
1、为什么要清除 .bss 段
2、使用汇编清除 .bss 段
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 @ 如果不等于,继续初始化
/* 其他操作 */
寄存器指令参考:
ldr赋值操作
stm 读写内存
cmp 条件执行