可分配节。 `I'
已初始化节。 `L'
同‘I’ `!'
对前一个属性值取反。
如果一个未映射节匹配了上面除'!'之外的一个属性,它就会被放入该内存区域。'!'属性对该测试取反,所以只有当它不匹配上面列出的行何属性时,一个未映射节才会被放入到内存区域。
ORIGIN是一个关于内存区域地始地址的表达式。在内存分配执行之前,这个表达式必须被求值产生一个常数,
这意味着你不可以使用任何节相关的符号。关键字'ORIGIN'可以被缩写为'org'或'o'(但是,不可以写为,比 如‘ORG’)
LEN是一个关于内存区域长充(以字节为单位)的表达式。就像ORIGIN表达式,这个表达式在分配执行前也
必须被求得为一个常数值。关键字'LENGTH'可以被简写为‘len'或'l'。 在下面的例子中,我们指定两个可用于分配的内存区域:一个从0开始,有256kb长度,另一个从0x4000000开始,有4mb长度。连接器会把那些没有进行显式映射且是只读或可执行的节放到'rom'内存区域。并会把另外的没有被显式映射地节放入到'ram'内存区域。
MEMORY {
rom (rx) : ORIGIN = 0, LENGTH = 256K ram (!rx) : org = 0x40000000, l = 4M }
一旦你定义了一个内存区域,你也可以指示连接器把指定的输出段放入到这个内存区域中,这可以通过使用'>REGION'输出段属性。比如,如果你有一个名为'mem'的内存区域,你可以在输出段定义中使用'>mem'。如果没有为输出段指定地址,连接器就会把地址设置为内存区域中的下一个可用的地址。如果总共的映射到一个内存区域的输出段对于区域来说太大了,连接器会提示一条错误信息。 PHDRS命令 =============
ELF目标文件格式使用“程序头”,它也就是人们熟知的“节”。程序头描述了程序应当如何被载入到内存中。
你可以通过使用带有'-p'选项的‘objdump’命令来打印出这个程序头。
当你在一个纯ELF系统上运行ELF程序时,系统的载入程序通过读取文件头来计算得到如何来载入这个文件。这
只在程序头被正确设置的情况下才会正常工作。本手册并不打算介绍系统载入程序如何解释文件头的相关细节
问题;关于更多信息,请参阅ELF ABI。
连接顺在缺省状态下会自己创建一个可用的程序头。但是,在某些情况下,你可能需要更为精确地指定程序头。
你可以使用命令‘PHDRS’达到这个目的。当连接器在连接脚本中看到‘PHDRS’命令时,它只会创建被指定了 的程序头。
连接器只在产生ELF输出文件时关心‘PHDRS’命令。在其它情况下,连接器只是简单地忽略‘PHDRS’。
下面是‘PHDRS’命令的语法。单词‘PHDRS’,‘FILEHDR’,‘AT’和‘FLAGS’都是关键字。
PHDRS {
NAME TYPE [ FILEHDR ] [ PHDRS ] [ AT ( ADDRESS ) ] [ FLAGS ( FLAGS ) ] ; }
NAME只在连接脚本的‘SECTIONS’命令中引用时用到。它不会被放到输出文件中。程序头的名字会被存储到单独
的名字空间中。每一个程序头都必须有一个唯一的名字。
某些特定类型的程序头描述系统载入程序要从文件中载入到内存的节。在连接脚本中,你通过把可载入的输出节放
到段中来指定这些段的内容。你可以使用‘:PHDR’输出节属性把一个节放到一个特定的段中。
把某些节放到多个段中也是正常的。这仅仅暗示了一个内存段中含有另一个段。你可以重复使用‘:PHDR’,在每
一个应当含有这个节的段中使用它一次。
如果你使用‘:PHDR’把一个节放到多个段中,那连接器把随后的所有没有指定‘:PHDR’的可分配节都放到同一个
段中。这是为了方便,因为通常一串连续的节会被放到一个单独的段中。你可以使用‘:NONE’来覆盖缺省的段,
告诉连接器不要把节放到任何一个段中。
你可能在程序头类型后面使用‘FILEHDR’和‘PHDRS’关键字来进一步描述段的内容。‘FILEHDR’关键字表示段应
当包含ELF文件头。‘PHDRS’关键字表示段应当包含ELF程序头本身。
TYPE可以是如下的一个。数字表示关键字的值。
`PT_NULL' (0)
表示一个不用的程序头。
`PT_LOAD' (1)
表示这个程序头描述了一个被从文件中载入的段。
`PT_DYNAMIC' (2)
表示一个可以从中找到动态链接信息的段。
`PT_INTERP' (3)
表示一个可以从中找到关于程序名解释的段。
`PT_NOTE' (4)
表示一个存有备注信息的段。
`PT_SHLIB' (5)
一个保留的程序头类型,被定义了,但没有被ELF ABI指定。
`PT_PHDR' (6)
表示一个可以从中找到程序头的段。
EXPRESSION
一个给出程序头的数值类型的表达式。这可以在使用上面未定义的类型时使用。
你可以通过使用‘AT’表达式指定一个段应当被载入到内存中的一个特定的地址。这跟
在输出节属性中使用‘AT’命令是完全一样的。程序头中的‘AT’命令会覆盖输出节属 性中的。
连接器通常会基于组成段的节来设置段属性。你可以通过使用‘FLAGS’关键字来显式指
定段标志。FLAGS的值必须是一个整型值。它被用来设置程序头的‘p_flags'域。
这里是一个关于‘PHDRS’的例子。它展示一个在纯ELF系统上的一个标准的程序头设置。
PHDRS {
headers PT_PHDR PHDRS ;
interp PT_INTERP ;
text PT_LOAD FILEHDR PHDRS ; data PT_LOAD ;
dynamic PT_DYNAMIC ; }
SECTIONS {
. = SIZEOF_HEADERS;
.interp : { *(.interp) } :text :interp .text : { *(.text) } :text
.rodata : { *(.rodata) } /* defaults to :text */ ...
. = . + 0x1000; /* move to a new page in memory */ .data : { *(.data) } :data
.dynamic : { *(.dynamic) } :data :dynamic ... }
VERSION命令 ===============
在使用ELF时,连接器支持符号版本。符号版本只在使用共享库时有用。动态连接器在运行一个
可能跟一个更早版本的共享库链接程序时,可以使用符号版本来选择一个函数的特定版本。
你可以直接在主连接脚本中包含一个版本脚本,或者你可以以一个隐式连接脚本的形式提供这个
版本脚本。你也可以使用‘--version-script'连接器选项。
‘VERSION’命令的语法很简单:
VERSION { version-script-commands }
版本脚本命令的格式跟Sun在Solaris 2.5中的连接器的格式是完全一样的。版本脚本定义一个版本
节点树。你可以在版本脚本中指定节点名和依赖关系。你可以指定哪些符号被绑定到哪些版本节点
上,你还可以把一组指定的符号限定到本地范围,这样在共享库的外面它们就不是全局可见的了。
最简单的演示版本脚本语言的方法是出示几个小例子:
VERS_1.1 { global: foo1; local: old*;
original*; new*; };
VERS_1.2 { foo2;
} VERS_1.1;
VERS_2.0 { bar1; bar2; } VERS_1.2;
这个示例版本脚本定义了三个版本节点。第一个版本节点定义为‘VERS_1.1’它没有其它的依赖。
脚本把符号‘foo1’绑定给‘VERS_1.1’。它把一些数量的符号限定到本地范围,这样它们在共
享库的外面就不可见了;这是通过通配符来完成的,所以任何名字以‘old’,‘original’或
‘new’开头的符号都会被匹配。可用的通配符跟在shell中匹配文件名时一样。
下面,版本脚本定义一个节点‘VER_1.2’。这个节点依赖‘VER_1.1’。脚本把符号‘foo2’绑
定给节点‘VERS_1.2’。
最后,版本脚本定义节点‘VERS_2.0’。这个节点依赖‘VERS_1.2’。脚本把符号‘bar1’和
‘bar2 ’绑定给版本节点‘VERS_2.0’。
当连接器发现一个定义在库中的符号没有被指定绑定到一个版本节点,它会把它绑定到一个未指
定基础版本的库。你可以通过使用‘global: *;’把所有未指定的符号绑定到一个给定的版本节 点上。
版本节点的名字没有任何特殊的含义只是为了方便人们阅读。版本‘2.0’可以出现在‘1.1’和
‘1.2’之间。但是,在书写版本脚本时,这会是一个引起混乱的办法。
如果在版本脚本中,这是一个唯一的版本节点,节点名可以被省略。这样的版本
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说教育文库ld中文使用手册完全版(5)在线全文阅读。
相关推荐: