开发者

LD linker: Target address aligning but not address in ROM

I have a program that's resident in flash and will run from flash. Early in the program data segments are copied from flash to ram. I'm using a linker script like (simplified):

.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__ = .);

I want the sections to be aligned on 4-byte boundaries (architecture is PowerPC 32-bit). Some of the data sections include sub-word items. I'm finding that the ALIGN instruction aligns the VMA address in RAM but doesn't align the LMA. So my copy-to-ram routine fails because the two areas don't correspond byte-for-byte.

My copy routine looks like

r3 = address in flash of开发者_StackOverflow社区 _etext
r4 = address in ram of __COPY_DATA_START__
words to copy = (__END_COPY__ - COPY_DATA_START) / 4

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

When the loop gets to an aligned bit, the destination points to some pad bytes, but the source data doesn't include the align-padding so the data gets put too early in memory.

I can tell this from the map file because it looks like (contrived example)

.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

Does anyone know the solution to this problem?

Thank you

Chris


I've had some success by using a different form of the "AT" linker script command. If I use

  _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 

Then it seems to align as I would expect. The SIZEOF( ) + SIZEOF( ) ... string gets pretty long by the end of the file but at least it works.

(Additional info: Normally you wouldn't copy the rodata section into ram because it's read only. On my system the flash can't handle the kind of accesses requured for floating point constants, so I do need to copy it into RAM even though it won't be modified).


It does not appear that you stated which linker you are using, but your script looks like a GNU linker script (so I will assume it is). To align both the VMA and LMA of a section using a GNU linker script do something like this...

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

.section_name is the name of the output section to align, and can be any legal name. The ALIGN statement on the left of the colon affects the VMA alignment, and the ALIGN statement on the right of the colon affects the LMA alignment. In your case you want vma_alignment = lma_alignment = 4. See section 3.6.1 of the GNU Linker reference manual.

So your overall script should look like the one below...

.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__ = .);

And your copy routine would look like...

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--
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜