Ada*_*win 15 embedded linker arm gnu linker-scripts
我正在开展一个大学项目,我正在从头开始为Atmel 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 ( * )
}
}
Run Code Online (Sandbox Code Playgroud)
在整个示例中(例如.ramvect,.fastcode和.stack部分),有符号定义,如__ram_start = .;.这些地址由启动汇编代码和初始化C代码使用,以初始化MCU RAM中的正确位置.
我理解的问题是,这些符号定义如何导致分配正确的值.这确实发生了,脚本是正确的,我只是不明白如何.
我理解它的方式,当你在一个部分中使用位置计数器时,它只包含与部分本身的虚拟内存地址(VMA)的相对偏移量.
因此,例如,在行中__ram_start = .;,我希望__ram_start被赋值为0x0 - 因为它在.ramvect部分的开头被赋予了位置计数器的值.但是,为了使初始化代码正常工作(它确实如此),必须将__ram_start指定为0x00200000(RAM开头的地址).
我还以为如预期,如果行是不是这只会工作__ram_start = ABSOLUTE(.);或__ram_start = ADDR(.ramvect);.
这同样适用于__fastcode_start和__stack_start__.它们不能全部被定义为地址0x0,否则程序将无法工作.但是这里链接的文档似乎表明应该发生的事情.这是文档中的引用:
注意: .实际上是指从当前包含对象的开头起的字节偏移量.通常这是SECTIONS语句,其起始地址为0,因此.可以用作绝对地址.如果.但是在段描述中使用它,它指的是从该段开始的字节偏移量,而不是绝对地址.
因此,在这些符号分配期间的位置计数器值应该与相应的部分VMA偏移.所以那些"_start"符号应该全部设置为0x0.哪个会打破这个计划.
显然我错过了一些东西.我想它可能只是将位置计数器值分配给符号(在一个部分内)导致默认情况下使用ABSOLUTE().但我无法在任何证实这一点的地方找到明确的解释.
如果有人能清除这一点,请提前感谢.
我想我可能已经找到了自己问题的答案.我不确定我是对的,但这是我能够想到的第一个解释实际上是有道理的.让我重新思考的是本文档的这一页.特别是这句话:
地址和符号可以是相对的部分,也可以是绝对的.节相对符号是可重定位的.如果使用`-r'选项请求可重定位输出,则进一步的链接操作可能会更改节相对符号的值.另一方面,绝对符号将在任何进一步的链接操作中保持相同的值.
这句话:
您可以使用内置函数ABSOLUTE强制表达式是绝对的,否则它将是相对的.例如,要创建一个绝对符号集,该符号设置为输出节末尾的地址
.data:Run Code Online (Sandbox Code Playgroud)SECTIONS { .data : { *(.data) _edata = ABSOLUTE(.); } }如果
ABSOLUTE没有使用,_edata将相对于该.data部分.
我以前读过它们,但这次我从新的角度看过它们.
因此,我认为我的误解是认为当分配了相对字节偏移地址时,符号只是在基址信息丢失时设置为该偏移的值.
这是基于我原来问题的引用:
注意: .实际上是指从当前包含对象的开头起的字节偏移量.通常这是SECTIONS语句,其起始地址为0,因此.可以用作绝对地址.如果.但是在段描述中使用它,它指的是从该段开始的字节偏移量,而不是绝对地址.
相反,我现在理解的是,基地址信息不会丢失.该符号不会简单地分配基址的偏移值.该符号仍将最终解析为绝对地址,但仅当其基地址无法更改时才会解析.
所以,我认为__stack_start__ = . ;应该改变一些东西__stack_start__ = ABSOLUTE(.) ;,哪个有效,我现在认为这是不必要的.更重要的是,我从这个回复的第一个引言中了解到你可以重新链接一个ELF文件?
因此,如果我使用__stack_start__ = ABSOLUTE(.) ;,运行链接器脚本来创建ELF可执行文件,然后尝试重新链接它并将.stack部分移动到其他位置,该__stack_start__符号仍然指向来自第一个链接的相同绝对地址,因此是不正确的.
这可能很难遵循,但我尽可能清楚地写出来.我怀疑我已接近正确的想法,但我仍然需要有人真正了解这些东西以确认或否认这一点.
该部分的位置由右括号(>RAM AT>ROM)之后的存储区域确定。因此,执行地址位于RAM的0x00200000及之后,但加载地址位于ROM(闪存)的0x00100000。启动代码必须将.fastcode输出部分从其负载复制到其执行地址,这就是符号的作用。
请注意,这些地址不必位于地址0,因为AT91SAM7S将RAM或ROM重映射到地址0。通常它以映射的ROM启动,并且启动代码将其切换到RAM。
| 归档时间: |
|
| 查看次数: |
8782 次 |
| 最近记录: |