我正在使用 ARM Cortex-M4 处理器(特别是
STM32F4
微控制器)开发一个嵌入式项目,并且遇到了与链接器脚本中定义的内存部分相关的特殊问题。我正在使用 arm-none-eabi-gcc
工具链进行编译。
我有一个二进制文件,我想将其包含在我的固件中。我在汇编文件中创建了一个自定义部分 (
.rawdata
) 以包含此二进制文件,并且我修改了 linker script
以将此部分放入 Flash
内存中。但是,我在运行时面临 .rawdata 部分中数据完整性的问题。
当我将
.rawdata
部分放置在 .data
部分或我的 .text
中的 linker script
部分时,一切都会按预期工作:数据在内存中正确分配,并且实际数据正确存储。我可以在运行时访问和打印数据,没有任何问题。
但是,当我尝试创建一个独立的
.rawdata
部分(在 .data
之外)或将其放置在 .text
部分内时,数据似乎已分配,但内容不是我所期望的。在运行时,当我打印 .rawdata
部分的内容时,我得到不正确的值(与原始 .bin
内容不匹配)。
有趣的是,当我使用 .elf
检查 arm-none-eabi-objdump
文件时,.rawdata
部分似乎包含正确的数据。这种差异仅在运行时发生。
链接器脚本片段:
ld
.rawdata :
{
. = ALIGN(4);
_mstart = .;
KEEP(*(.rawdata))
. = ALIGN(4);
_mend = .;
} >FLASH
为什么将
.rawdata
部分放置在 .data
部分内可以正常工作,但将其创建为独立部分会导致运行时数据不正确?
对于 ARM Cortex-M4 处理器的链接器脚本中的自定义部分,是否缺少特定的注意事项或配置?
当
.rawdata
部分的数据在 .data 部分之外定义时,如何确保其数据在运行时保持完整?
任何有关如何解决此问题的见解或建议将不胜感激。预先感谢您的帮助!
如果我检查使用
arm-none-eabi-objdump -h -j .rawdata blink.elf
arm-none-eabi-objdump -s -j .rawdata blink.elf
blink.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
1 .rawdata 0000003c 080001c8 080001c8 000071dc 2**0
CONTENTS, READONLY
blink.elf: file format elf32-littlearm
Contents of section .rawdata:
80001c8 cdcccc3d cdcc4c3e 9a99993e cdcccc3e ...=..L>...>...>
80001d8 0000003f 9a99193f 3333333f cdcc4c3f ...?...?333?..L?
80001e8 6666663f 0000803f cdcc8c3f 9a99993f fff?...?...?...?
80001f8 6666a63f 3333b33f 0000c03f ff.?33.?...?
这是应该加载的正确数据。
但是,如果在运行时我检查使用 USART 打印该内存区域内的内容,我会得到:
data size: 60 bytes
Start address: 0x80001c8
End address: 0x8000204
00000000
00000000
3f501eb4
bfe008ee
3d600962
416277e1
c6ffe8d3
3c201ffe
40c1e8d1
41428902
c6004342
4161df76
c2000560
4161a8f3
c2000560
其中地址与上面相同,但内存中的内容不同。
相反, 如果我将
.rawdata
放在 .text
或 .data
部分内,我会得到与应有的相同的内存内容。
现在补充一下,我发现使用:
arm-none-eabi-objcopy -O binary blink.elf so.bin
.rawdata
数据消失了,我已经使用hexdump
进行了检查,实际数据仅在.elf文件中,但不在生成的.bin中。
另外,我注意到
.hex
文件的偏移量存在一些冲突:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .isr_vector PROGBITS 08000000 001000 0001c8 00 WA 0 0 4
[ 2] .rawdata PROGBITS 080001c8 0071dc 00003c 00 0 0 1
[ 3] .text PROGBITS 080001d0 0011d0 0053cc 00 AX 0 0 16
[ 4] .data PROGBITS 20000000 007000 0001dc 00 WA 0 0 4
[ 5] .bss NOBITS 200001dc 0071dc 00017c 00 WA 0 0 4
您可以看到
.rawdata
和 .bss
在十六进制文件中的偏移量相同,但是 .bss 被标记为 TYPE NOBITS,因此它不应该占用 .hex 文件中数据的任何空间,我不这样做不知道这是否也会导致问题
要解决此问题并创建自定义部分,请在程序集文件中将“aw”标志添加到
.rawdata
部分:
.section .rawdata,"aw"
.incbin "my.bin"
来自 binutils 文档:
“aw”标志指定应分配该节 (a) 和 可写(w)。
这确保了该部分在内存中正确分配,并且可以在运行时访问和修改。
如果未指定标志,则默认标志取决于该部分 姓名。如果部分名称无法识别,则默认为 没有上述标志的部分:不会分配它 在内存中,不可写,也不可执行。该部分将包含 数据。
因此,根据文档,该部分不会从
.elf
复制到 .bin
using arm-none-eabi-objcopy -O binary blink.elf so.bin
,也不会 flashed
复制到 MCU 使用的工具,如 openocd
最后,
.rawdata
部分将如下所示,并将在MCU中正确加载数据:_mstart
:
.rawdata : ALIGN(4)
{
_mstart = .;
KEEP(*(.rawdata))
. = ALIGN(4);
_mend = .;
} >FLASH