GNU 链接器 ARM - 为什么我的部分重叠?

GNU linker ARM - why my sections overlap?

我需要添加一个小堆以在 TM4C ARM 微控制器上使用标准库函数(_sbrk 需要 end 符号)。

这是我的 linker 脚本(带有微控制器演示):

/* Entry Point */
ENTRY(Reset_Handler)

HEAP_SIZE = 1024;

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}

SECTIONS
{
    .text :
    {
        _text = .;
        KEEP(*(.isr_vector))
        *(.text*)
        *(.rodata*)
        _etext = .;
    } > FLASH

    .data : AT(ADDR(.text) + SIZEOF(.text))
    {
        _data = .;
        _ldata = LOADADDR (.data);
        *(vtable)
        *(.data*)
        _edata = .;
    } > SRAM

    .bss :
    {
        _bss = .;
        *(.bss*)
        *(COMMON)
        _ebss = .;
    } > SRAM

    .heap : AT(ADDR(.bss) + SIZEOF(.bss))
    {
        . = ALIGN(8);
        __end__ = .;
        PROVIDE(end = .);
        __HeapBase = .;
        . += HEAP_SIZE;
        __HeapLimit = .;
    } > SRAM
}

我只在 .bss 之后添加了 .heap 类似于 .data/.text 但我得到 link 错误:

ld: section .init loaded at [000126b4,000126bf] overlaps section .data loaded at [000126b4,00012f8f]
collect2: error: ld returned 1 exit status

当我删除 AT(ADDR(.bss) + SIZEOF(.bss)) 时也会发生这种情况。当我删除 .heap 并调用 libc 函数时,一切都会编译并且 links,输出二进制文件运行正确。

我应该如何调整脚本以在 bss 之后正确放置堆?

事实证明我的堆和 bss 是正确的,但是在链接标准库函数时添加了名为 .init 和 .fini 的新部分 - 它们与 .data 冲突。这是我更正后的链接描述文件:

/* Entry Point */
ENTRY(Reset_Handler)

HEAP_SIZE = 1024;

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}

SECTIONS
{
    .text :
    {
        _text = .;
        KEEP(*(.isr_vector))
        *(.text*)
        *(.rodata*)
        KEEP (*(.init))
        KEEP (*(.fini))
        _etext = .;
    } > FLASH

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > FLASH

    .ARM :
    {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
    } > FLASH

    __end_code = .;

    .data : AT(__end_code)
    {
        _data = .;
        _ldata = LOADADDR (.data);
        *(vtable)
        *(.data*)
        _edata = .;
    } > SRAM

    .bss :
    {
        _bss = .;
        *(.bss*)
        *(COMMON)
        _ebss = .;
    } > SRAM

    .heap : AT(_ebss)
    {
        . = ALIGN(8);
        __end__ = .;
        PROVIDE(end = .);
        __HeapBase = .;
        . += HEAP_SIZE;
        __HeapLimit = .;
    } > SRAM
}

我添加了行 KEEP (*(.init))KEEP (*(.fini)).ARM 部分(来自另一个 MCU 链接描述文件)。现在一切都链接并运行良好。

如果您使用的是 TivaWare 库,我建议您使用在 Code Composer 中创建相应项目时生成的链接描述文件。您可以将其复制到您的项目中。例如,对于 tm4c123glx launchpad 评估板上的处理器,名称将为 tm4C123gh6pm.lds。我会把它贴在这里:

/******************************************************************************
 *
 * Default Linker script for the Texas Instruments TM4C123GH6PM
 *
 * This is derived from revision 15071 of the TivaWare Library.
 *
 *****************************************************************************/

MEMORY
{
    FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00040000
    SRAM (WX)  : ORIGIN = 0x20000000, LENGTH = 0x00008000
}

REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_BSS", SRAM);
REGION_ALIAS("REGION_DATA", SRAM);
REGION_ALIAS("REGION_STACK", SRAM);
REGION_ALIAS("REGION_HEAP", SRAM);
REGION_ALIAS("REGION_ARM_EXIDX", FLASH);
REGION_ALIAS("REGION_ARM_EXTAB", FLASH);

SECTIONS {

    PROVIDE (_intvecs_base_address = 0x0);

    .intvecs (_intvecs_base_address) : AT (_intvecs_base_address) {
        KEEP (*(.intvecs))
    } > REGION_TEXT

    PROVIDE (_vtable_base_address = 0x20000000);

    .vtable (_vtable_base_address) : AT (_vtable_base_address) {
        KEEP (*(.vtable))
    } > REGION_DATA

    .text : {
        CREATE_OBJECT_SYMBOLS
        *(.text)
        *(.text.*)
        . = ALIGN(0x4);
        KEEP (*(.ctors))
        . = ALIGN(0x4);
        KEEP (*(.dtors))
        . = ALIGN(0x4);
        __init_array_start = .;
        KEEP (*(.init_array*))
        __init_array_end = .;
        *(.init)
        *(.fini*)
    } > REGION_TEXT

    PROVIDE (__etext = .);
    PROVIDE (_etext = .);
    PROVIDE (etext = .);

    .rodata : {
        *(.rodata)
        *(.rodata*)
    } > REGION_TEXT

    .data : ALIGN (4) {
        __data_load__ = LOADADDR (.data);
        __data_start__ = .;
        *(.data)
        *(.data*)
        . = ALIGN (4);
        __data_end__ = .;
    } > REGION_DATA AT> REGION_TEXT

    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    } > REGION_ARM_EXIDX

    .ARM.extab : {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > REGION_ARM_EXTAB

    .bss : {
        __bss_start__ = .;
        *(.shbss)
        *(.bss)
        *(.bss.*)
        *(COMMON)
        . = ALIGN (4);
        __bss_end__ = .;
    } > REGION_BSS

    .heap : {
        __heap_start__ = .;
        end = __heap_start__;
        _end = end;
        __end = end;
        KEEP(*(.heap))
        __heap_end__ = .;
        __HeapLimit = __heap_end__;
    } > REGION_HEAP

    .stack : ALIGN(0x8) {
        _stack = .;
        __stack = .;
        KEEP(*(.stack))
    } > REGION_STACK
}

然后确保您的启动代码初始化了正确的部分(您还将获得一个名为 tm4c123gh6pm_startup_ccs_gcc.c 的文件,其中包含启动代码,或者用作- 是或作为指南。

您会注意到它们在初始化各个部分所需的变量方面做得很好。避免了 user2162550 提出的问题。

顺便说一句 - 我注意到当使用 -O2 链接器错误编译时有点混淆 - 如果你的代码适合关闭它,直到你得到你想要的一切。