我想在二进制文件中插入一个字节数组,但在特定部分中,因此我可以稍后使用 objcopy
更新此部分。
第 1 步 - 失败
如果我在 objdump
生成的 elf
文件我可以看到以下内容:
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
在 elf
文件中构建并使用 egain objdump
后,我获得:
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 处理器这样的东西具有针对 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 是可访问的(即,尝试这样做不会导致错误),它只是(还)不包含您期望的数据。这将不同于试图访问一个实际上可访问的地址(例如,许多情况下取消引用一个从未远程有效的指针和指向不存在任何东西的指针)通常会出错。
关于c - 如果链接描述文件中未定义部分,则虚拟内存地址错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57185792/