2012-01-22 59 views
6

长话短说。我希望学习如何创建一个好的链接器脚本,以便我应该更换平台/架构/供应商时,我不会再陷于零地,不知道该怎么做。我并不关心任务的难度,理解它也是如此。关于链接器脚本创建和验证的建议

我已经开始了一个排序project,因为它是,创建编程基础或骨架和STM的32位Cortex-M3的芯片开发。在jsiei97的帮助下,从STM32F103RB开始(我也有一个TI Stellaris LM3S828,但那是另一个问题),而不需要授权的IDE。由于我是一名学生,而且大多数学生都承担不起这样的事情。

据我所知,还有的ODev,和Eclipse插件,什么不可以,并已阅读各种博客,Wiki,文档/手册页和大多数项目为您提供一个链接脚本很少知道解释,为什么和哪里的东西已被定义。

我已经为STM32编译了一个arm-none-eabi工具链,但是我挂起的地方在链接器脚本中。 CodeSourcery也需要一个。在阅读gnu手册页后,我有一个关于如何创建它们和它们的语法的基本概念,但是我根本不知道从哪里开始放入除明显的.text,.bss和.data之外的各种额外部分。

我创建了一个rudimentary version但我得到链接错误要求部分定义,这就是我卡住的地方。我知道如何定义它们,但知道我在做什么甚至接近正确的问题。

+0

gnu链接器脚本充其量是相当痛苦的。从gcc 3.x到4.x以前的工作再也没有工作了,所以我认为它会继续下去,无论你有多好,他们都会在某天将你的脚下的地毯拉下来。 –

+0

这是真的。我只能期待这一点。然而,从4.x到5.x,我可以得到一些坚实的工作,并且这将是跟随更改日志的问题。应该做任何重大改变。 – Crewe

回答

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/

和通过检查GCC的输出与标准连接器脚本交叉编译,使用nm。我基本上确定了所有正在输出的部分,并找出哪些部分实际上是有用的,以及在内存中哪些部分应该用于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) } 
} 
+0

有人告诉我们,我们不能只提供答案的链接,因为这些答案可能会改变,但会将信息提供给我们正在讨论的答案。我已将您指定的文件添加到您的答案中。 –

+1

您从哪里获得创建此脚本所需的信息?你是怎么知道你需要** _ sheap **,** _ sidata **和** _ sstack **以及分配给他们的。这是我正在寻找的信息类型。 – Crewe

+1

我编辑了我的答案。每个部分(以及更多)都使用标准链接器脚本进行编译。检查脚本中的注释。 _sheap是堆的开始,_sstack是堆栈的开始。 – anrope

8

我有一个简单的链接脚本,我可以跨平台定期重复使用,只需根据需要更改一些地址即可。

http://github.com/dwelch67/

有许多许多的样本与海湾合作委员会的样品和那些最有链接脚本。

MEMORY 
{ 
    rom : ORIGIN = 0x00000000, LENGTH = 0x40000 
    ram : ORIGIN = 0x10000000, LENGTH = 30K 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > rom 
    .bss : { *(.bss*) } > ram 
} 
+3

+1保持简单。绝对有人可以阅读并理解它。许多人试图直接将内存映射寄存器等放入链接器脚本中,很快它就会自动生成。更不用说不可移植。 – Dan

+1

这是不是至少缺少数据部分? (你的初始化全局变量在哪里?) – dbrank0