裸机 ARM 链接器脚本:如何将初始化数据从 ROM 重新定位到 RAM?

Bare Metal ARM linker script: How to relocate initialized data from ROM to RAM?

我想把全局变量的初始值放在ROM段,然后,重新定位它们的地址,把它们的值复制到RAM中(这样就可以被程序编辑)。

我的链接器脚本部分

/* code */
.text :
{
    __text_start = .;
    *(.text)
    __text_end = .;
} > ROM



/* Initialized global and static variables */
.data : AT ( __text_end )
{ 
    __data_start = . ; 
    *(.data); 
    __data_end = . ;  
} > RAM

我的引导ROM代码:

int global_var = 0xAAA;

void main()
{
    global_var = 0xBBB;
}

问题:初始值0xAAA在编译后的bin文件中位于RAM地址而不是ROM

如何在 ROM 中定义初始 .data 值,然后将其地址重新定位到 RAM?

感谢您的帮助

查看有关内存布局和链接的this综合说明。

您必须添加相关的启动代码,将 ROM 中的 RAM 部分复制到它们在 RAM 中的目标位置,并初始化 C 运行时环境(清零 .bss 等)。网上有很多示例,通常由您的 SDK 提供,与还提供的链接器脚本相匹配,因为这些文件必须匹配。

int global_var = 0xAAA;
int global_too;
void main()
{
    global_var = 0xBBB;
}

MEMORY
{
    bob : ORIGIN = 0x08000000, LENGTH = 0x100
    ted : ORIGIN = 0x20000000, LENGTH = 0x100
}
SECTIONS
{
    .text   : { *(.text*)   } > bob
    .rodata : { *(.rodata*) } > bob
    .data   : { *(.data*)   } > ted AT > bob
    .bss    : { *(.bss*)    } > ted AT > bob
}

Disassembly of section .text:

08000000 <reset-0x8>:
 8000000:   20000400
 8000004:   08000009

08000008 <reset>:
 8000008:   f000 f802   bl  8000010 <main>
 800000c:   e7fe        b.n 800000c <reset+0x4>
    ...

08000010 <main>:
 8000010:   4b01        ldr r3, [pc, #4]    ; (8000018 <main+0x8>)
 8000012:   4a02        ldr r2, [pc, #8]    ; (800001c <main+0xc>)
 8000014:   601a        str r2, [r3, #0]
 8000016:   4770        bx  lr
 8000018:   20000000
 800001c:   00000bbb

Disassembly of section .data:

20000000 <global_var>:
20000000:   00000aaa

Disassembly of section .bss:

20000004 <global_too>:
20000004:   00000000

如果你真的 want/need .data 或 .bss 然后继续并添加类似这样的东西

MEMORY
{
    bob : ORIGIN = 0x08000000, LENGTH = 0x100
    ted : ORIGIN = 0x20000000, LENGTH = 0x100
}
SECTIONS
{
    .text   : { *(.text*)   } > bob
    .rodata : { *(.rodata*) } > bob
    __data_rom_start__ = .;
    .data   : 
        { 
            __data_start__ = .;
            *(.data*)   
            __data_end__ = .;
        } > ted AT > bob
    .bss    : 
        { 
            __bss_start__ = .;
            *(.bss*)    
            __bss_end__ = .;
        } > ted AT > bob
}

在bootstrap中仔细检查

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __bss_start__
.word __bss_end__

Disassembly of section .text:

08000000 <reset-0x8>:
 8000000:   20000400
 8000004:   08000009

08000008 <reset>:
 8000008:   f000 f80c   bl  8000024 <main>
 800000c:   e7fe        b.n 800000c <reset+0x4>
 800000e:   46c0        nop         ; (mov r8, r8)
 8000010:   08000034
 8000014:   20000000
 8000018:   20000004
 800001c:   20000004
 8000020:   20000008

08000024 <main>:
 8000024:   4b01        ldr r3, [pc, #4]    ; (800002c <main+0x8>)
 8000026:   4a02        ldr r2, [pc, #8]    ; (8000030 <main+0xc>)
 8000028:   601a        str r2, [r3, #0]
 800002a:   4770        bx  lr
 800002c:   20000000
 8000030:   00000bbb

Disassembly of section .data:

20000000 <global_var>:
20000000:   00000aaa

Disassembly of section .bss:

20000004 <global_too>:
20000004:   00000000

 8000010:   08000034
 8000014:   20000000
 8000018:   20000004
 800001c:   20000004
 8000020:   20000008

arm-none-eabi-nm so.elf 
20000008 B __bss_end__
20000004 B __bss_start__
20000004 D __data_end__
08000034 T __data_rom_start__
20000000 D __data_start__
20000004 B global_too
20000000 D global_var
08000024 T main
08000008 t reset

hexdump -C so.bin
00000000  00 04 00 20 09 00 00 08  00 f0 0c f8 fe e7 c0 46  |... ...........F|
00000010  34 00 00 08 00 00 00 20  04 00 00 20 04 00 00 20  |4...... ... ... |
00000020  08 00 00 20 01 4b 02 4a  1a 60 70 47 00 00 00 20  |... .K.J.`pG... |
00000030  bb 0b 00 00 aa 0a 00 00                           |........|
00000038

并且您可以在文件中的偏移量 0x34 处看到 0x00000aaa。

然后填写 bootstrap 使用这些工具生成的地址将 .data 从闪存复制到 ram 并归零 .bss。

我对 .data 没有用处,也不对 .bss 做任何假设,所以我的看起来像这样

reset:
    bl main
    b .
MEMORY
{
    bob : ORIGIN = 0x08000000, LENGTH = 0x100
    ted : ORIGIN = 0x20000000, LENGTH = 0x100
}
SECTIONS
{
    .text   : { *(.text*)   } > bob
    .rodata : { *(.rodata*) } > bob
    .bss    : { *(.bss*)    } > ted
}

YMMV

幸运或不幸的是,gnu ld 提供了不止一种方法来解决这个问题,因为您已经开始使用链接描述文件进行演示。同时 gnu ld 使它成为一个 PITA 来解决这个问题,对 where/how 非常敏感以放置 something = .;您会看到各种不同的示例,但它们似乎都有效。

还要注意这些名称也不重要:

MEMORY
{
    bob : ORIGIN = 0x08000000, LENGTH = 0x100
    ted : ORIGIN = 0x20000000, LENGTH = 0x100
}
SECTIONS
{
    .hello : { *(.text*)    } > bob
    .world : { *(.data*)    } > ted AT > bob
}


Disassembly of section .hello:

08000000 <reset-0x8>:
 8000000:   20000400
 8000004:   08000009

08000008 <reset>:
 8000008:   f000 f802   bl  8000010 <main>
 800000c:   e7fe        b.n 800000c <reset+0x4>
    ...

08000010 <main>:
 8000010:   4b01        ldr r3, [pc, #4]    ; (8000018 <main+0x8>)
 8000012:   4a02        ldr r2, [pc, #8]    ; (800001c <main+0xc>)
 8000014:   601a        str r2, [r3, #0]
 8000016:   4770        bx  lr
 8000018:   20000000
 800001c:   00000bbb

Disassembly of section .world:

20000000 <global_var>:
20000000:   00000aaa


hexdump -C so.bin
00000000  00 04 00 20 09 00 00 08  00 f0 02 f8 fe e7 00 00  |... ............|
00000010  01 4b 02 4a 1a 60 70 47  00 00 00 20 bb 0b 00 00  |.K.J.`pG... ....|
00000020  aa 0a 00 00                                       |....|
00000024

仍然生成所需的二进制文件。

简答:

试试这个

} > RAM AT > ROM