是否允许写入链接器文件中未定义的部分?

Is writing to a section not defined in linker file allowed?

在我的链接器文件中,我有以下内存部分。

MEMORY
{
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k

    mram (rwx) : ORIGIN = 0xA0000010, LENGTH = 1M
}

mram外设的实际地址从0xA0000000开始。在 C 文件中,我可以写入特定的内存地址

 (*(uint32_t *)(void *)0xA0000000) = 0xaabbccdd;

这会造成任何问题吗?

链接描述文件中指定的 space 定义了链接器可以在定义的内存区域中定位的位置和内容。它不会在您留在 0xA0000000 to 0xA000000F 的“洞”中找到任何东西,因为它不知道它。

从这个意义上说,它是“安全的”,因为链接器不会尝试使用那个 space。它完全由您的代码控制——您已通过不将其交给链接器来对该区域负责。确实声明:

(*(uint32_t *)(void *)0xA0000000) = 0xaabbccdd;

将向该位置写入一个 32 位值。关键是编译器和链接器都不会阻止您在该区域执行您将要执行的操作。

不太合理的是LENGTH = 1M。这将使您的 mram 0x100010 字节长(即 1M + 0x10)。这是一个问题,因为链接器可以自由地在区域 0x1000000x10000F 中定位对象。其后果取决于您的硬件,但很可能它会包装到您试图对链接器隐藏的区域 0x100000 to 0x10000F 中。我想你需要 LENGTH = 1M - 0x10LENGTH = 0x0FFFF0.

现在虽然您可以免除链接器管理该区域以便在您的代码中对其进行管理,但这可能不是最佳方法。最好在所需的绝对地址处创建一个链接器符号。

所以给出:

MEMORY
{
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k

    mram (rwx) : ORIGIN = 0xA0000000, LENGTH = 1M
} 

您将在 mram 中创建链接器符号:

SECTIONS
{
    ...

    .mram :
    {
        reserved_mram = 0 ; /* address is zero offset from .mram1 */
        . += 0x10 ;         /* create 16 byte "hole" at address reserved_mram */

        ...  /* other mram linker assignment follows */

    } < mram

    ...
}

那么在你的代码中你应该能够声明:

extern uint32_t reserved_mram[] ;  // 4 x 32-bit word array.

并且通过 reserved_mram 您可以象征性地访问 0xA00000000 处的内存,并且代码始终与链接描述文件同步,因此您可以轻松地重新定位 space 而不会引入冲突。

当然没有边界检查,也没有大小信息 - 您仍然需要将对 reserved_mram[0] 的访问限制为 reserved_mram[3]

您也可以为每个位置创建一个单独的符号(具有特定于您的应用程序的有意义的名称):

    .mram :
    {
        reserved_mram1 = 0 ;
        . += 4 ;
        reserved_mram2 = . ;
        . += 4 ;
        reserved_mram3 = . ;
        . += 4 ;
        reserved_mram4 = . ;
        . += 4 ;

        ...  /* other mram linker usage follows */

    } < mram

然后在你的代码中:

extern uint32_t reserved_mram1 ;
extern uint32_t reserved_mram2 ;
extern uint32_t reserved_mram3 ;
extern uint32_t reserved_mram4 ;

另一种选择;您可以为该区域创建一个独立的部分,然后在代码中使用 __attribute__((section(.xxx))) 指令在其中创建变量。例如:

MEMORY
{
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k

    mram1 (rwx) : ORIGIN = 0xA0000000, LENGTH = 0x10
    mram2 (rwx) : ORIGIN = 0xA0000010, LENGTH = 0xFFFF0
} 

SECTIONS
{
    ...

    .mram1 :
    {
        *(.mram1) 
    } < mram1

    ...
}

然后在你的代码中:

uint32_t my_mram_data __attribute__ ((section (".mram1"))) ;

变量 my_mram_data 将在 某处 .mram1 中创建,但链接器决定在哪里。这里的优点是您可以在代码中创建任意变量而无需修改链接器脚本,如果您尝试分配给 .mram1 比可用数据更多的数据,您将收到链接器错误。

请注意,链接描述文件的语法是神秘的,并且在链接器之间有所不同 - 我不认为这与 GNU 链接器有关?但是我的链接器 foo 是严格 按需 (即我在需要的时候弄清楚)并且我没有声称以上任何一个是完整或正确的,甚至是唯一可能的解决方案- 将其视为说明性的,并参考链接器文档以获取准确信息。