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

标签 c gcc linker embedded linker-scripts

我想在二进制文件中插入一个字节数组,但在特定部分中,因此我可以稍后使用 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/

相关文章:

c++ - 与库的 c 绑定(bind)链接

c++ - 使用 free() 时出现段错误

c - "int a=({10;});"这个表达式用C语言怎么解释?

c++ - 在 Linux 上的 C++ 源文件上运行 'gcc' 给出 "cc1plus: out of memory allocating ..."错误消息

c++ - 对 C++ 中的链接器感到困惑

c++ - Boost单元测试链接错误--abi不匹配?

c++ - 我是否需要在显式加载的共享库之间隐式链接以进行交互?

c - 编译c代码时出错

c - linux C select()永远不会返回0

c++ - 使用 OpenMPI 从 Fortran 调用 C++