Как определить базовый адрес для счетчика местоположения. когда VMA и LMA разные?

Согласно руководству ld на специальном символе ., т.е. счетчике местоположения .

Примечание: . фактически относится к байтовому смещению от начала текущего содержащего объекта. Обычно это оператор SECTIONS, начальный адрес которого равен 0. может использоваться как абсолютный адрес. Если . используется внутри описания раздела, однако он относится к байтовому смещению от начала этого раздела, а не к абсолютному адресу. Таким образом, в таком сценарии:

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

Секции '.text' будет назначен начальный адрес 0x100 и размер точно 0x200 байт, даже если во входных секциях '.text' недостаточно данных для заполнения этой области.

И в руководстве ld также говорится о VMA раздела вывода и LMA:

Каждая загружаемая или выделяемая секция вывода имеет два адреса. Первый - это VMA или адрес виртуальной памяти. Это адрес, который будет иметь секция при запуске выходного файла. Второй - это LMA или адрес загрузочной памяти. Это адрес, по которому будет загружен раздел. В большинстве случаев два адреса будут одинаковыми. Примером, когда они могут быть разными, является то, что раздел данных загружается в ПЗУ, а затем копируется в ОЗУ при запуске программы (этот метод часто используется для инициализации глобальных переменных в системе на основе ПЗУ). В этом случае адресом ПЗУ будет LMA, а адресом ОЗУ - 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*/

person smwikipedia    schedule 13.07.2016    source источник


Ответы (2)


Чтобы ответить на ваш вопрос, можно использовать два факта из официальной ld документации.

Первый факт из секции вывода 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 = . ;}
 }

Второй факт из счетчика местоположения.

. фактически относится к байтовому смещению от начала текущего содержащего объекта. Обычно это оператор SECTIONS, начальный адрес которого 0, поэтому . может использоваться как абсолютный адрес. Однако, если . используется внутри описания раздела, это относится к байтовому смещению от начала этого раздела, а не к абсолютному адресу.

Объединив эти две части информации, можно сказать, что счетчик местоположения определяет значение VMA, давая его смещение от начального адреса текущего содержащего объекта (оператора SECTIONS или секции вывода).

Таким образом, абсолютный базовый адрес счетчика местоположения равен

  • начальный адрес оператора SECTIONS, то есть 0, если мы ссылаемся на . вне определения секции вывода
  • VMA секции вывода, если мы ссылаемся на . внутри этой секции вывода

Что касается раздела .data в вашем примере, вы правы: PLACE 1 указывает, что LMA находится в ROM2, а PLACE 2 указывает, что VMA находится в RAM.

Поскольку счетчик местоположения, когда он используется внутри описания раздела, относится к байтовому смещению от начала этого раздела, базовым адресом для символа . в разделе .data является 0. Однако это относительный адрес, и он соответствует абсолютному адресу 0x20000000, который является VMA раздела .data. Между прочим, это согласуется с указанным выше фактом, что PLACE 2 указывает, что VMA находится в RAM области памяти (псевдоним REGION_DATA).
Если бы ваш пример был реальным, вы могли бы легко проверить то, что только что было заявлено, используя встроенная функция языка сценариев ADDR(section) компоновщика для получения VMA для раздела .data.

person mw215    schedule 13.07.2016
comment
Спасибо. Я уточнил пример в своем вопросе, чтобы ясно выразить свое замешательство. - person smwikipedia; 14.07.2016

Прочитав еще несколько ld-скриптов, я пришел к следующему пониманию:

Я написал приведенный ниже фрагмент для иллюстрации инструкции объявления раздела.

введите описание изображения здесь

Итак, как показано выше, объявление section в ld-скрипте имеет две важные вещи, которые необходимо указать:

  • LMA во время загрузки
  • VMA во время выполнения

Мы можем указать эти адреса двумя способами:

  • именно по определенному адресу
  • или добавить в область памяти

Эти два способа имеют разные позиции в заявлении объявления раздела, как показано выше, до или после фигурной скобки.

Сама секция - это ЖЕСТКОЕ ТЕЛО. Счетчик местоположения . ТОЛЬКО обозначает смещение внутри содержащего его объекта. Ни больше, ни меньше. Это ни VMA, ни LMA.

Базой смещения может быть VMA или LMA содержащего раздела, в зависимости от того, о чем вы говорите: во время выполнения или во время загрузки.

Но в операторе присваивания символа, как показано ниже, или при других манипуляциях с символом в объявлении раздела, VMA используется в качестве основы ..

  .data_flash     : {_data_flash = .;} >CODE
person smwikipedia    schedule 18.07.2016