`
dkn28dkn
  • 浏览: 17302 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

rtems 下linkcmd分析代码

 
阅读更多

rtems 下linkcmd分析代码
2010年11月09日
  /*
  *  GP32 Linker script
  *
  *  Written by Philippe Simons 
  *
  *  The license and distribution terms for this file may be
  *  found in the file LICENSE in this distribution or at
  *
  *  http://www.rtems.com/license/LICENSE.
  *
  *  $Id: linkcmds,v 1.1 2008/05/06 21:01:27 joel Exp $
  */
  OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm","elf32-littlearm")
  OUTPUT_ARCH(arm)
  ENTRY(_start)                                                                     ENTRY:用来指定入口地址。
  /* SEARCH_DIR(/usr/local/rtems-arm-dev-tools/arm-rtem s/lib); */
  MEMORY {
  sdram : ORIGIN = 0x30000000, LENGTH = 64M
  }
  /*
  * Declare some sizes.
  */
  /* The base for SDRAM is set to umon's APPRAMBASE */
  _sdram_base = DEFINED(_sdram_base) ? _sdram_base : 0x30000000;
  _sdram_size = DEFINED(_sdram_size) ? _sdram_size : 64M;
  _irq_stack_size = DEFINED(_irq_stack_size) ? _irq_stack_size : 0x40000;
  _fiq_stack_size = DEFINED(_fiq_stack_size) ? _fiq_stack_size : 0x10000;
  _abt_stack_size = DEFINED(_abt_stack_size) ? _abt_stack_size : 0x10000;
  _svc_stack_size = DEFINED(_svc_stack_size) ? _svc_stack_size : 0x40000;
  /* Do we need any of these for elf?
  __DYNAMIC = 0;    */
  SECTIONS
  {
  .base :
  {
  arm_exception_table = .;    
  arm_reset_vect    = .;     /* 0x00 */
  . += 4;
  arm_undef_vect    = .;     /* 0x04 */
  . += 4;
  arm_swi_vect      = .;     /* 0x08 */
  . += 4;
  arm_iabrt_vect    = .;     /* 0x0c */
  . += 4;
  arm_dabrt_vect    = .;     /* 0x10 */
  . += 4;
  /* no vector here */
  . += 4;
  arm_irq_vect      = .;     /* 0x18 */
  . += 4;
  arm_fiq_vect      = .;     /* 0x1c */
  . += 4;
  /* FIXME: */
  rtems_vector_table = .;
  . += (8 * 4);                     /* 8 ARM interrupts */
  bsp_vector_table = .;
  . += (32 * 4);                    /* 32 S3C2440 interrupts */
  . = ALIGN (0x100);
  } > sdram
  .text      :
  {
  _axf_text_start = . ;
  *(EXCLUDE_FILE (*text.iwram*) .text)
  *(.text.*)
  *(.stub)
  /*
  * Special FreeBSD sysctl sections.
  */
  . = ALIGN (16);
  __start_set_sysctl_set = .;
  *(set_sysctl_*);
  __stop_set_sysctl_set = ABSOLUTE(.);
  *(set_domain_*);
  *(set_pseudo_*);
  /* .gnu.warning sections are handled specially by elf32.em.  */
  *(.gnu.warning)
  *(.gnu.linkonce.t*)
  *(.glue_7)
  *(.glue_7t)
  . = ALIGN(4);  /* REQUIRED. LD is flaky without it. */
  } > sdram
  __text_end = . ;
  .init          : 
  { 
  *(.init)
  } > sdram   /*=0*/
  .jcr : 
  { 
  *(.jcr) 
  } > sdram
  .fini      :
  {
  *(.fini)
  } > sdram  /*=0*/
  .rodata :
  {
  *(.rodata)
  *all.rodata*(*)
  *(.roda)
  *(.rodata.*)
  *(.gnu.linkonce.r*)
  SORT(CONSTRUCTORS)
  . = ALIGN(4);   /* REQUIRED. LD is flaky without it. */
  } > sdram = 0xff
  .ctors :
  {
  /* gcc uses crtbegin.o to find the start of the constructors, so
  we make sure it is first.  Because this is a wildcard, it
  doesn't matter if the user does not actually link against
  crtbegin.o; the linker won't look for a file to match a
  wildcard.  The wildcard also means that it doesn't matter which
  directory crtbegin.o is in.  */
  KEEP (*crtbegin.o(.ctors))
  KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
  KEEP (*(SORT(.ctors.*)))
  KEEP (*(.ctors))
  . = ALIGN(4);   /* REQUIRED. LD is flaky without it. */
  } >sdram = 0
  .dtors :
  {
  KEEP (*crtbegin.o(.dtors))
  KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
  KEEP (*(SORT(.dtors.*)))
  KEEP (*(.dtors))
  . = ALIGN(4);   /* REQUIRED. LD is flaky without it. */
  } >sdram = 0
  .eh_frame :
  {
  KEEP (*(.eh_frame))
  . = ALIGN(4);   /* REQUIRED. LD is flaky without it. */
  } >sdram = 0
  .gcc_except_table :
  {
  *(.gcc_except_table)
  . = ALIGN(4);   /* REQUIRED. LD is flaky without it. */
  } >sdram = 0
  _axf_ro_end = . ;
  .data ALIGN(4) :
  {
  _axf_data_start = ABSOLUTE(.);
  *(.data)
  *(.data.*)
  *(.gnu.linkonce.d*)
  CONSTRUCTORS
  . = ALIGN(4);  /* REQUIRED. LD is flaky without it. */
  } >sdram = 0xff
  __data_end  =  . ;
  .bss ALIGN(4):
  {
  _axf_bss_start = ABSOLUTE(.);
  _clear_start = .;
  *(.bss)
  *(.bss.*)
  *(.gnu.linkonce.b.*)
  *(COMMON)
  . = ALIGN(64);
  _clear_end = .;
  . = ALIGN (256);
  _abt_stack = .;
  . += _abt_stack_size;
  . = ALIGN (256);
  _irq_stack = .;
  . += _irq_stack_size;
  . = ALIGN (256);
  _fiq_stack = .;
  . += _fiq_stack_size;
  . = ALIGN (256);
  _svc_stack = .;
  . += _svc_stack_size;
  /* 
  * Ideally, the MMU's translation table would be in SRAM. But we
  * don't have any. If we don't use more regions than TLB entries (64),
  * the lookup will only happen once for each region.
  */
  . = ALIGN (16 * 1024);
  _ttbl_base = .;
  . += (16 * 1024);
  . = ALIGN (1024);
  _bss_free_start = .;
  } > sdram
  _axf_bss_end = . ;
  _end = . ;
  __end__ = . ;
  PROVIDE (end = _end);
  /* Debugging stuff follows? */
  /* 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) }
  .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) } 
  /*.stack 0x80000 : { _stack = .; *(.stack) }*/
  /* These must appear regardless of  .  */
  }
  以前的经验,链接脚本是嵌入式开发,单片机开发相当重要的一个东西。它完成的工作是做PC机软件的同志们不用关心的,但是也是很复杂的一项工作。总结来看链接脚本要告诉连接器
  1:输出什么
  2:输入是什么,那么obj文件
  3:要用什么库,库放在什么地方
  4:内存分布地址
  5:提供启动代码一些全局地址变量
  一般来说链接脚本需要搞清楚这几样事情后才能编写,那arm-gcc-ld的脚本也一定要实现这些功能。对于大多数的链接器来说,对于简单的项目不需要脚本,只是使用命令参数就可以完成了。
  MEMORY:
  它是用来补充SECTIONS命令的,用来描述目标CPU中可用的内存区域。它是可选的,如果没有这个命令,LD会认为SECTIONS描述的相邻的内存块之间有足够可用的内存。其实很容易理解但是却很少用(我没用过,嘿嘿),在SECTIONS中每个段的分布都没有考虑ARM能够寻址的地址中,ROM,RAM,FLASH是不是连续的。如果不是连续的怎么办?MEMORY就是设置各个区的起始位置,大小,属性的命令,在一个脚本中只能有一个。
  举一个例子:
  如果你的板子有两段存储,而且很遗憾的是不是连续的,一段是从0x0开始,大小为256K,另一段是从0x40000000开始的大小为4M,你可以在脚本中写入如下的代码来描述你的板子的内存信息。 很显然下面的一句用了简略标签,这并不重要,重要的是怎样使用它,不过在那之前还是想再仔细研究下MEMORY命令的细节。
  MEMORY命令的语法是:
  MEMORY
  {
  name (attr) : ORIGIN = origin, LENGTH = len
  ...
  }
  name:一个用户定义的名字,Linker将在内部使用它,所以别把它和SECTIONS里用到的文件名,段名等搞重复了,它要求是独一无二的。
  attr  :如同它的名字一样,这是内存段的属性描述。
  `R'    Read-only sections.
  `W'   Read/write sections.
  `X'    Sections containing executable code.
  `A'    Allocated sections.
  `I'     Initialized sections.
  `L'    Same as I.
  `!'    Invert the sense of any of the following attributes.
  别怪我懒,确实不想再打一遍这个的翻译,而且很久没用英文的俺翻译的估计也不好。总体来说,它是属性就行了。 
  ORIGIN:这是起始地址
  LENGTH:段长
  由此可见上面那段实例显示ROM和RAM的明确位置,而且还显示了他们的只能,一个存代码,一个除了存代码什么都可以。
  接着就是老问题了,怎么用这个。如果仅仅是规定我的板子有什么特点又不用的话那就是脱了裤子放屁,多此一举。这个问题留在SECTIONS命令中回顾。
  SECTIONS:
  它是脚本文件中最重要的元素,不可缺省。它的作用就是用来描述输出文件的布局。
  SECTIONS命令的语法:
  SECTIONS 
  {
  ...
  secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
  ...
  }
  这么多的参数中,只有secname和contents是必须的,其他都是可选的参数。也就说它的最简单的格式就是:
  SECTIONS 
  {
  ...
  secname  : { 
  contents 
  } 
  ...
  }
  但是注意:secname前后的两个空格是必须的,否则就是不合法输入。
  secname定义了段名,其实最开始就忽略了一个重要的因素,arm-gcc-ld脚本需要描述输入和输出,而表面上一看却看不出来什么是输入什么事输入,其实secname和contents就是描述这两个信息的参数。secname是输出文件的段,即输出文件有哪些段,而contents就是描述输出文件的这个段从哪些文件里抽取而来。明确这个了就不难理解为什么SECTIONS命令什么都可以不要就是不能没有这两个参数了。
  secname:定义段,但是别以为定义的段一定要是教科书上写的.data,.text这些科班的必须品,你甚至可以创建一个段来放一个美女的图片。
  contents:它的语法开始复杂起来了,但是你可以简单的把输入文件写到代码中:
  .data : { main.o led.o}
  但是结果被列的目标文件中所有的代码都被链接到.data中去了,显然不大符合我们的要求啊。那么还有一种写法:
  .data : {
  main.o(.data) 
  main.o(.text) // 也可以这样写 main.o(.data  .text)或者main.o(.data , .text)
  led.o(.data) 
  }
  这个写法让只有被选中的文件的特殊段被链接到输出文件的.data段了。当然,我们似乎还有更好的写法:
  .data : {
  *(.data) 
  }
  这样的话,所有目标文件的.data段都被连接到了输出文件中了(这似乎是最常用的方法)。
  核心的部分讲完了,开始回顾前面说到了的那些参数:
  start:强制链接地址。也许没有讲清楚的是,在SECTIONS中,各个段是按次序排列的,前一个段用到什么地方下一个段接着用,而start就是强迫链接器将当前的段连接到指定的地址中。
  .data  0x400000000 : { ..... }
  BLOCK(align):说实话,没看懂。只知道用的时候用的比较多的是ALIGN(4)这样的标记,表示排列地址的时候按4的倍数排列,这样做的理由很简单,系统会快。
  AT(addr):实现存放地址和加载地址不一致的功能,AT表示在文件中存放的位置,而在内存里呢,按照普通方式存储。至于用处,目前在下不知。
  >region:好戏来了,这个region就是前面说的MEMORY命令定义的位置信息。表明当前section所放置的mem有什么特点,如果不符合会怎么样呢?不晓得嘛。
  其他略了吧,累了,主要是没中文资料(屁话,有了还用我刻薄吗),其实有点日文资料也行啊,英文我比较苦手)。
  注释:
  和C语言一样的哦,/**/
  其它:
  其实ARM-GCC-LD脚本还真的和别的不一样,它的功能要强一些,从manual看,它有三大功能:
  1:设置入口函数
  2:定义一个变量并赋值
  3:描述输入输出文件的链接规则
  其实上面的介绍是功能3,1和2都没有讲过。对于arm-gcc-ld脚本来说设置入口函数和定义变量可以在SECTIONS命令大括号里,也可以在外面。语法是:
  ENTRY(symbol)
  这个symbol应该是某个函数,或者是汇编代码里的一个入口。然而,其实ARM-GCC-LD有很多种方式定义入口,所以当你看到你的脚本里没有这句话而板子运行的很正常的时候别大吃一斤。
  1:在连接的时候使用-e参数。
  2:在脚本里使用ENTRY
  3:如果定义过start这个入口(如果你在汇编里如果本身就有这个名字叫start的入口,那么不用特别的声明也可以)
  4:SECTION中.text的第一个入口函数
  5:地址为0的指令
  其实看了这个我们可以理解是ARM对入口的一个选择优先级,1和2是一样的,显示的指明入口,这也是推荐的方法,没人会觉得程序员故弄玄虚是什么好事情。3是连接器的智能吧,而4和5就是无奈的选择了,程序员没干好的事情CPU只要猜着来处理了,有.text段的话就从它开始执行吧,连.text都没有的就从0x00000000开始执行,至于执行到哪里去了,火星人知道。
  关于定义变量,其实一般的脚本都会有的,目的只有一个,给汇编启动代码提地址信息。比如说,一段需要清零的区域在脚本里定义了,而脚本自己不是变形金刚,他不能主动给你清零的,需要你自己的启动代码来清零,清零的代码当然在汇编的启动代码里,它怎么知道需要清零的内存在什么地方?就靠脚本里定义的变量了。没错,事情就是这样的,那也就说一定会有一个提取地址的方法将地址赋给变量了哦,yes!就是小小的一个点"."。 RAM_START = .; 定义了一个RAM_START变量,地址是当前的地址,什么是当前的地址啊?就是链接器在连接的时候根据前面的段排列后的当前位置。当然也可以设置当前位置的值,不过最好不要小于前面排列需要的最小内存。
  . = 0x00000000
  定义当前地址为0x0。
  常用的基本上就这么多了,看一个实例吧:  9 .data : { *(.data) }
  10 .rodata : { *(.rodata) }
  11 Image_ZI_Base = .;
  12 .bss : { *(.bss) }
  13 Image_ZI_Limit = .;
  21 .debug_info 0 : { *(.debug_info) }
  22 .debug_line 0 : { *(.debug_line) } 
  23 .debug_abbrev 0 : { *(.debug_abbrev)}
  24 .debug_frame 0 : { *(.debug_frame) }
  25}
  18PROVIDE (__stack = .);
  19 end = .;
  20 _end = .;14 __bss_start__ = .;
  15 __bss_end__ = .;
  16 __EH_FRAME_BEGIN__ = .;
  17 __EH_FRAME_END__ = .;
  .bss { *(.bss) *(COMMON) }
  这个例子中将所有输入文件的所有通用符号放入输出.bss section内。可以看到COMMOM section的使用方法跟其他section的使用方法是一样的。
  有些目标文件格式把通用符号分成几类。例如,在MIPS elf目标文件格式中,把通用符号分成standard common symbols(标准通用符号)和small common symbols(微通用符号,不知道这么译对不对?),此时连接器认为所有standard common symbols在COMMON section内,而small common symbols在.scommon section内。
  在一些以前的连接脚本内可以看见[COMMON],相当于*(COMMON),不建议继续使用这种陈旧的方式。
  输入section和垃圾回收:
  在连接命令行内使用了选项--gc-sections后,连接器可能将某些它认为没用的section过滤掉,此时就有必要强制连接器保留一些特定的 section,可用KEEP()关键字达此目的。如KEEP(*(.text))或KEEP(SORT(*)(.text))
  最后看个简单的输入section相关例子:
  SECTIONS {
  outputa 0x10000 :
  {
  all.o
  foo.o (.input1)
  }
  outputb :
  {
  foo.o (.input2)
  foo1.o (.input1)
  }
  outputc :
  {
  *(.input1)
  *(.input2)
  }
  }
  本例中,将all.o文件的所有section和foo.o文件的所有(一个文件内可以有多个同名section).input1 section依次放入输出outputa section内,该section的VMA是0x10000;将foo.o文件的所有.input2 section和foo1.o文件的所有.input1 section依次放入输出outputb section内,该section的VMA是当前定位器符号的修调值(对齐后);将其他文件(非all.o、foo.o、foo1.o)文件的. input1 section和.input2 section放入输出outputc section内。
分享到:
评论

相关推荐

    rtems移植代码分析之sparc-leon2

    rtems移植代码分析之sparc-leon2: 对rtems中针对sparc处理器、leon2兼容板卡移植代码进行分析, 主要包括三部分代码分析:cpukit/score/cpu、 c/src/lib/libcpu/sparc、c/src/lib/libbsp/sparc/leon2 希望能对喜欢...

    rtems编译配置系统分析

    rtems编译配置系统分析: rtems配置过程、rtems编译过程、rtems安装过程、rtems应用编译链接过程。对这四个流程的详细分析和背后源代码分析。 希望能对喜欢rtems的人有所帮助,共勉!

    RTEMS 例子

    RTEMS 例子源代码,可以直接编译使用

    RTEMS介绍-中文

    中文介绍了RTEMS,包括简介,性能,支持的处理器,系统架构,主要的几个版本合入特性,代码获取方式,系统覆盖测试,shell,任务调度策略,同步与互斥方法以及虚拟化

    实时操作系统rtems镜像

    RTEMS, 即: 实时多处理器系统(Real Time Executive for Multiprocessor Systems),是一个开源的无版税实时嵌入操作系统RTOS。 它最早用于美国国防系统,早期的名称为实时导弹系统(Real Time Executive for Missile ...

    rtems-4.10.0.tar.bz2

    RTEMS实时操作系统源代码

    rtems学习资料

    rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料rtems学习资料

    rtems-stm32f407-IAR.7z

    rtems嵌入式操作系统在stm32f407上工程,rtems移植到IAR编辑器下。方便调式、查看、学习内核代码。

    rtems5-arm.7z

    arm-rtems5-gcc.exe,mingw64下编译rtems嵌入式操作系统的工具链,32bit ARM处理器可用

    rtems中文文档.rar

    rtems中文文档.rar rtems中文文档.rar

    rtems 交叉编译环境建立

    rtems 4.66.9.3交叉编译环境的建立过程

    论文研究-RTEMS实时操作系统内核分析与研究 .pdf

    RTEMS实时操作系统内核分析与研究,杨晓钢,,作为前美国军方研制的嵌入式系统, RTEMS一直在军工和航天航空领域有着广泛的应用。随着该实时操作系统的发展,越来越多的科技工作��

    RTEMS Shell User’s Guide

    RTEMS Shell User’s Guide

    rtems_building_v10.sh

    rtos rtems 开发环境 交叉工具链 shell脚本 RTEMS安装脚本 #rtems4 11在linuxmint 16 cinnamon 64bit上测试通过

    RTEMS实时操作系统_周红波

    介绍了源代码开放的嵌入式实时操作系统RTEMS, 并将它与其它各种实时操作系统RTOS-Linux、VxWorks进行性能比较, 显示RTEMS 最适用于研究开发高性能、高可靠性的综合接入设备。

    fedora安装rtems4.11

    fedora开发rtems4.11笔记!

    uart.rar_RTEMS_rtems uart

    tq2440 rtems 下的uart串口驱动程序

    rtems介绍与使用指南

    本文简述了RTEMS的概念,其与posix标准的区别以及环境搭建

    skyeye 1.2.2 仿真 rtems csb337

    skyeye 1.2.2 仿真 rtems csb337,已经打过补丁

    ppc上的rtems移植

    在powerpc上移植rtems系统的文档

Global site tag (gtag.js) - Google Analytics