.data 部分之前无法解释的空内存地址
Unexplained empty memory address before .data section
我目前正在 STM32 上编写一个程序,它使用一个简单的引导加载程序和两个子应用程序。子应用程序位于闪存中,引导加载程序将其中一个(代码和数据)加载到 RAM 存储器中,然后开始执行它。只需遍历闪存中的地址并将数据从这些地址复制到 RAM 即可完成复制。
最近我遇到了一些奇怪的错误。我试图从全局定义的数组中读取一些数据。我得到了错误的价值观,例如当我试图读取 array[0]
时,我得到了 array[1]
.
的值
我对 .elf 和 .hex 文件进行了一些调试和反汇编,我想我已经找到了这个错误的原因。原来是这个项目.elf文件的.ARM
段之间有一个空的space
令人惊讶的是,这个空 space 不存在于 .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}
由于这个空内存 space,它在 .hex 文件中消失了,当我的引导加载程序将数据加载到 RAM 时,LMA 是 2000eec8
的 array[0]
最终成为地址 2000eec4
.
这是我使用的 linker 脚本中令人不安的片段:
/* 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 文件link 合并为一个.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
但是到目前为止没有成功。
有谁知道这个空的 space 来自哪里以及如何摆脱它(或将其包含在 .hex 文件中)?
编辑: 根据前两条评论的建议,我试过:
* 在我的工具链中使用最新版本的 arm-none-eabi-gcc
和 arm-none-eabi-objcopy
,
* .ARM
部分的 ALIGN(4)
,
* 不将 .ARM
部分复制到 RAM。
不幸的是,这些解决方案中的 none 解决了这个问题。
我最近注意到,有时 .elf
文件中的数据对齐正确(.data
部分的第一个地址是紧跟在 [= =19=]节)。这取决于 .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
部分在地址 0x*******C
结束时,.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 大声疾呼。
我目前正在 STM32 上编写一个程序,它使用一个简单的引导加载程序和两个子应用程序。子应用程序位于闪存中,引导加载程序将其中一个(代码和数据)加载到 RAM 存储器中,然后开始执行它。只需遍历闪存中的地址并将数据从这些地址复制到 RAM 即可完成复制。
最近我遇到了一些奇怪的错误。我试图从全局定义的数组中读取一些数据。我得到了错误的价值观,例如当我试图读取 array[0]
时,我得到了 array[1]
.
我对 .elf 和 .hex 文件进行了一些调试和反汇编,我想我已经找到了这个错误的原因。原来是这个项目.elf文件的.ARM
段之间有一个空的space
令人惊讶的是,这个空 space 不存在于 .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}
由于这个空内存 space,它在 .hex 文件中消失了,当我的引导加载程序将数据加载到 RAM 时,LMA 是 2000eec8
的 array[0]
最终成为地址 2000eec4
.
这是我使用的 linker 脚本中令人不安的片段:
/* 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 文件link 合并为一个.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
但是到目前为止没有成功。
有谁知道这个空的 space 来自哪里以及如何摆脱它(或将其包含在 .hex 文件中)?
编辑: 根据前两条评论的建议,我试过:
* 在我的工具链中使用最新版本的 arm-none-eabi-gcc
和 arm-none-eabi-objcopy
,
* .ARM
部分的 ALIGN(4)
,
* 不将 .ARM
部分复制到 RAM。
不幸的是,这些解决方案中的 none 解决了这个问题。
我最近注意到,有时 .elf
文件中的数据对齐正确(.data
部分的第一个地址是紧跟在 [= =19=]节)。这取决于 .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
部分在地址 0x*******C
结束时,.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 大声疾呼。