Понимание счетчика местоположений сценариев 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 () используется по умолчанию. Но у меня нетЯ не смог найти четкого объяснения где-либо, что подтверждает это.
Спасибо заранее, если кто-нибудь может это прояснить.