我的工作,我正在写软件的从地上爬起来的爱特梅尔微控制器SAM7S256一所大学的项目。 这是更深入地比其他MCU我合作过,如连接器脚本语言和汇编语言的知识是必要的这一次。
我一直都仔细检查了SAM7S芯片示例项目,以充分了解如何从头开始一个SAM7 / ARM项目。 一个明显的例子是米罗萨梅克的“建筑裸机ARM系统的GNU”教程发现这里 (其中在该问题的代码是从)。 我也花了很多时间阅读从sourceware.org链接器和汇编文件。
我很高兴,我知道大部分下面的链接脚本。 这里有一个涉及位置计数器没有意义对我的事情。 下面是设置有上面的教程链接脚本:
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 = .;
。 这些地址,以初始化在MCU的RAM正确的位置使用的启动汇编代码和初始化C代码。
我有一个问题的理解,是这些符号的定义是如何导致被分配了正确的价值观。 这确实发生了,剧本是正确的,我只是不明白怎么样。
我的理解是,当你使用一节内的位置计数器的方式,它仅包含一个相对从部分本身的虚拟内存地址(VMA)的偏移量。
因此,例如,在线路__ram_start = .;
,我希望__ram_start被分配值为0x0 - 因为它是在.ramvect节一开始就指定位置计数器的值。 然而,对于初始化代码才能正常工作(其它),__ram_start一定是指定为0x00200000(地址为RAM的开头)。
我本来以为这只会工作打算,如果行是不是__ram_start = ABSOLUTE(.);
或__ram_start = ADDR(.ramvect);
。
这同样适用于__fastcode_start
和__stack_start__
。 他们不能全部得到定义为地址0x0,否则程序将无法正常工作。 但文档链接在这里似乎表明,这就是应该发生。 下面是从文档报价:
注意: 。 实际上指的是字节从当前包含对象的起始位置的偏移。 通常,这是该科的语句,其起始地址为0,因此。 可作为绝对地址。 如果。 使用段说明内部然而,它指的是字节从该部分,而不是绝对地址的起始偏移。
所以在这些符号分配位置的计数器值应该是从相应的部分的VMA偏移。 因此,这些“_start”符号都应该得到设置为0x0。 这将打破计划。
所以,很显然,我失去了一些东西。 我想这可以简单地是分配位置计数器值的符号(一个段内)在无水结果()正在使用的默认值。 但我一直没能在别处找到一个明确的解释,即证明了这一点。
在此先感谢如果有人可以清除这件事。