【问题标题】:How to decide the base address for the location counter "." when VMA and LMA are different?如何确定位置计数器“。”的基地址。当VMA和LMA不同时?
【发布时间】:2016-11-15 09:55:12
【问题描述】:

根据ld手册on the special symbol ., i.e.the Location Counter

注意:.实际上是指从开头的字节偏移量 当前包含对象。通常这是 SECTIONS 语句, 其起始地址为 0,因此 .可以用作绝对地址。 如果 。然而,在章节描述中使用,它指的是 从该部分开始的字节偏移量,而不是绝对地址。 因此在这样的脚本中:

 SECTIONS
 {
     . = 0x100
     .text: {
       *(.text)
       . = 0x200
     }
     . = 0x500
     .data: {
       *(.data)
       . += 0x600
     }
 }

“.text”部分将被分配一个 0x100 的起始地址和一个 大小正好为 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 指定LMAROM2 中,而PLACE 2 指定VMARAM 中?那么.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*/

【问题讨论】:

    标签: gnu ld binutils


    【解决方案1】:

    要回答您的问题,可以利用官方 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 在 RAM 中。

    由于在段描述中使用位置计数器时,它指的是从该段开始的字节偏移量,所以.data 段中. 符号的基地址是0。然而,这是一个相对地址,它对应于绝对地址0x20000000,它是.data 部分的VMA。顺便说一句,这与上面提到的事实是一致的,即PLACE 2 指定 VMA 位于RAM 内存区域(别名REGION_DATA)。
    如果您的示例是真实示例,您可以使用 ADDR(section) 链接器脚本语言内置函数轻松检查刚刚陈述的内容,以获取 .data 部分的 VMA。

    【讨论】:

    • 谢谢。我改进了我的问题中的示例,以清楚地说明我的困惑。
    【解决方案2】:

    又看了几个ld脚本后,我得到了如下理解:

    我写了下面的sn-p来说明部分声明声明

    如上图所示,ld 脚本中的section 声明有两件重要的事情需要指定:

    • 加载时的 LMA
    • 运行时的 VMA

    我们可以通过两种方式指定这些地址:

    • 精确到特定地址
    • 或附加到内存区域

    这两种方式在段声明语句中的位置不同,如上图,在花括号之前或之后。

    截面本身就是一个刚体。位置计数器. ONLY 代表其包含对象内的偏移量。 不多也不少既不是 VMA,也不是 LMA。

    偏移量的基数可以是包含部分的 VMA 或 LMA,取决于您所说的是运行时或加载时间。

    但是在像下面这样的符号赋值语句或在节声明中的其他符号操作中,VMA 被用作.的基础。

      .data_flash     : {_data_flash = .;} >CODE
    

    【讨论】:

    • 我当时就想通了。我现在需要阅读我自己的回复才能理解它......
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 2012-04-24
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多