gcc - 我怎么知道 .data 部分需要从哪里获取 init 数据? (gcc 链接器)

标签 gcc linker microcontroller bare-metal

在构建基于 gcc 的裸机 mcu 项目时,您需要在启动期间处理 .data 和 .bss 部分的初始化。

.bss 部分非常简单,因为我只是将整个部分填充为 0。
但是 .data 部分中的变量需要在 rom/flash 中有它们的初始化数据并在启动时复制。

我怎么知道在哪里可以找到带有初始化值的数据?

让我们举个例子。

假设我在 main.c 中创建了两个全局变量

unsigned int my_global_variable_one  = 1;
unsigned int my_global_variable_two  = 2;

然后我可以在目标文件上使用 objdump 来查看它们将位于哪个部分,
但是我在 objdump 输出中找不到任何应该放置 init 数据的地方。
$ arm-none-eabi-objdump --syms main.o | grep my_global_variable
00000000 g     O .data  00000004 my_global_variable_one
00000004 g     O .data  00000004 my_global_variable_two

然后我可以查看整个系统的结果 Sprite ,在本例中为 main.elf。
$ arm-none-eabi-nm -n main.elf | grep my_global_variable
20000000 D my_global_variable_one
20000004 D my_global_variable_two

我在哪里可以找到它们的位置以便我可以复制数据?
我需要在我的链接器脚本中加入什么?

它应该是 .text 或 .rodata 之类的,但我怎么知道?

如何检查 my_global_variable_one 的初始化数据在哪里?

我可以使用任何 binutils 命令(如 readelf 或 objdump)找到这些数据的位置吗?

/谢谢

这是在 stm32 (Cortex M3) mcu 上,并且使用了 gcc 的 CodeBench 版本。

最佳答案

编译器将所有代码和一些只读数据放在 .text 中。部分。可能还有.rodata部分。你可以让你的链接器脚本把它放在一个像这样的 ROM 地址中:

. = <rom-base-address>;
.rodata : { *(.rodata) }
<other read-only sections go here>
.text   : { *(.text) }

编译器将所有可写数据的初始值放入.data部分,以及所有在 .bss 中没有初始值的符号. .bss很简单,您只需将其放在 RAM 中即可。 .data想在运行时在 RAM 中,但在加载时在 ROM 中,链接描述文件允许您使用 AT 来做到这一点。关键词:
. = <ram-base-address>;
.bss  : { *(.bss) }
.data : AT ( ADDR (.text) + SIZEOF (.text) )
        { *(.data) }

这意味着数据部分现在具有不同的 LMA 和 VMA(加载内存地址/虚拟内存地址)。您的程序将期望在 VMA(运行时地址)找到数据,但数据实际上存在于 LMA(您可能必须教您的 flasher 这样做),它就在 .text 之后。部分。

如果您需要弄清楚复制到哪里和从哪里复制,那么您可以在链接描述文件中创建指针。因此,像这样修改上面的例子:
.data : AT ( ADDR (.text) + SIZEOF (.text) )
        { _data_lma = LOADADDR(.data); _data_vma = .;
          *(.data);
          _data_size = SIZEOF (.data);}

然后你可以做 memcpy (_data_vma, _data_lma, _data_size)在您的启动代码中(尽管您可能需要在汇编程序中手动编写代码?)这些符号将作为在链接时解析的常量全局变量出现在您的程序中。因此,在您的汇编代码中,您可能有以下内容:
_data_lma_k:
   .long _data_lma

然后数字将被硬编码到 .text部分。当然,汇编器语法在您的平台上可能会有所不同。

有关更多信息,请参阅链接器手册 here

关于gcc - 我怎么知道 .data 部分需要从哪里获取 init 数据? (gcc 链接器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9288822/

相关文章:

c - 基于麦克风输入的 PWM 信号生成

linux - 在 GDB 中使用 ptype 显示所有 C++ 数据字段(甚至是继承的)

c++ - 您将如何列出已编译库中包含的可用函数等?

c++ - gcc - 如何找到头文件包含文件的路径

linux - 使用 as 和 ld 在 x86-64 Linux 上汇编和运行 i386 asm 程序

c++ - 如何不链接 msvcr100.dll?

将整数数组转换为字符数组,每个整数每 3 位

c - 使用 Atmel 89C2051 微 Controller 开发固件应用程序需要哪些软件?

c++ - 为什么此代码为 std::hash 模板的 **ALL** 枚举提供特化?

c++ - "array bound is not an integer constant"在运行时创建结构