根据ld手册上的特殊符号.
,即Location Counter。
笔记: 。实际上指的是距当前包含对象开头的字节偏移量。通常这是 SECTIONS 语句,其起始地址为 0,因此 . 可以用作绝对地址。如果 。然而,它在节描述中使用,它指的是从该节开始的字节偏移量,而不是绝对地址。因此在这样的脚本中:
Run Code Online (Sandbox Code Playgroud)SECTIONS { . = 0x100 .text: { *(.text) . = 0x200 } . = 0x500 .data: { *(.data) . += 0x600 } }
即使“.text”输入节中没有足够的数据来填充该区域,“.text”节也将被分配起始地址 0x100 和正好 0x200 字节的大小。
ld 手册还提到了输出部分的 VMA 和 LMA:
每个可加载或可分配的输出部分都有两个地址。第一个是 VMA,即虚拟内存地址。这是运行输出文件时该节将具有的地址。第二个是 LMA,或加载内存地址。这是该部分将被加载的地址。在大多数情况下,两个地址是相同的。它们可能不同的一个例子是,当程序启动时,数据部分被加载到 ROM 中,然后复制到 RAM 中(此技术通常用于初始化基于 ROM 的系统中的全局变量)。在这种情况下,ROM 地址将是 LMA,RAM 地址将是 VMA。
所以我的问题是:
如果使用不同的 VMA 和 LMA 指定输出节,则字节偏移的基地址是多少.
?
在下面的示例中,该.data
部分具有不同的 VMA 和 LMA。我的理解是PLACE 1
指定LMA
是在ROM2
,而PLACE 2
指定VMA
是在RAM
?.
那么该部分中符号的基地址是多少.data
?
SECTIONS
{
.text :
{
*(.text)
} > REGION_TEXT
.rodata :
{
*(.rodata)
rodata_end = .;
} > REGION_RODATA
.data : AT (rodata_end) <=========== PLACE 1
{
data_start = .;
*(.data)
} > REGION_DATA <=========== PLACE 2
data_size = SIZEOF(.data);
data_load_start = LOADADDR(.data);
.bss :
{
*(.bss)
} > REGION_BSS
}
Run Code Online (Sandbox Code Playgroud)
内存布局如下:
MEMORY
{
ROM : ORIGIN = 0, LENGTH = 2M /*0M ~ 2M*/
ROM2 : ORIGIN = 0x10000000, LENGTH = 1M /*256M ~ 257M*/
RAM : ORIGIN = 0x20000000, LENGTH = 1M /*512M ~ 513M*/
}
REGION_ALIAS("REGION_TEXT", ROM); /*0M ~ 2M*/
REGION_ALIAS("REGION_RODATA", ROM2); /*256M ~ 257M*/
REGION_ALIAS("REGION_DATA", RAM); /*512M ~ 513M*/
REGION_ALIAS("REGION_BSS", RAM); /*512M ~ 513M*/
Run Code Online (Sandbox Code Playgroud)
要回答您的问题,可以利用官方ld
文档中的两个事实。
来自输出部分 LMA 的第一个事实。
\n\n\n\n\n以下链接器脚本创建三个输出节:一个称为\n
\n.text
,从 开始0x1000
,一个称为\n ,即使其VMA 为,也会.mdata
在该节的末尾加载\n ,以及\n 一个调用以保存地址 处的未初始化数据。符号由值 定义,这表明位置计数器保存的是 VMA 值,而不是 LMA 值。.text
0x2000
.bss
0x3000
_data
0x2000
SECTIONS\n {\n .text 0x1000 : { *(.text) _etext = . ; }\n .mdata 0x2000 :\n AT ( ADDR (.text) + SIZEOF (.text) )\n { _data = . ; *(.data); _edata = . ; }\n .bss 0x3000 :\n { _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}\n }\n
Run Code Online (Sandbox Code Playgroud)\n\n来自位置计数器的第二个事实。
\n\n\n\n\n。实际上指的是距当前包含 object 的开头的字节偏移量。通常这是一条
\nSECTIONS
语句,其起始地址为0
,因此.
可以用作绝对地址。但是,如果.
在节描述内使用 \n,则它指的是距该节开头的字节\n 偏移量,而不是绝对地址。
将这两条信息放在一起,可以说位置计数器通过给出其距当前包含对象(SECTIONS
语句或输出节)的起始地址的偏移量来指定 VMA 值。
所以位置计数器的绝对基地址是
\n\nSECTIONS
为\xe2\x80\x930
.
.
节内部引用\n)至于.data
您示例中的部分,您\xe2\x80\x99是正确的:PLACE 1
指定LMA位于ROM2
,同时PLACE 2
指定VMA位于RAM
.
由于位置计数器在节描述内使用时,指的是距该节开头的字节偏移量,因此.
该节内符号的基地址.data
为0
。然而,这是一个相对地址,它对应于绝对地址,0x20000000
即该.data
部分的 VMA。顺便说一句,这与上述指定PLACE 2
VMA 位于RAM
内存区域(别名REGION_DATA
)的事实是一致的。
\n如果您的示例是真实的,您可以通过使用ADDR(section)
链接器脚本语言内置函数获取该.data
部分的 VMA 来轻松检查刚才所说的内容。
归档时间: |
|
查看次数: |
3173 次 |
最近记录: |