3

问题

我的问题是,当我使用以下旨在将代码放入 RAM 的脚本时,重定位部分会充满虚假数据。

我的问题是:

  1. 为什么_srelocate符号比符号大 4 个字节_etext?他们不应该是一样的吗?

  2. 另外,如果 1. 的答案是否定的,我不应该从_etext + 4to复制_srelocate吗?

背景及相关代码

我正在使用 Atmel ATSAM3N4X 系列处理器(ARM Cortex M3),希望对我的链接器脚本和.relocate部分初始化有所帮助。

原因是_etext符号比_srelocate符号少 4 个字节。

以下链接描述文件是 Atmel Studio 6 生成的默认脚本(如果您想要ram/rom符号位置,请参阅问题的附录)。

/* ----------------------------------------------------------------------------
 *         SAM Software Package License
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/* Section Definitions */
SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _sfixed = .;
        KEEP(*(.vectors .vectors.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
        *(.ARM.extab* .gnu.linkonce.armextab.*)

        /* Support C constructors, and C destructors in both user code
           and the C library. This also provides support for C++ code. */
        . = ALIGN(4);
        KEEP(*(.init))
        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;

        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        __init_array_end = .;

        . = ALIGN(0x4);
        KEEP (*crtbegin.o(.ctors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
        KEEP (*(SORT(.ctors.*)))
        KEEP (*crtend.o(.ctors))

        . = ALIGN(4);
        KEEP(*(.fini))

        . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;

        KEEP (*crtbegin.o(.dtors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
        KEEP (*(SORT(.dtors.*)))
        KEEP (*crtend.o(.dtors))

        . = ALIGN(4);
        _efixed = .;            /* End of text section */
    } > ram

    . = ALIGN(4);
    _etext = .;

    .relocate : AT (_etext)
    {
        . = ALIGN(4);
        _srelocate = .;
        *(.ramfunc .ramfunc.*);
        *(.data .data.*);
        . = ALIGN(4);
        _erelocate = .;
    } > ram

    /* .bss section which is used for uninitialized data */
    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        _sbss = . ;
        _szero = .;
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = . ;
        _ezero = .;
    } > ram

    /* stack section */
    .stack (NOLOAD):
    {
        . = ALIGN(8);
        _sstack = .;
        . = . + STACK_SIZE;
        . = ALIGN(8);
        _estack = .;
    } > ram

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    PROVIDE_HIDDEN (__exidx_start = .);
    .ARM.exidx :
    {
      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > ram
    PROVIDE_HIDDEN (__exidx_end = .);

    . = ALIGN(4);
    _end = . ;
}

我曾经nm查看过符号值是什么,并将它们包括在下面:

2000115c A _etext
20001160 D _srelocate
200015c8 D _erelocate

现在,Atmel Studio 6 自动生成了我的项目,并给了我一个Reset_Handler()复制该.relocate部分的内容_etext_srelocate清除该.bss部分。该项目带有两个链接器脚本,一个用于基于 FLASH 的执行,一个用于基于 RAM 的代码。默认是基于 FLASH 的代码,但我将其更改为基于 RAM 的链接器脚本(上面提供),然后遇到了问题。

将部分从 FLASH复制.relocate到 RAM 的初始化代码也是自动生成的,我在更改链接器脚本时没有更改它。它看起来像这样:

void Reset_Handler(void)
{
    uint32_t *pSrc, *pDest, Size;

    /* Initialize the relocate segment */
    pSrc = &_etext;
    pDest = &_srelocate;

    if (pSrc != pDest) {
        for (; pDest < &_erelocate;) {
            *pDest++ = *pSrc++;
        }
    }

    /* Clear the zero segment */
    for (pDest = &_szero; pDest < &_ezero;) {
        *pDest++ = 0;
    }

    /* Set the vector table base address */
    pSrc = (uint32_t *) & _sfixed;
    SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);

    if (((uint32_t) pSrc >= IRAM_ADDR) && ((uint32_t) pSrc < IRAM_ADDR + IRAM_SIZE)) {
        SCB->VTOR |= (1UL) << SCB_VTOR_TBLBASE_Pos;
    }

    /* Initialize the C library */
    __libc_init_array();

    /* Branch to main function */
    main();

    /* Infinite loop */
    while (1);
}

编辑1:

使用objdump -t CodeFile.elf > CodeFile.symbols,我在我的.relocate部分的开头找到了这个符号,这似乎表明它_srelocate并不真正指向.relocate.

    2000115c g     O .relocate  00000000 .hidden __TMC_END__

这个符号是什么?

我查了一下并在 GCC 4.7 中发现了这个错误,但无法确定它在我的版本中是否已修复。

我的编译器是arm-none-eabi-gcc并且将它的版本声明为4.7.0...链接器是arm-none-eabi-ld并且它的版本是2.22

编辑2:

我已经对此进行了一些研究,并记录在我提出的这个相关的 SO 问题中。请同时查看它,因为它解释了问题是GCC 错误

附录

链接描述文件的内存布局

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/* Memory Spaces Definitions */
MEMORY
{
    rom (rx)  : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00006000 /* sram, 24K */
}

/* The stack size used by the application. NOTE: you need to adjust  */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : 0x800 ;
4

2 回答 2

3

我很久以前就发现了我自己问题的答案,但在我的编辑中似乎仍然有点不清楚,所以请允许我在这里将其正式化。

问题是由于GCC 中的错误,链接器在 my和符号之间插入了一个额外的TMC_END符号,占用了 4 个字节。这是不正确的,因为这个符号与我正在编写的代码无关,我什至没有使用这个功能。我在另一个 SO question中发现并解释了这一点。_etext_srelocate

解决方法:

正确地,Atmel 的示例代码假设如果您的代码用完闪存,您的_srelocate符号地址和_etext符号地址将不同,一个地址以 . 开头,另一个地址0x004...0x20....

如果您的代码用完了 RAM,这意味着您有一个引导加载程序,它将相关部分复制到正确的内存位置,因此_etext符号的地址也将驻留在 RAM 中并等于_srelocate符号的地址。

因此,Atmel 试图确保该_srelocate部分始终驻留在 RAM 中。

由于 GCC 中的错误,解决方案是更改代码以检查_srelocate符号的地址是否已经在 RAM 中,如下所示:

// I can't remember what #define Atmel has for SRAM so I'm just going to
// use this one for the purposes of my example.
#define SRAM_START_ADDRESS 0x20000000

void Reset_Handler(void)
{
    uint32_t *pSrc, *pDest, Size;

    /* Initialize the relocate segment */
    pSrc = &_etext;      // Could either be in Flash or SRAM depending on your configuration.
    pDest = &_srelocate; // Always in SRAM or there's something strange going on...

    if ((intptr_t)pSrc < (intptr_t)SRAM_START_ADDRESS) { // <<<< Changed code here <<<<
        // We enter here only if pSrc is pointing to a location in Flash.
        // If that's the case, we need to copy the memory from Flash to SRAM.
        for (; pDest < &_erelocate;) {
            *pDest++ = *pSrc++;
        }
    }

    /* Clear the zero segment */
    for (pDest = &_szero; pDest < &_ezero;) {
        *pDest++ = 0;
    }

    /* Set the vector table base address */
    pSrc = (uint32_t *) & _sfixed;
    SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);

    if (((uint32_t) pSrc >= IRAM_ADDR) && ((uint32_t) pSrc < IRAM_ADDR + IRAM_SIZE)) {
        SCB->VTOR |= (1UL) << SCB_VTOR_TBLBASE_Pos;
    }

    /* Initialize the C library */
    __libc_init_array();

    /* Branch to main function */
    main();

    /* Infinite loop */
    while (1);
}

这适用于我的情况。据我所知,此错误已修复,并且该修复已恢复,因此您不太可能在 Atmel Studio 中修复它。

于 2014-08-08T01:34:22.483 回答
0

我不确定这是否是您的问题,但如果您使用 SAM-BA 将代码复制到 SRAM,SAM-BA 引导程序将 SRAM 的前 2048 (0x800) 字节用于变量及其堆栈。也许这就是为什么您的重定位部分被踩在脚下的原因(当您复制代码时,ISR 和其他代码仍在运行,这些需要自己的 SRAM)。

由于这个原因,所有 SAM-BA 小程序示例都被复制到 0x20000800。

我不知道除了实现类似于 SAM-BA 的东西之外,您还会如何将代码放在 SRAM 中,在这种情况下,您还需要自己的 SRAM 部分来存储数据。

这是 SAM4S16 部分的小程序的链接描述文件:

/* ----------------------------------------------------------------------------
 *         SAM Software Package License
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/*------------------------------------------------------------------------------
 *      Linker script for running in internal SRAM on the SAM4S16
 *----------------------------------------------------------------------------*/

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

/* Memory Spaces Definitions */
MEMORY
{
    romcodesram (W!RX) : ORIGIN = 0x20000000, LENGTH = 0x800
    sram (W!RX) : ORIGIN = 0x20000800, LENGTH = 0x0001F800 /* sram, 128K - sizeof(romcodesram) */
}

SECTIONS
{
    /* startup code in the .isr_vector */
    .text :
    {
        . = ALIGN(4);
        _stext = .;
        KEEP(*(.isr_vector .isr_vector.*))
        *(.mailbox)
        *(.text .text.*)
        *(.rodata .rodata.*)
        *(.ramfunc .ramfunc.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.rodata .rodata*)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
    } > sram

    /* data */
    .data :
    {
        . = ALIGN(4);
        _sidata = .;
        _sdata = .;

        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = .;
    } > sram

    .bss (NOLOAD) : {
        _szero = .;
        *(.bss)
        . = ALIGN(4);
        _ezero = .;
    } >sram

    /* Stack in SRAM */
    _sstack = 0x2001FFF0;
}
. = ALIGN(4);
end = .;
于 2014-08-05T15:27:58.200 回答