Разделы LD и NOLOAD: понимание странного значения LMA

Я пишу чистое ядро, и мне трудно понять вывод ld в случае раздела NOLOAD. Я объявляю символы, которые существуют только с активированным MMU, поэтому VMA и LMA не совпадают. Раньше я объявлял такой раздел так:

_foobar_start = .;
.foobar : AT(ADDR(.foobar) - VA_PA_OFFSET)
{
    *.o(.foobar.section*)
}
_foobar_end = .;

Теперь содержимое одного из моих разделов загружается загрузчиком, поэтому я хочу только объявить символы VMA, которые будут использоваться во время выполнения, для доступа к данным, поэтому я попробовал атрибут NOLOAD:

_foobar_start = .;
.foobar (NOLOAD) :
{
    . += SIZE_OF_FOOBAR;
}
_foobar_end = .;

Я знаю, что в этом случае меня не волнует LMA, но я ожидал увидеть что-то вроде, где LMA = VMA (см. руководство по LD):

.foobar         0x000000004002c000     0x353c load address 0x000000004002c000

но я получаю кое-что со странным LMA, в котором я не понимаю:

.foobar         0x000000004002c000     0x353c load address 0x0000000001900000

Если я заставлю VMA = LMA в скрипте, используя

.foobar (NOLOAD) : AT(_foobar_start)

все в порядке и я вижу только

.foobar         0x000000004002c000     0x353c

Даже без принудительного VMA = LMA результирующий ELF в порядке, но я получаю некоторые предупреждения во время компиляции из-за других разделов (toto - другой раздел):

warning: dot moved backwards before `.toto

и я бы хотел прочитать о них.

Есть ли причина, по которой я не получаю LMA = VMA при указании NOLOAD?

РЕДАКТИРОВАТЬ: вот полный файл компоновщика, вызывающий проблему. Я добавил несколько комментариев, чтобы указать на проблемы

OUTPUT_ARCH(CONFIG_LINKER_ARCH)
OUTPUT_FORMAT(CONFIG_LINKER_FORMAT)

_kern_phys_base = OCRAM_BASE_PA + OCRAM_OFFSET;

_kern_offset = KERNEL_VA_PA_OFFSET;

SECTIONS
{
    . = _kern_phys_base;

    _start_image_addr = .;

    . = ALIGN(0x1000);
    _early_text_start = .;
    .early_text :
    {
        KEEP(*(.text.boot))
        KEEP(*(.text.mmu))
    }

    . = ALIGN(4);
    .early_rodata :
    {
        *(.rodata.boot*)
        *(.rodata.mmu*)
    }
    _early_text_end = .;

    . = ALIGN(0x1000);
    _early_data_start = .;
    .early_data :
    {
        *(.data.boot)
    }
    _early_data_end = .;

    . = ALIGN(0x4000);
    _early_bss_start = .;
    .early_bss :
    {
        *(.bss.mmu)
        *(.bss.boot)
    }
    . = ALIGN(16);
    _early_bss_end = .;

    _early_end = .;

    /*
     * The following part is accessed only once the MMU has been
     * activated, so we first need to jump into "high" memory
     */
    . += _kern_offset;

    . = ALIGN(0x1000);
    _text_start = .;
    .text : AT(ADDR(.text) - _kern_offset)
    {
        *(.text .text.*)
    }
    _text_end = .;

    . = ALIGN(0x1000);
    _rodata_start = .;
    .rodata : AT(ADDR(.rodata) - _kern_offset)
    {
        *(.rodata*)
    }
    _rodata_end = .;

    . = ALIGN(4);
    _arm_extab_start = .;
    .ARM.extab : AT(ADDR(.ARM.extab) - _kern_offset)
    {
        *(.ARM.extab)
    }
    _arm_extab_end = .;

    . = ALIGN(4);
    _arm_exidx_start = .;
    .ARM.exidx : AT(ADDR(.ARM.exidx) - _kern_offset)
    {
        *(.ARM.exidx)
    }
    _arm_exidx_end = .;

    . = ALIGN(4);
    _kernel_debug_info_start = .;
    _kernel_debug_info_end = .;

    . = ALIGN(4);
    _emergency_code_vstart = .;
    _emergency_code_vend = .;

    /*
     * This is where I use the NOLOAD, with AT this time
     * This 'archive' part is not located in OCRAM, but some
     * where else in RAM
     */
    _archive_point_save = .;
    . = DDR_BASE_VA;
    . = ALIGN(512);
    _archive_start = .;
    .archive_data (NOLOAD) : AT(_archive_start)
    {
        codes.o(.rawdata*)
    }
    _archive_end = .;
    . = _archive_point_save;

    /* Back to OCRAM VMA */
    . = ALIGN(0x1000);
    _data_start = .;
    .data : AT(ADDR(.data) - _kern_offset)
    {
        *(.data*)
    }
    _data_end = .;

    . = ALIGN(32);
    _bss_start = .;
    .bss : AT(ADDR(.bss) - _kern_offset)
    {
        *(.bss .bss.*)
    }
    . = ALIGN(16);
    _bss_end = .;

    /*
     * Second location, also in RAM, just after the '.archive_data' section
     * This time I didn't put the AT to show the difference in output
     */
    _dyn_archive_point_save = .;
    . = _archive_end;
    . = ALIGN(0x1000);
    _dyn_archive_start = .;
    .dyn_archive (NOLOAD) :
    {
        . += _dyn_archive_space;
    }
    _dyn_archive_end = .;
    . = _dyn_archive_point_save;

    /* Back to OCRAM VMA */
    . = ALIGN(0x1000);
    _kernel_stack_guard = .;
    . += 0x1000;

    .stack (NOLOAD) :
    {
        _kernel_stack_end = .;
        /* 2 pages of 4 kB */
        . += 0x2000;
        _kernel_stack_start = .;
    }

    _kernel_image_end = .;
}

А вот результат objdump -x:

build/kernel/kernel.elf:     file format elf32-littlearm
build/kernel/kernel.elf
architecture: arm, flags 0x00000102:
EXEC_P, D_PAGED
start address 0x00910000

Program Header:
0x70000001 off    0x0003072c vaddr 0x4003072c paddr 0x0093072c align 2**2
         filesz 0x000000a0 memsz 0x000000a0 flags r--
    LOAD off    0x00010000 vaddr 0x00910000 paddr 0x00910000 align 2**16
         filesz 0x00002828 memsz 0x00008000 flags rwx
    LOAD off    0x00018000 vaddr 0x40018000 paddr 0x00918000 align 2**16
         filesz 0x000199e0 memsz 0x0001fa28 flags rwx
    LOAD off    0x00038000 vaddr 0x41028000 paddr 0x01928000 align 2**16
         filesz 0x00000000 memsz 0x00100000 flags rw-
    LOAD off    0x00039000 vaddr 0x40039000 paddr 0x40039000 align 2**16
         filesz 0x00000000 memsz 0x00002000 flags rw-
    LOAD off    0x00040000 vaddr 0x41000000 paddr 0x41000000 align 2**16
         filesz 0x00000000 memsz 0x00028000 flags rw-
private flags = 5000200: [Version5 EABI] [soft-float ABI]

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .early_text   000015c0  00910000  00910000  00010000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .early_rodata 00000030  009115c0  009115c0  000115c0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .early_data   00000828  00912000  00912000  00012000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  3 .early_bss    00004000  00914000  00914000  00012828  2**14
                  ALLOC
  4 .text         000142d8  40018000  00918000  00018000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  5 .rodata       000036c0  4002d000  0092d000  0002d000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .ARM.extab    0000006c  400306c0  009306c0  000306c0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .ARM.exidx    000000a0  4003072c  0093072c  0003072c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .archive_data 00028000  41000000  41000000  00040000  2**0
                  ALLOC
  9 .data         000009e0  40031000  00931000  00031000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 10 .bss          00006048  400319e0  009319e0  000319e0  2**3
                  ALLOC
 11 .dyn_archive  00100000  41028000  01928000  00038000  2**0
                  ALLOC
 12 .stack        00002000  40039000  40039000  00039000  2**0
                  ALLOC
 13 .comment      0000002d  00000000  00000000  000319e0  2**0
                  CONTENTS, READONLY
 14 .ARM.attributes 00000037  00000000  00000000  00031a0d  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
no symbols

Как видите: .archive_data и .stack правильно получают VMA = LMA, а .dyn_archive - нет. Если я удалю AT из .archive_data, я получу то же поведение, что и .dyn_archive с адресом 0x1900000


person Vinz    schedule 18.12.2017    source источник
comment
Если есть шанс, вы можете опубликовать свой полный файл компоновщика. Также может оказаться полезным objdump -x вашего связанного исполняемого файла.   -  person Michael Petch    schedule 19.12.2017
comment
Я попытаюсь сделать короткую версию своего файла компоновщика, которая будет вызывать такое же поведение. Что касается objdump -x, я не могу, извините, но я смогу распечатать некоторые части. Скоро обновлю.   -  person Vinz    schedule 19.12.2017
comment
@ Майкл-Петч: Вывод достаточно чистый, я выразился полностью.   -  person Vinz    schedule 19.12.2017
comment
Из нового пакета тестов кажется, что AT навсегда изменит LMA: если я удалю последующее использование AT и оставлю первое, адреса LMA останутся действительными. Я пытаюсь найти ссылку на это поведение в руководстве, но это объясняет, почему мне нужно использовать AT для этих разделов, которые находятся в другом месте.   -  person Vinz    schedule 19.12.2017
comment
В руководстве по сценарию компоновщика есть утверждение: В противном случае, если может быть найдена область памяти, совместимая с текущим разделом, и эта область содержит хотя бы один раздел, тогда LMA устанавливается таким образом, чтобы разница между VMA и LMA совпадает с разницей между VMA и LMA последней секции в расположенном регионе.   -  person Hsu Hau    schedule 24.02.2020


Ответы (1)


Кажется, мой последний комментарий действителен, что подтверждается (по крайней мере, в той степени, в которой мы интерпретируем руководство) в binutils ML

Предупреждение, вызванное сценарием «LMA идет в обратном направлении», и правильное обновление LMA каждый раз, когда . обновляется вручную, является правильным способом.

person Vinz    schedule 20.12.2017