链接器脚本.relocate部分的第一个符号_srelocate是不正确的(GCC Bug?)

问题

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

我的问题是:

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

  2. 另外,如果1.的答案为NO,我不应该从_etext + 4复制到_srelocate吗?

背景和相关代码

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

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

以下链接描述文件是Atmel Studio 6生成的默认脚本(如果您希望ram / rom符号位置看到问题的Apendix )。

 /* ---------------------------------------------------------------------------- * 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的链接器脚本(上面提供),并遇到了问题。

.relocate部分从FLASH复制到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 VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); if (((uint32_t) pSrc >= IRAM_ADDR) && ((uint32_t) pSrc 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并将其版本arm-none-eabi-gcc4.7.0 …链接器是arm-none-eabi-ld ,其版本是2.22

编辑2:

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

Apendix

链接描述文件的内存布局

 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 ; 

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

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

解决方法:

Atmel的示例代码正确地假设,如果您的代码耗尽闪存, _srelocate符号的地址和_etext符号的地址将不同,一个地址以0x004...开头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中修复它。

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

因此,所有SAM-BA applet示例都被复制到0x20000800。

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

以下是SAM4S16部件的applet的链接描述文件:

 /* ---------------------------------------------------------------------------- * 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 = .;