zoukankan      html  css  js  c++  java
  • 【转】链接脚本

    出自http://blog.csdn.net/sunjiajiang/article/details/7098272

    脚本的主要目的是描述如何把输入文件中的节(sections)映射到输出文件中,并控制

    输出文件的存储布局。


    1:输出什么

    2:输入是什么,那么obj文件

    3:要用什么库,库放在什么地方

    4:内存分布地址

    5:提供启动代码一些全局地址变量

    ——————————————————————————————————————————

    1:设置入口函数

    2:定义一个变量并赋值

    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对入口的一个选择优先级,12是一样的,显示的指明入口,这也是推荐的方法,没人会觉得程序员故弄玄虚是什么好事情。3是连接器的智能吧,而45就是无奈的选择了,程序员没干好的事情CPU只要猜着来处理了,有.text段的话就从它开始执行吧,连.text都没有的就从0x00000000开始执行


    关于定义变量,其实一般的脚本都会有的,目的只有一个,给汇编启动代码提地址信息。

    比如说,一段需要清零的区域在脚本里定义了,而脚本自己不是变形金刚,他不能主动给你清零的,需要你自己的启动代码来清零,清零的代码当然在汇编的启动代码里,它怎么知道需要清零的内存在什么地方?就靠脚本里定义的变量了。没错,事情就是这样的,那也就说一定会有一个提取地址的方法将地址赋给变量了哦,yes!就是小小的一个点"."

    RAM_START= .;

    定义了一个RAM_START变量,地址是当前的地址,什么是当前的地址啊?就是链接器在连接的时候根据前面的段排列后的当前位置。当然也可以设置当前位置的值,不过最好不要小于前面排列需要的最小内存。

    .= 0x00000000

    定义当前地址为0x0。



    —————————————3:描述输入输出文件的链接规则——————————

    MEMORY

    它是用来补充SECTIONS命令的,用来描述目标CPU中可用的内存区域。它是可选的,如果没有这个命令,LD会认为SECTIONS描述的相邻的内存块之间有足够可用的内存。其实很容易理解但是却很少用(我没用过,嘿嘿),在SECTIONS中每个段的分布都没有考虑ARM能够寻址的地址中,ROM,RAM,FLASH是不是连续的。如果不是连续的怎么办?MEMORY就是设置各个区的起始位置,大小,属性的命令,在一个脚本中只能有一个。

    举一个例子:

    如果你的板子有两段存储,而且很遗憾的是不是连续的,一段是从0x0开始,大小为256K,另一段是从0x40000000开始的大小为4M,你可以在脚本中写入如下的代码来描述你的板子的内存信息。

    MEMORY

    {

    rom(rx) : ORIGIN = 0, LENGTH = 256K

    ram(!rx) : org = 0x40000000, l = 4M

    }


    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'     Initializedsections.
    `L'    Same as I.
    `!'   Invert the sense of any of the following attributes.

    ORIGIN:这是起始地址

    LENGTH:段长

    由此可见上面那段实例显示ROMRAM的明确位置,而且还显示了他们的职能,一个存代码,一个除了存代码什么都可以。


    SECTIONS

    它是脚本文件中最重要的元素,不可缺省。它的作用就是用来描述输出文件的布局。

    SECTIONS命令的语法:

    SECTIONS

    {
          ...
          secname start BLOCK(align)(NOLOAD) : AT ( ldadr )
          { contents} >region :phdr =fill
          ...
    }

    这么多的参数中,只有secname和contents是必须的,其他都是可选的参数。也就说它的最简单的格式就是:

    SECTIONS

    {
          ...
          secname  : {

                    contents

         
         ...
    }

    但是注意:secname前后的两个空格是必须的,否则就是不合法输入。

    secname定义了段名,其实最开始就忽略了一个重要的因素,arm-gcc-ld脚本需要描述输入和输出,而表面上一看却看不出来什么是输入什么事输入,其实secnamecontents就是描述这两个信息的参数。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):用的比较多的是ALIGN4)这样的标记,表示排列地址的时候按4的倍数排列,这样做的理由很简单,系统会快。

    ATaddr):实现存放地址和加载地址不一致的功能,AT表示在文件中存放的位置,而在内存里呢,按照普通方式存储。

    >region:好戏来了,这个region就是前面说的MEMORY命令定义的位置信息。表明当前section所放置的mem有什么特点

    注释:

     和c语言一样,/**/



    SECTIONS

    {

    .=0x30000000;

    .text: { *(.text) }

    .data: { *(.data) }

    .rodata: { *(.rodata) }

    Image_ZI_Base= .;

    .bss: { *(.bss) }

    Image_ZI_Limit= .;

    .debug_info 0 : { *(.debug_info) }

    .debug_line 0 : { *(.debug_line) }

    .debug_abbrev 0 : { *(.debug_abbrev)}

    .debug_frame 0 : { *(.debug_frame) }

    }
    PROVIDE(__stack = .);

    end= .;

    _end= .;

    __bss_start__= .;

    __bss_end__= .;

    __EH_FRAME_BEGIN__= .;

    __EH_FRAME_END__= .;

    Image_RO_Limit= .;

    Image_RW_Base= .;

    Image_RO_Base= .;

    Image_RW_Limit= .;

     
    1
    0
  • 相关阅读:
    三、thinkphp
    二、thinkphp
    一、thinkphp
    层次数据结构字符串处理,split函数使用
    jquery div层级选择器
    css ul li 制作导航条
    个人Android作品开发——FinancePad记账通
    springMVC+ibatis数据持久化入门级学习例子
    java reflect 例子
    java给图片加水印代码
  • 原文地址:https://www.cnblogs.com/libra13179/p/6159097.html
Copyright © 2011-2022 走看看