LD链接器:目标地址对齐但不是ROM中的地址

时间:2009-11-13 14:58:23

标签: embedded linker

我有一个驻留在flash中的程序,它将从flash运行。在程序的早期,数据段从flash复制到ram。我正在使用像(简化)这样的链接器脚本:

.text      :
{
  *(.text)
} > FLASH
_etext = .;
PROVIDE (etext = .);

.rodata     :
{
  PROVIDE(__COPY_DATA_START__ = .); 
  *(.rodata) 
} > ram AT>flash

PROVIDE (__SDATA2_START__ = .);
.sdata2   :
{ 
  *(.sdata2)
} > ram AT>flash

PROVIDE (__sbss2_start = . );
.sbss2   : { 
  *(.sbss2) 
  . = ALIGN(4)
} > ram AT>flash
PROVIDE (__sbss2_end = . );
PROVIDE (__SBSS2_END__ = .);

.data    :
{
  *(.data)
  *(.gnu.linkonce.d*)
  CONSTRUCTORS
  *(.eh_frame)
} > ram AT>flash
PROVIDE (__END_COPY__ = .);

我希望这些部分在4字节边界上对齐(架构是PowerPC 32位)。一些数据部分包括子词项。我发现ALIGN指令对齐RAM中的VMA地址但没有对齐LMA。所以我的copy-to-ram例程失败了,因为这两个区域不是逐字节对应的。

我的复制程序看起来像

r3 = address in flash of _etext
r4 = address in ram of __COPY_DATA_START__
words to copy = (__END_COPY__ - COPY_DATA_START) / 4

while (words to copy)
  * r4++ = *r3++

当循环到达对齐位时,目标指向一些填充字节,但源数据不包括对齐填充,因此数据在内存中放得太早。

我可以从地图文件中看出这个,因为它看起来像(人为的例子)

.rodata         0x00000000      0xb15 load address 0xfff13000
                0x00000000                PROVIDE (__COPY_DATA_START__, .)

.sdata          0x00000b18      0x10  load address 0xfff13b15  <<< origin 0xb18 is aligned but load address hasn't moved on by the padding bytes

有谁知道这个问题的解决方案?

谢谢

克里斯

2 个答案:

答案 0 :(得分:3)

通过使用不同形式的“AT”链接器脚本命令,我获得了一些成功。如果我使用

  _etext = .;
  PROVIDE (etext = .);
  .rodata : AT (_etext)
  { 
... contents of section ...
  }

  .sdata2 : AT (_etext + SIZEOF(.rodata) + SIZEOF(.gcc_except_table))
  { 
... contents of section ...
  } > ram

  .sbss2 : AT (_etext + SIZEOF(.rodata) + SIZEOF(.gcc_except_table) + SIZEOF(.sdata2) )
  { 
... contents of section ...
    . = ALIGN(16);
  } > ram 

然后它看起来像我期望的那样对齐。 <{1}}字符串在文件末尾变得很长,但至少可以正常工作。

(附加信息:通常你不会将rodata部分复制到ram中,因为它是只读的。在我的系统上,flash无法处理浮点常数所需的访问类型,所以我需要将它复制到RAM,即使它不会被修改)。

答案 1 :(得分:-1)

您似乎没有说明您正在使用哪个链接器,但您的脚本看起来像GNU链接器脚本(所以我假设它是)。要使用GNU链接器脚本对齐节的VMA和LMA,请执行以下操作...

.section_name ALIGN( vma_alignment ) : ALIGN( lma_alignment ){
  ...section contents
}

.section_name是要对齐的输出节的名称,可以是任何合法名称。冒号左侧的ALIGN语句影响VMA对齐,冒号右侧的ALIGN语句影响LMA对齐。在您的情况下,您需要vma_alignment = lma_alignment = 4.请参阅GNU Linker参考手册的第3.6.1节。

所以你的整体脚本应该如下所示......

.text      :
{
  *(.text)
} > FLASH
_etext = .;
PROVIDE (etext = .);

.rodata ALIGN(4)  : ALIGN(4)
{
  PROVIDE(__VMA_COPY_DATA_START__ = ADDR(.rodata)); /*The runtime address of .rodata*/
  PROVIDE(__LMA_COPY_DATA_START__ = LOADADDR(.rodata)); /*The load address of .rodata*/

  *(.rodata) 
} > ram AT>flash

PROVIDE (__SDATA2_START__ = .);
.sdata2   :
{ 
  *(.sdata2)
} > ram AT>flash

PROVIDE (__sbss2_start = . );
.sbss2   : { 
  *(.sbss2) 
  . = ALIGN(4)
} > ram AT>flash
PROVIDE (__sbss2_end = . );
PROVIDE (__SBSS2_END__ = .);

.data    :
{
  *(.data)
  *(.gnu.linkonce.d*)
  CONSTRUCTORS
  *(.eh_frame)
} > ram AT>flash
 /*
 *align address so that (__END_COPY__ -  __VMA_COPY_DATA_START__) / 4 does not round down.
 *If alignment is not done then the copy routine could potentially drop up to 3 bytes at 
 *the end of the .data section if the section does not end on a multiple of 4 bytes.
 */
. = ALIGN(4)
PROVIDE (__END_COPY__ = .);

你的复制例程看起来像......

r3 = address in flash of __LMA_COPY_DATA_START__
r4 = address in ram of   __VMA_COPY_DATA_START__
words_to_copy = (__END_COPY__ -  __VMA_COPY_DATA_START__) / 4

while (words_to_copy){
  * r4++ = *r3++
  words_to_copy--
}