如果链接描述文件中未定义部分,则虚拟内存地址错误

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 objdumpelf 文件后,我获得:

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 (例如许多取消引用从未远程有效的指针和指向不存在的指针的许多情况)通常会错误。