长话短说。我希望学习如何创建一个好的链接器脚本,这样我就可以更改平台/架构/供应商,我不会因为不知道该怎么做而再次停留在零点。我并不关心任务的难度,而是关心它。
我已经开始使用project来创建一个基础或骨架,用于编程和开发STM的32位Cortex-M3芯片。在jsiei97的帮助下,从STM32F103RB开始(我还有TI Stellaris LM3S828,但这是另一个问题),无需许可的IDE。因为我是学生,大多数学生都买不起这样的东西。
我知道有ODev,Eclipse插件和什么没有,并且已阅读各种博客,wiki,docs / man页面,大多数项目为您提供了一个链接器脚本,几乎不知道如何解释为什么以及确定事物的地方。
我为STM32编译了一个arm-none-eabi工具链,但我挂起的是链接器脚本。 CodeSourcery也需要一个。我有一个基本概念,在阅读gnu手册之后如何创建它们和它们的语法,但我只是想知道从除了明显的.text,.bss和。之外的各种额外部分开始的位置。数据。
我创建了一个rudimentary version,但我收到了链接错误,询问了部分定义以及我遇到的问题。我知道如何定义它们,但知道我所做的事情是否接近正确就是问题所在。
答案 0 :(得分:8)
我有一个简单的链接器脚本,我会在平台上定期重用,只需根据需要更改一些地址。
有很多样本很多都有gcc样本,其中大多数都有链接描述文件。
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x40000
ram : ORIGIN = 0x10000000, LENGTH = 30K
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
}
答案 1 :(得分:2)
这是STM32F105RB的工作链接描述文件(还有R8和RC的版本):
https://github.com/anrope/stm-arp/blob/github/arp.rb.ld(下方文字)
我的头脑猜测是你不必改变任何东西。也许是MEMORY {}语句中定义的区域的起源。希望这些评论对您有所帮助。
我用GNU / GCC交叉编译器将其用于自己。编译之后,在代码上运行nm
以确保将部分放置在正确的地址是有帮助的。
编辑: 我使用GNU ld文档将这个链接器脚本拼凑在一起:
http://sourceware.org/binutils/docs/ld/
并使用nm
检查使用标准链接描述文件的GCC交叉编译的输出。我基本上确定了所有正在输出的部分,并找出了哪些部分实际上有用,以及内存应该用于STM32F105。
我在每个部分目的的链接描述文件中做了笔记。
/*
arp.{r8,rb,rc}.ld :
These linker scripts (one for each memory density of the stm32f105) are used by
the linker to arrange program symbols and sections in memory. This is especially
important for sections like the interrupt vector, which must be placed where the
processor is hard-coded to look for it.
*/
/*stm32f105 dev board linker script*/
/*
OUTPUT_FORMAT() defines the BFD (binary file descriptor) format
OUTPUT_FORMAT(default, big, little)
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/* ENTRY() defines the symbol at which to begin executing code */
ENTRY(_start)
/* tell ld where to look for archive libraries */
/*SEARCH_DIR("/home/arp/stm/ctc/arm-eabi/lib")*/
/*SEARCH_DIR("/home/arp/stm/ccbuild/method2/install/arm-eabi/lib")*/
SEARCH_DIR("/home/arp/stm32dev-root/usrlol/arm-eabi/lib")
/*
MEMORY{} defines the memory regions of the target device,
and gives them an alias for use later in the linker script.
*/
/* stm32f105rb */
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32k
flash (rx) : ORIGIN = 0x08000000, LENGTH = 128k
option_bytes_rom (rx) : ORIGIN = 0x1FFFF800, LENGTH = 16
}
_sheap = _ebss + 4;
_sstack = _ebss + 4;
/*placed __stack_base__ trying to figure out
global variable overwrite issue
__stack_base__ = _ebss + 4;*/
_eheap = ORIGIN(ram) + LENGTH(ram) - 1;
_estack = ORIGIN(ram) + LENGTH(ram) - 1;
/* SECTIONS{} defines all the ELF sections we want to create */
SECTIONS
{
/*
set . to an initial value (0 here).
. (dot) is the location counter. New sections are placed at the
location pointed to by the location counter, and the location counter
is automatically moved ahead the length of the new section. It is important
to maintain alignment (not handled automatically by the location counter).
*/
. = SEGMENT_START("text-segment", 0);
/*isr_vector contains the interrupt vector.
isr_vector is read only (could be write too?).
isr_vector must appear at start of flash (USR),
address 0x0800 0000*/
.isr_vector :
{
. = ALIGN(4);
_sisr_vector = .;
*(.isr_vector)
_eisr_vector = .;
} >flash
/*text contains executable code.
text is read and execute.*/
.text :
{
. = ALIGN(4);
*(.text)
. = ALIGN(4);
*(.text.*)
} >flash
/*init contains constructor functions
called before entering main. used by crt (?).*/
.init :
{
. = ALIGN(4);
KEEP(*(.init))
} >flash
/*fini contains destructor functions
called after leaving main. used by crt (?).*/
.fini :
{
. = ALIGN(4);
KEEP(*(.fini))
} >flash
/* rodata contains read only data.*/
.rodata :
{
. = ALIGN(4);
*(.rodata)
/* sidata contains the initial values
for variables in the data section.
sidata is read only.*/
. = ALIGN(4);
_sidata = .;
} >flash
/*data contains all initalized variables.
data is read and write.
.data (NOLOAD) : AT(_sidata)*/
.data : AT(_sidata)
{
. = ALIGN(4);
_sdata = .;
*(.data)
_edata = .;
} >ram
/*bss contains unintialized variables.
bss is read and write.
.bss (NOLOAD) :*/
.bss :
{
. = ALIGN(4);
_sbss = .;
__bss_start__ = .;
*(.bss)
. = ALIGN(4);
/*COMMON is a special section containing
uninitialized data.
Example: (declared globally)
int temp; //this will appear in COMMON */
*(COMMON)
_ebss = .;
__bss_end__ = .;
} >ram AT>flash
. = ALIGN(4);
end = .;
/* remove the debugging information from the standard libraries */
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}