2009-11-13 85 views
2

我有一個駐留在閃存中的程序,它將從閃存運行。在程序的早期,數據段從閃存複製到RAM。我使用像鏈接腳本(簡化):LD鏈接器:目標地址對齊但不是ROM中的地址

.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。所以我的副本到內存例程失敗,因爲這兩個區域不對應字節對字節。

我的副本日常的樣子

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 

有誰知道解決這個問題?

謝謝

克里斯

回答

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 

然後它似乎與我預期的一致。在文件結尾處,SIZEOF() + SIZEOF() ...字符串變得相當長,但至少可以工作。 (附加信息:通常你不會將rodata部分複製到RAM中,因爲它是隻讀的。在我的系統上,flash無法處理浮點常量所需的訪問類型,所以我需要將其複製到RAM中,即使它不會被修改)。

-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鏈接器參考手冊的第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-- 
} 
+0

這個答案是錯的。冒號後的ALIGN(x)確實_NOT_設置LMA對齊。我剛剛用binutils 2.25試過。 – Sven 2015-03-28 13:03:27