【发布时间】:2012-11-29 16:01:04
【问题描述】:
我正在从事一个大学项目,我正在从头开始为 Atmel SAM7S256 微控制器编写软件。这比我以前使用过的其他 MCU 更深入,因为这次需要了解链接器脚本和汇编语言。
我一直在仔细研究 SAM7S 芯片的示例项目,以便完全了解如何从头开始启动 SAM7/ARM 项目。一个值得注意的例子是 Miro Samek 的“使用 GNU 构建裸机 ARM 系统”教程,该教程位于 here(此问题中的代码来自哪里)。我还花了很多时间从 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 = .;。启动汇编代码和初始化 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,否则程序将无法运行。但是文档linked here 似乎表明这就是应该发生的事情。这是文档中的引用:
注意:.实际上是指从当前包含对象开始的字节偏移量。通常这是 SECTIONS 语句,其起始地址为 0,因此 .可以用作绝对地址。如果 。但是,在节描述中使用,它指的是从该节开始的字节偏移量,而不是绝对地址。
因此,在这些符号分配期间的位置计数器值应该从相应的部分 VMA 偏移。所以那些“_start”符号应该all被设置为0x0。这会破坏程序。
所以很明显我错过了一些东西。我想这可能只是将位置计数器值分配给一个符号(在一个部分内)导致 ABSOLUTE() 默认使用。但我无法在任何地方找到明确的解释来证实这一点。
如果有人可以解决这个问题,请提前感谢。
【问题讨论】:
-
这是我使用 .fastcode 时的经验。我反汇编了输出并查看了链接器映射(因为我也遇到了其他问题)。我看到的是 .bss 部分与 .data 部分具有完全相同的 RAM 地址。这意味着如果您的启动文件中有代码,首先复制数据,然后使用提供的地址清除 bss,数据部分将被清除为 bss 部分的大小。不过,我不能肯定地说,因为它取决于很多东西,包括 Makefile 和你的来源。尝试反汇编一个测试程序。
-
我看过了。自从我从事这个项目以来已经有一段时间了,但我认为这个问题所基于的代码最终没有 .fastcode、.data 或 .bss。所以这就是为什么那里没有问题。但是,我确实在项目的下一阶段再次使用了相同的链接器脚本。这次有 .fastcode 和 .bss(虽然没有 .data)。当我查看链接器映射时,.fastcode 以
0x00200040和0x0020029C开始和结束。 .data 以0x0020029C开始和结束,因为它是空的。 .bss 以0x0020029C和0x00200438开始和结束。所以一切似乎都很好。 -
为了确定,我创建了几个全局变量并重新编译。 .fastcode、.bss 和 .data 的 VMA 都符合预期并且没有重叠。我认为这一定是我们的工具链之间的区别,我使用的是 YAGARTO 与 GCC 4.7.2 和 Binutils 2.23.1。编辑:刚刚看到你的新评论。是的,我认为你是对的。有趣的是,我们使用的是相同的 LD 版本,但这可能与它的 YAGARTO 方面有关。无论如何感谢您的帮助,确保一切正常是件好事。
-
一个额外的提示:如果你在你的 .fastcode 部分使用汇编程序,你不应该使用
.section .fastcode,而应该使用.section .fastcode,"ax",%progbits。因为如果你不添加标志,你的代码有时会被包含(如果你幸运的话)。 -
@nonsensical 这是来自非官方来源的旧版本 GNU ld 的手册。 sourceware.org/binutils/docs/ld
标签: linker embedded arm gnu linker-scripts