Понимание счетчика местоположений сценариев GNU Linker

я работаю над университетским проектом, где яЯ пишу программное обеспечение для микроконтроллера Atmel SAM7S256 с нуля. Это глубже, чем другие микроконтроллеры, которые яМы работали с ним раньше, так как на этот раз необходимо знание сценариев компоновщика и языка ассемблера.

Мы тщательно изучили примеры проектов для чипов SAM7S, чтобы полностью понять, как начать проект SAM7 / ARM с нуля. Ярким примером является Миро Самек "Построение Bare-Metal ARM систем с помощью GNU " Учебник найденВот (откуда код в этом вопросе). Я'Мы также потратили много времени на чтение документации компоновщика и ассемблера с sourceware.org.I '

Я очень рад, что по большей части понимаю следующий скрипт компоновщика. Там'Это всего лишь одна вещь, связанная с счетчиком местоположения, который нене имеет смысла для меня. Ниже приведен скрипт компоновщика, входящий в приведенный выше учебник:

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_vectors)

MEMORY {                                       /* memory map of AT91SAM7S64 */
    ROM (rx)  : ORIGIN = 0x00100000, LENGTH = 64k
    RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 16k
}

/* The sizes of the stacks used by the application. NOTE: you need to adjust */
C_STACK_SIZE   = 512;
IRQ_STACK_SIZE = 0;
FIQ_STACK_SIZE = 0;
SVC_STACK_SIZE = 0;
ABT_STACK_SIZE = 0;
UND_STACK_SIZE = 0;

/* The size of the heap used by the application. NOTE: you need to adjust   */
HEAP_SIZE = 0;

SECTIONS {

    .reset : {
        *startup.o (.text)  /* startup code (ARM vectors and reset handler) */
        . = ALIGN(0x4);
     } >ROM

    .ramvect : {                        /* used for vectors remapped to RAM */
        __ram_start = .;
        . = 0x40;
    } >RAM

    .fastcode : {
        __fastcode_load = LOADADDR (.fastcode);
        __fastcode_start = .;

        *(.glue_7t) *(.glue_7)
        *isr.o (.text.*)
        *(.text.fastcode)
        *(.text.Blinky_dispatch)
        /* add other modules here ... */

        . = ALIGN (4);
        __fastcode_end = .;
    } >RAM AT>ROM

    .text : {
        . = ALIGN(4);
        *(.text)                                   /* .text sections (code) */
        *(.text*)                                 /* .text* sections (code) */
        *(.rodata)           /* .rodata sections (constants, strings, etc.) */
        *(.rodata*)         /* .rodata* sections (constants, strings, etc.) */
        *(.glue_7) /* glue arm to thumb (NOTE: placed already in .fastcode) */
        *(.glue_7t)/* glue thumb to arm (NOTE: placed already in .fastcode) */

        KEEP (*(.init))
        KEEP (*(.fini))

        . = ALIGN(4);
        _etext = .;                         /* global symbol at end of code */
    } >ROM

    .preinit_array : {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(SORT(.preinit_array.*)))
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
    } >ROM

    .init_array : {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
    } >ROM

    .fini_array : {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(.fini_array*))
        KEEP (*(SORT(.fini_array.*)))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >ROM

    .data : {
        __data_load = LOADADDR (.data);
        __data_start = .;
        *(.data)                                          /* .data sections */
        *(.data*)                                        /* .data* sections */
        . = ALIGN(4);
        _edata = .;
    } >RAM AT>ROM

    .bss : {
        __bss_start__ = . ;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;                     /* define a global symbol at bss end */
        __bss_end__ = .;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );
    PROVIDE ( __end__ = _ebss );

    .heap : {
        __heap_start__ = . ;
        . = . + HEAP_SIZE;
        . = ALIGN(4);
        __heap_end__ = . ;
    } >RAM

    .stack : {
        __stack_start__ = . ;

        . += IRQ_STACK_SIZE;
        . = ALIGN (4);
        __irq_stack_top__ = . ;

        . += FIQ_STACK_SIZE;
        . = ALIGN (4);
        __fiq_stack_top__ = . ;

        . += SVC_STACK_SIZE;
        . = ALIGN (4);
        __svc_stack_top__ = . ;

        . += ABT_STACK_SIZE;
        . = ALIGN (4);
        __abt_stack_top__ = . ;

        . += UND_STACK_SIZE;
        . = ALIGN (4);
        __und_stack_top__ = . ;

        . += C_STACK_SIZE;
        . = ALIGN (4);
        __c_stack_top__ = . ;

        __stack_end__ = .;
    } >RAM

    /* Remove information from the standard libraries */
    /DISCARD/ : {
        libc.a ( * )
        libm.a ( * )
        libgcc.a ( * )
    }
}

Во всем примере (например, в разделах .ramvect, .fastcode и .stack) есть определения символов, такие как__ram_start = .;, Эти адреса используются кодом сборки запуска и кодом C инициализации, чтобы инициализировать правильные местоположения в MCU 'оперативная память

Что я понимаю, так это то, как эти определения символов приводят к назначению правильных значений. Это происходит, сценарий правильный, я просто нене понимаю как.

Насколько я понимаю, когда вы используете счетчик местоположения в разделе, он содержит только относительное смещение от адреса виртуальной памяти (VMA) самого раздела.

Так, например, в строке__ram_start = .;Я ожидал бы, что __ram_start будет присвоено значение 0x0 - так как ему присваивается значение счетчика местоположений в самом начале раздела .ramvect. Однако, чтобы код инициализации работал правильно (что он и делает), __ram_start должен быть назначен как 0x00200000 (адрес для начала ОЗУ).

Я бы подумал, что это будет работать только так, как задумано, если линия была вместо__ram_start = ABSOLUTE(.); или же .__ram_start = ADDR(.ramvect);

То же самое касается__fastcode_start а также__stack_start__, Они могут't все будут определены как адреса 0x0, иначе программа нет работа. Но документациясвязаны здесь кажется, что этос тем, что должно происходить. Вот's цитата из документации:

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

Таким образом, значения счетчика местоположения во время этих назначений символов должны быть смещениями от соответствующих VMA секций. Так что те_Начните" символы должнывсе быть установлен на 0x0. Который сломал бы программу.

Так что, очевидно, яЯ что-то упустил. Я полагаю, что это может быть просто из-за того, что присвоение значения счетчика местоположения символу (внутри секции) приводит к тому, что ABSOLUTE () используется по умолчанию. Но у меня нетЯ не смог найти четкого объяснения где-либо, что подтверждает это.

Спасибо заранее, если кто-нибудь может это прояснить.

Ответы на вопрос(2)

Ваш ответ на вопрос