【裸机开发】使用汇编清除 .bss 段

目录

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 条件执行

猜你喜欢

转载自blog.csdn.net/challenglistic/article/details/131231523