裸机 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
我想把全局变量的初始值放在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