Embedded LD链接器:目标地址对齐,但不是ROM中的地址
我有一个驻留在flash中的程序,它将从flash运行。在程序的早期,数据段从闪存复制到ram。我使用的链接器脚本如下(简化): 我希望各部分在4字节边界上对齐(体系结构为PowerPC 32位)。一些数据部分包括子单词项。我发现ALIGN指令与RAM中的VMA地址对齐,但没有与LMA对齐。因此,我的复制到ram例程失败,因为这两个区域没有逐字节对应 我的复印程序看起来像Embedded LD链接器:目标地址对齐,但不是ROM中的地址,embedded,linker,Embedded,Linker,我有一个驻留在flash中的程序,它将从flash运行。在程序的早期,数据段从闪存复制到ram。我使用的链接器脚本如下(简化): 我希望各部分在4字节边界上对齐(体系结构为PowerPC 32位)。一些数据部分包括子单词项。我发现ALIGN指令与RAM中的VMA地址对齐,但没有与LMA对齐。因此,我的复制到ram例程失败,因为这两个区域没有逐字节对应 我的复印程序看起来像 r3 = address in flash of _etext r4 = address in ram of __COPY_
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++
当循环到达对齐位时,目标指向一些pad字节,但源数据不包括对齐填充,因此数据过早地放入内存
我可以从映射文件中看出这一点,因为它看起来像(人为的示例)
.rodata 0x00000000 0xb15加载地址0xfff13000
0x00000000提供(复制数据开始)
.sdata 0x00000b18 0x10加载地址0xfff13b15通过使用不同形式的“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中,因为它是只读的。在我的系统上,闪存无法处理浮点常量所需的访问类型,因此我确实需要将其复制到ram中,即使它不会被修改)。您似乎没有说明正在使用哪个链接器,但是您的脚本看起来像GNU链接器脚本(所以我假设它是)。要使用GNU链接器脚本对齐节的VMA和LMA,请执行以下操作
.section_name ALIGN( vma_alignment ) : ALIGN( lma_alignment ){
...section contents
}
.section_name是要对齐的输出节的名称,可以是任何合法名称。冒号左侧的ALIGN语句影响VMA对齐,冒号右侧的ALIGN语句影响LMA对齐。在您的情况下,您希望vma_校准=lma_校准=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--
}
这个答案是错误的。结肠后的对齐(x)未设置LMA对齐。我刚刚用binutils 2.25试过了。
.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--
}