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--
}
精彩评论