【转】链接脚本

出自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对入口的一个选择优先级,1和2是一样的,显示的指明入口,这也是推荐的方法,没人会觉得程序员故弄玄虚是什么好事情。3是连接器的智能吧,而4和5就是无奈的选择了,程序员没干好的事情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:段长

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

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语言一样,/**/

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
时间: 2024-11-07 21:13:14

【转】链接脚本的相关文章

关于链接脚本中程序入口的一些问题

http://www.jb51.net/article/62360.htm 在编写普通的c语言程序时,我们都会先写一个main函数,并认为main函数是所有程序的入口函数,其实main函数只是我们所编写的程序的入口函数,真正可执行文件的入口点并不是main函数,在执行main函数之前还有许多的初始化工作需要做,这些在main函数之前的工作是由标准 C 库完成的,然后再由标准  C 库调用main函数. 真正可执行文件的入口点可以通过查看链接脚本(在使用ld命令时加上-verbose参数)可以看出

Linux链接脚本学习--lds(转)

Linux链接脚本学习--lds 一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制,这个脚本是用链接命令语言书写的. 二.链接脚本 链接脚本的一个主要目的是描述输入文件中的各个段(数据段,代码段,堆,栈,bss)如何被映射到输出文件中,并控制输出文件的内存排布. 链接器总是使用链接脚本的,如果你不提供,则链接器会使用一个缺省的脚本,这个脚本是被编

链接脚本之LMA VMA解释

链接脚本中的LMA和VMA是什么意思.这个问题纠结了一段时间,今天在看<ARM体系结构与编程>时,豁然开朗,写下自己的认识.分享例如以下: LMA:载入地址 位于存储器中的地址  LOAD MEMORY ADDRESS VMA:执行地址(虚拟地址) 执行时的地址 VIRTUAL MEMORY ADDRESS  为什么用VMA表示呐?由于cpu执行的地址都是虚拟地址,经过MMU转为物理地址.在没有开MMU的裸板下,延续了这一称呼.理解为执行地址. 为什么要分 两种地址? 执行映像文件时,有些域能

重定位和链接脚本

大部分指令是"位置有关编码" 位置无关编码:汇编源文件编码成二进制可执行程序时,编码方式与位置无关. 在我们写程序时,必须给编译器链接器指定地址.将来的程序被执行时必须放在当时编译链接时给定的地址才能运行. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 但是也有一种特别的指令他可以跟指定的链接地址没有关系,这些代码不管放在哪里都可以正常运行. 分析: 之前的裸机程序中,makefile中用-Ttext 0x0来指定链接地址是0x0;这意味着我们认为将来这个程序会被

powerpc uboot链接脚本大改造

在做完了linux由arm处理器核移植到ppc处理器核的工作后,还需要进行uboot的移植,之前对uboot的分析文章都是基于arm平台,感兴趣的朋友可以看看,链接如下: http://blog.csdn.net/column/details/uboot-note.html 借这次ppc移植工作,也学习了ppc uboot的相关知识,顺道写几篇文章记录下. 工作背景是公司处理器由arm处理器核cortex A8换为ppc处理器核ppc460s,现在处于FPGA仿真验证阶段,SOC的外设控制器都没

内核移植(四)——Makefile和链接脚本分析

1:Makefile分析 (1) kernel的Makefile写法和规则等和uboot的Makefile是一样的,甚至Makefile中的很多内容都是一样的. (2) kernel的Makefile比uboot的Makefile要复杂,这里我们并不会一行一行的详细分析. (3) Makefile中只有一些值得关注的我会强调一下,其他不强调的地方暂时可以不管. (4) Makefile中刚开始定义了kernel的内核版本号.这个版本号挺重要(在模块化驱动安装时会需要用到),要注意会查,会改. (

linux 内核移植(四)——Makefile和链接脚本分析

1:Makefile分析 (1) kernel的Makefile写法和规则等和uboot的Makefile是一样的,甚至Makefile中的很多内容都是一样的. (2) kernel的Makefile比uboot的Makefile要复杂,这里我们并不会一行一行的详细分析. (3) Makefile中只有一些值得关注的我会强调一下,其他不强调的地方暂时可以不管. (4) Makefile中刚开始定义了kernel的内核版本号.这个版本号挺重要(在模块化驱动安装时会需要用到),要注意会查,会改. (

第二部分:S5PV210_重定位和链接脚本_2

重定位和链接脚本 (1)重定位:分为静态重定位和动态重定位 静态重定位:静态重定位是在程序执行之前进行重定位,它根据装配模块将要装入的内存起始位置,直接修改装配模块中的有关使用地址的指令 我们下面要分析就是静态重定位的情况. 动态重定位:动态重定位是指,不是在程序执行之前而是在程序执行过程中进行地址重定位.更确切地说,是在每次访问内存单元前才进行地址变换.动态重定位可使装配模块不加任何修改而装入内存,但是它需要硬件——定位寄存器的支持. 图片的参考来源:http://c.biancheng.ne

重定位与链接脚本

1.为什么需要重定位 位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执

u-boot链接脚本分析

eclipse 64位下载地址:http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/kepler/SR1/eclipse-standard-kepler-SR1-win32-x86_64.zip 如果从nand flash 启动,0地址就对应的是nand flash ,nand flash 不能像内存那样去写,通过这个可以判断是否是从nand flash 启动 U-boot最根本