如果链接描述文件中未定义部分,则虚拟内存地址错误
Wrong Virtual Memory Address if section is not defined in the linker script
我想在二进制文件中插入一个字节数组,但在特定部分中,因此我可以稍后使用 objcopy
.
更新此部分
第 1 步 - 失败
如果我在 objdump
生成的 elf
文件时通过 volatile const __attribute__((section(".pub_key"))) uint8_t pub_key_start[10] = "10 characters"
声明数组,我可以看到以下内容:
Sections:
Idx Name Size VMA LMA File off Algn
...
6 .pub_key 00000018 20000674 08039e04 00040674 2**2
...
注意 VMA 和 LMA 是不同的。当我 运行 二进制文件时,符号 pub_key_start
的有效地址是 0x20000674
,但该地址不可访问。实际数据在0x08039e04
.
第 2 步 - 成功
但是,如果我在链接描述文件中定义一个部分,例如:
.pub_key :
{
. = ALIGN(4);
_pub_key_sec_start = .;
*(.pub_key)
*(.pub_key*)
_pub_key_sec_end = .;
. = ALIGN(4);
} >SOME_REGION
构建并使用 egain objdump
和 elf
文件后,我获得:
Sections:
Idx Name Size VMA LMA File off Algn
...
6 .pub_key 00000018 08039e04 08039e04 00049e04 2**2
...
请注意,现在 VMA 和 LMA 相同。
如果现在我用gdb
调试,我可以确认符号pub_key_start
的地址是0x08039e04
,我可以像往常一样访问数组(pub_key_start[n]
).
为什么会这样?
在链接描述文件中定义一个部分而不是不这样做的确切含义是什么?
首先,您使用的似乎是 ARM 部件(可能是 STM32?),其中闪存位于 0x08000000,RAM 位于 0x20000000。
在你的第一种情况下,你有效地(如果可能是无意地)指定的是在 RAM 中相当常见的初始化数据存储,C 启动例程应该将它的初始化从闪存复制到 RAM 以供使用。如果您没有在 RAM 中看到它,可能是复制例程有问题(自定义启动文件中缺少?),或者您正在使用调试器查看 运行.
除非您以其他方式设置链接描述文件,否则您可能会发现这就是 所有 程序中初始化全局数据(例如在源文件中定义的数据)的处理方式。
在第二种情况下,您正在指定直接从闪存访问的数据。
请注意,像 Cortex-M 处理器这样的东西具有针对 data 访问 RAM(以及代码访问闪存)优化的准哈佛数据路径,同时对闪存进行数据访问支持它会产生仲裁开销。当然,许多部分的 RAM 也有限,因此将已初始化但不变的数据复制到 RAM 可能会使用更好地为实际需要在 运行 时间修改的内容保存的资源。
终于解决了一个特定的挑剔问题:
When I run the binary, effectively the address of the symbol pub_key_start is 0x20000674, but that address is not accessible. The actual data is in 0x08039e04.
这是不正确的 - 地址 0x20000674 可访问(即尝试这样做不会导致错误),它只是(还)不包含您期望的数据到。这将不同于尝试访问实际上不可访问的地址 accessible (例如许多取消引用从未远程有效的指针和指向不存在的指针的许多情况)通常会错误。
我想在二进制文件中插入一个字节数组,但在特定部分中,因此我可以稍后使用 objcopy
.
第 1 步 - 失败
如果我在 objdump
生成的 elf
文件时通过 volatile const __attribute__((section(".pub_key"))) uint8_t pub_key_start[10] = "10 characters"
声明数组,我可以看到以下内容:
Sections:
Idx Name Size VMA LMA File off Algn
...
6 .pub_key 00000018 20000674 08039e04 00040674 2**2
...
注意 VMA 和 LMA 是不同的。当我 运行 二进制文件时,符号 pub_key_start
的有效地址是 0x20000674
,但该地址不可访问。实际数据在0x08039e04
.
第 2 步 - 成功
但是,如果我在链接描述文件中定义一个部分,例如:
.pub_key :
{
. = ALIGN(4);
_pub_key_sec_start = .;
*(.pub_key)
*(.pub_key*)
_pub_key_sec_end = .;
. = ALIGN(4);
} >SOME_REGION
构建并使用 egain objdump
和 elf
文件后,我获得:
Sections:
Idx Name Size VMA LMA File off Algn
...
6 .pub_key 00000018 08039e04 08039e04 00049e04 2**2
...
请注意,现在 VMA 和 LMA 相同。
如果现在我用gdb
调试,我可以确认符号pub_key_start
的地址是0x08039e04
,我可以像往常一样访问数组(pub_key_start[n]
).
为什么会这样?
在链接描述文件中定义一个部分而不是不这样做的确切含义是什么?
首先,您使用的似乎是 ARM 部件(可能是 STM32?),其中闪存位于 0x08000000,RAM 位于 0x20000000。
在你的第一种情况下,你有效地(如果可能是无意地)指定的是在 RAM 中相当常见的初始化数据存储,C 启动例程应该将它的初始化从闪存复制到 RAM 以供使用。如果您没有在 RAM 中看到它,可能是复制例程有问题(自定义启动文件中缺少?),或者您正在使用调试器查看 运行.
除非您以其他方式设置链接描述文件,否则您可能会发现这就是 所有 程序中初始化全局数据(例如在源文件中定义的数据)的处理方式。
在第二种情况下,您正在指定直接从闪存访问的数据。
请注意,像 Cortex-M 处理器这样的东西具有针对 data 访问 RAM(以及代码访问闪存)优化的准哈佛数据路径,同时对闪存进行数据访问支持它会产生仲裁开销。当然,许多部分的 RAM 也有限,因此将已初始化但不变的数据复制到 RAM 可能会使用更好地为实际需要在 运行 时间修改的内容保存的资源。
终于解决了一个特定的挑剔问题:
When I run the binary, effectively the address of the symbol pub_key_start is 0x20000674, but that address is not accessible. The actual data is in 0x08039e04.
这是不正确的 - 地址 0x20000674 可访问(即尝试这样做不会导致错误),它只是(还)不包含您期望的数据到。这将不同于尝试访问实际上不可访问的地址 accessible (例如许多取消引用从未远程有效的指针和指向不存在的指针的许多情况)通常会错误。