我有一个驻留在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
有谁知道这个问题的解决方案?
谢谢
克里斯
答案 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--
}