.data 部分之前无法解释的空内存地址



我目前正在STM32上编写一个程序,该程序使用一个简单的引导加载程序和两个子应用程序。子应用程序位于闪存中,引导加载程序将其中一个(代码和数据)加载到 RAM 内存中,然后开始执行它。只需遍历闪存中的地址并将数据从这些地址复制到RAM,即可完成复制。

最近我遇到了一些奇怪的错误。我试图从全局定义的数组中读取一些数据。我得到了错误的值,例如,当我试图读取array[0]时,我得到了array[1]的值。

我对 .elf 和 .hex 文件进行了一些调试和反汇编,我想我已经找到了这个错误的原因。原来,该项目的.elf文件的.ARM部分之间有一个空白区域。
令人惊讶的是,这个空白区域在.hex文件(我用于刷新STM32板)中不存在。
这就是我要说的:

  • .elf 文件:
2000ee70:   469e        mov lr, r3
2000ee72:   4770        bx  lr
Disassembly of section .ARM:
2000ee74 <__exidx_start>:
2000ee74:   7fff267c    svcvc   0x00ff267c
2000ee78:   00000001    andeq   r0, r0, r1
Disassembly of section .data:
2000ee80 <evnames.5255>:
2000ee80:   00000000    andeq   r0, r0, r0
2000ee84:   08030104    stmdaeq r3, {r2, r8}
  • .hex 文件:
802de70:   4770469e    
802de74:   7fff267c    svcvc   0x00ff267c
802de78:   00000001    andeq   r0, r0, r1
802de7c:   00000000    andeq   r0, r0, r0
802de80:   08030104    stmdaeq r3, {r2, r8}

显然,地址是不同的,因为.elf文件中的地址是VMA,而.hex文件中的地址是LMA。
我在这里注意到的是,在.ARM部分之后,下一个内存地址应该是2000ee7C但是由于未知原因,.data部分从2000ee80开始。所以他们之间有一个无法解释的空话。但是这个空字在 .hex 文件中不存在。00000001紧随其后的是00000000
所以基本上,我认为 .hex 文件的反汇编应该输出以下结果:

802de70:   4770469e    
802de74:   7fff267c    svcvc   0x00ff267c
802de78:   00000001    andeq   r0, r0, r1
802de7c:       <something here>
802de80:   00000000    andeq   r0, r0, r0
802de84:   08030104    stmdaeq r3, {r2, r8}

由于这个空白内存空间在 .hex 文件中消失了,当我的引导加载程序将数据加载到 RAM 时,LMA2000eec8array[0]最终位于地址2000eec4.

这是我使用的链接器脚本的令人不安的片段:

/* ARM specific sections, they also go to FLASH and are copied to RAM */
.ARM.extab : { 
*(.ARM.extab* .gnu.linkonce.armextab.*) 
} > RAMAPP AT> FLASH_APP
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > RAMAPP AT> FLASH_APP
/* Initialized data sections - variables etc.  */
.data :
{
. = ALIGN(4);
*(.data)           /* .data sections */
*(.data*)          /* .data* sections */
. = ALIGN(4);    
} >RAMAPP AT> FLASH_APP /* Data section is placed in FLASH_APP but its Virtual Memory Address is in RAM_APP */

我使用以下命令将 .o 文件链接到一个 .elf 文件中:

arm-none-eabi-gcc -Wl,--gc-sections -mthumb -mthumb-interwork -mcpu=cortex-m4 --specs=nosys.specs -L[path_to_library_files] -T[path_to_ld_file] [long_list_of_object_files] -o [output_elf_file]

我使用以下命令将 .elf 文件转换为 .hex 文件:

arm-none-eabi-objcopy -O ihex [elf_file] [output_hex_file]

我尝试尝试使用我提供给arm-none-eabi-objcopy的参数,并arm-none-eabi-gcc摆脱这种填充,例如--file-alignment--gap-fill但到目前为止没有成功。

有没有人知道这个空白空间从何而来以及如何摆脱它(或将其包含在 .hex 文件中)?

编辑:根据前两条评论的建议,我尝试了:
*在我的工具链中使用最新版本的arm-none-eabi-gccarm-none-eabi-objcopy
*.ARM部分的ALIGN(4)
*不将.ARM部分复制到RAM。
不幸的是,这些解决方案都没有解决这个问题。

我最近注意到的是,有时数据在.elf文件中正确对齐(.data部分的第一个地址是紧跟在.ARM部分末尾之后的地址)。这取决于.ARM部分恰好结束的地址。我可以通过在代码中添加一些额外的函数调用(导致更大的.text区域)来操纵它,例如:

2000ee84:   469e        mov lr, r3
2000ee86:   4770        bx  lr
Disassembly of section .ARM:
2000ee88 <__exidx_start>:
2000ee88:   7fff2668    svcvc   0x00ff2668
2000ee8c:   00000001    andeq   r0, r0, r1
Disassembly of section .data:
2000ee90 <evnames.5255>:
2000ee90:   00000000    andeq   r0, r0, r0
2000ee94:   2001111c    andcs   r1, r1, ip, lsl r1

这样,我已经确定了: * 当.ARM部分以地址0x*******0结尾时,.data部分错误地从0x*******8开始(应该是0x*******4) * 当.ARM部分在地址0x*******8结束时,.data部分错误地从0x*******0开始(应该0x*******C) * 当.ARM部分在地址


0x*******4结束时,.data部分正确开始于0x*******8
* 当.ARM部分在地址 CC_结束时42.data部分正确地从0x*******0开始

好的,事实证明我必须ALIGN_WITH_INPUT添加到链接器脚本中的 .data 部分。喜欢这个:

.data : ALIGN_WITH_INPUT
{
. = ALIGN(4);
*(.data)           /* .data sections */
*(.data*)          /* .data* sections */
. = ALIGN(4);    
} >RAMAPP AT> FLASH_APP

此参数会导致截面的 LMA 以与 VMA 相同的方式对齐。 现在,.hex 文件中的对齐方式与 .elf 文件中的对齐方式相同。
向reddit用户FreddieChopin大喊大叫,他帮助我解决了这个问题。

最新更新