根据ld手册on the special symbol .
, i.e.the Location Counter。
注意:。实际上是指从开始的字节偏移量 当前包含对象。通常这是SECTIONS声明, 因此,其起始地址为0。可以用作绝对地址。 如果。然而,在部分描述中使用它,它指的是 从该部分的开头起的字节偏移量,而不是绝对地址。 因此在这样的脚本中:
SECTIONS { . = 0x100 .text: { *(.text) . = 0x200 } . = 0x500 .data: { *(.data) . += 0x600 } }
' .text' section将被分配一个起始地址0x100和a 正好大小为0x200字节,即使数据中没有足够的数据 `.text区段'输入部分来填补这个区域。
ld手册也说output section's VMA and 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
}
内存布局如下:
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*/
答案 0 :(得分:2)
要回答您的问题,可以使用官方ld
文档中的两个事实。
来自Output Section LMA的第一个事实。
以下链接描述文件创建三个输出节:一个调用
.text
,从0x1000
开始,一个名为.mdata
,已加载 在.text
部分的末尾,即使其VMA为0x2000
,也是如此 一个名为.bss
的人在地址0x3000
处保留未初始化的数据。该 符号_data
定义为值0x2000
,表示 位置计数器保存VMA值,而不是LMA值。
SECTIONS
{
.text 0x1000 : { *(.text) _etext = . ; }
.mdata 0x2000 :
AT ( ADDR (.text) + SIZEOF (.text) )
{ _data = . ; *(.data); _edata = . ; }
.bss 0x3000 :
{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}
}
来自The Location Counter的第二个事实。
即可。实际上是指从当前开始的字节偏移量 包含对象。通常这是
SECTIONS
语句,其中 起始地址为0
,因此.
可用作绝对地址。如果.
然而,在部分描述中使用它,它指的是字节 偏离该部分的开头,而不是绝对地址。
将这两条信息放在一起,可以说位置计数器通过给出当前包含对象(SECTIONS
语句或输出部分)的起始地址的偏移量来指定VMA值。
所以位置计数器的绝对基地址是
SECTIONS
语句的起始地址 - 即0
- 如果我们在输出部分定义之外引用.
.
,则输出部分的VMA
那个输出部分对于您示例中的.data
部分,您是对的:PLACE 1
指定LMA位于ROM2
,而PLACE 2
指定VMA位于{{1} }}
由于位置计数器在部分描述中使用时,指的是从该部分开始的字节偏移量,RAM
部分中.
符号的基址是{{1 }}。但是,这是一个相对地址,它对应于.data
部分的VMA绝对地址0
。顺便说一句,这与上述事实一致0x20000000
指定VMA位于.data
内存区域(别名PLACE 2
)。
如果您的示例是真实示例,则可以使用RAM
链接描述文件内置函数轻松检查刚刚声明的内容,以获取REGION_DATA
部分的VMA。
答案 1 :(得分:0)
在我阅读了几个ld脚本之后,我得出了以下理解:
为了说明部分声明声明,我写了下面的代码片段。
如上所示,ld脚本中的private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
声明有两个要指定的重要事项:
我们可以通过两种方式指定这些地址:
这两种方式在部分声明声明中具有不同的位置,如上所示,在花括号之前或之后。
部分本身是 RIGID BODY 。位置计数器section
仅代表其包含对象内的偏移量。 不多,不少。 既不是VMA也不是LMA。
偏移的基数可以是包含部分的VMA或LMA,取决于它是您正在谈论的运行时或加载时间。
但是在下面的符号赋值语句或章节声明中的其他符号操作中, VMA被用作.
的基础。
.