GNU ld使用手册
- 格式:pdf
- 大小:814.85 KB
- 文档页数:47
ld选项和lds文件==================================================================================0. Contents1. 概论2. 基本概念3. 脚本格式4. 简单例子5. 简单脚本命令6. 对符号的赋值7. SECTIONS命令8. MEMORY命令9. PHDRS命令10. VERSION命令11. 脚本内的表达式12. 暗含的连接脚本1. 概论--------------------------------------------------------------------------------每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局. 但你也可以用连接命令做一些其他事情.连接器有个默认的内置连接脚本, 可用ld --verbose查看. 连接选项-r和-N可以影响默认的连接脚本(如何影响?).-T选项用以指定自己的链接脚本, 它将代替默认的连接脚本.你也可以使用<暗含的连接脚本>以增加自定义的链接命令.以下没有特殊说明,连接器指的是静态连接器.2. 基本概念--------------------------------------------------------------------------------链接器把一个或多个输入文件合成一个输出文件.输入文件: 目标文件或链接脚本文件.输出文件: 目标文件或可执行文件.目标文件(包括可执行文件)具有固定的格式, 在UNIX或GNU/Linux平台下, 一般为ELF格式. 若想了解更多, 可参考UNIX/Linux平台可执行文件格式分析有时把输入文件内的section称为输入section(input section), 把输出文件内的section称为输出section(output sectin).目标文件的每个section至少包含两个信息: 名字和大小. 大部分section还包含与它相关联的一块数据, 称为section contents(section内容). 一个section可被标记为“loadable(可加载的)”或“allocatable(可分配的)”.loadable section: 在输出文件运行时, 相应的section内容将被载入进程地址空间中.allocatable section: 内容为空的section可被标记为“可分配的”. 在输出文件运行时, 在进程地址空间中空出大小同section指定大小的部分. 某些情况下, 这块内存必须被置零.如果一个section不是“可加载的”或“可分配的”, 那么该section通常包含了调试信息. 可用objdump -h命令查看相关信息.每个“可加载的”或“可分配的”输出section通常包含两个地址: VMA(virtual memory address虚拟内存地址或程序地址空间地址)和LMA(load memory address加载内存地址或进程地址空间地址). 通常VMA和LMA是相同的.在目标文件中, loadable或allocatable的输出section有两种地址: VMA(virtual Memory Address)和LMA(Load Memory Address). VMA是执行输出文件时section所在的地址, 而LMA是加载输出文件时section所在的地址. 一般而言, 某section的VMA == LMA. 但在嵌入式系统中, 经常存在加载地址和执行地址不同的情况: 比如将输出文件加载到开发板的flash中(由LMA指定), 而在运行时将位于flash中的输出文件复制到SDRAM中(由VMA指定).可这样来理解VMA和LMA, 假设:(1) .data section对应的VMA地址是0x08050000, 该section内包含了3个32位全局变量, i、j和k, 分别为1,2,3.(2) .text section内包含由"printf( "j=%d ", j );"程序片段产生的代码.连接时指定.data section的VMA为0x08050000, 产生的printf指令是将地址为0x08050004处的4字节内容作为一个整数打印出来.如果.data section的LMA为0x08050000,显然结果是j=2如果.data section的LMA为0x08050004,显然结果是j=1还可这样理解LMA:.text section内容的开始处包含如下两条指令(intel i386指令是10字节,每行对应5字节):jmp 0x08048285movl $0x1,%eax如果.text section的LMA为0x08048280, 那么在进程地址空间内0x08048280处为“jmp 0x08048285”指令, 0x08048285处为movl $0x1,%eax指令. 假设某指令跳转到地址0x08048280, 显然它的执行将导致%eax寄存器被赋值为1.如果.text section的LMA为0x08048285, 那么在进程地址空间内0x08048285处为“jmp 0x08048285”指令, 0x0804828a处为movl $0x1,%eax指令. 假设某指令跳转到地址0x08048285, 显然它的执行又跳转到进程地址空间内0x08048285处, 造成死循环.符号(symbol): 每个目标文件都有符号表(SYMBOL TABLE), 包含已定义的符号(对应全局变量和static变量和定义的函数的名字)和未定义符号(未定义的函数的名字和引用但没定义的符号)信息.符号值: 每个符号对应一个地址, 即符号值(这与c程序内变量的值不一样, 某种情况下可以把它看成变量的地址). 可用nm命令查看它们. (nm的使用方法可参考本blog的GNU binutils笔记)3. 脚本格式--------------------------------------------------------------------------------链接脚本由一系列命令组成, 每个命令由一个关键字(一般在其后紧跟相关参数)或一条对符号的赋值语句组成. 命令由分号‘;’分隔开.文件名或格式名内如果包含分号';'或其他分隔符, 则要用引号‘"’将名字全称引用起来. 无法处理含引号的文件名./* */之间的是注释.4. 简单例子--------------------------------------------------------------------------------在介绍链接描述文件的命令之前, 先看看下述的简单例子:以下脚本将输出文件的text section定位在0x10000, data section定位在0x8000000:SECTIONS{. = 0x10000;.text : { *(.text) }. = 0x8000000;.data : { *(.data) }.bss : { *(.bss) }}解释一下上述的例子:. = 0x10000 : 把定位器符号置为0x10000 (若不指定, 则该符号的初始值为0)..text : { *(.text) } : 将所有(*符号代表任意输入文件)输入文件的.text section合并成一个.text section, 该section的地址由定位器符号的值指定, 即0x10000.. = 0x8000000 :把定位器符号置为0x8000000.data : { *(.data) } : 将所有输入文件的.text section合并成一个.data section, 该section的地址被置为0x8000000..bss : { *(.bss) } : 将所有输入文件的.bss section合并成一个.bss section,该section的地址被置为0x8000000+.data section的大小.连接器每读完一个section描述后, 将定位器符号的值*增加*该section的大小. 注意: 此处没有考虑对齐约束.5. 简单脚本命令--------------------------------------------------------------------------------- 1 -ENTRY(SYMBOL) : 将符号SYMBOL的值设置成入口地址.入口地址(entry point): 进程执行的第一条用户空间的指令在进程地址空间的地址)ld有多种方法设置进程入口地址, 按一下顺序: (编号越前, 优先级越高)1, ld命令行的-e选项2, 连接脚本的ENTRY(SYMBOL)命令3, 如果定义了start符号, 使用start符号值4, 如果存在.text section, 使用.text section的第一字节的位置值5, 使用值0- 2 -INCLUDE filename : 包含其他名为filename的链接脚本相当于c程序内的的#include指令, 用以包含另一个链接脚本.脚本搜索路径由-L选项指定. INCLUDE指令可以嵌套使用, 最大深度为10. 即: 文件1内INCLUDE文件2, 文件2内INCLUDE文件3... , 文件10内INCLUDE文件11. 那么文件11内不能再出现INCLUDE 指令了.- 3 -INPUT(files): 将括号内的文件做为链接过程的输入文件ld首先在当前目录下寻找该文件, 如果没找到, 则在由-L指定的搜索路径下搜索. file可以为-lfile形式,就象命令行的-l选项一样. 如果该命令出现在暗含的脚本内, 则该命令内的file在链接过程中的顺序由该暗含的脚本在命令行内的顺序决定.- 4 -GROUP(files) : 指定需要重复搜索符号定义的多个输入文件file必须是库文件, 且file文件作为一组被ld重复扫描,直到不在有新的未定义的引用出现.- 5 -OUTPUT(FILENAME) : 定义输出文件的名字同ld的-o选项, 不过-o选项的优先级更高. 所以它可以用来定义默认的输出文件名. 如a.out- 6 -SEARCH_DIR(PATH) :定义搜索路径,同ld的-L选项, 不过由-L指定的路径要比它定义的优先被搜索.- 7 -STARTUP(filename) : 指定filename为第一个输入文件在链接过程中, 每个输入文件是有顺序的. 此命令设置文件filename为第一个输入文件.- 8 -OUTPUT_FORMAT(BFDNAME) : 设置输出文件使用的BFD格式同ld选项-o format BFDNAME, 不过ld选项优先级更高.- 9 -OUTPUT_FORMAT(DEFAULT,BIG,LITTLE) : 定义三种输出文件的格式(大小端)若有命令行选项-EB, 则使用第2个BFD格式; 若有命令行选项-EL,则使用第3个BFD格式.否则默认选第一个BFD格式.TARGET(BFDNAME):设置输入文件的BFD格式同ld选项-b BFDNAME. 若使用了TARGET命令, 但未使用OUTPUT_FORMAT命令, 则最用一个TARGET命令设置的BFD格式将被作为输出文件的BFD格式.另外还有一些:ASSERT(EXP, MESSAGE):如果EXP不为真,终止连接过程EXTERN(SYMBOL SYMBOL ...):在输出文件中增加未定义的符号,如同连接器选项-uFORCE_COMMON_ALLOCATION:为common symbol(通用符号)分配空间,即使用了-r连接选项也为其分配NOCROSSREFS(SECTION SECTION ...):检查列出的输出section,如果发现他们之间有相互引用,则报错.对于某些系统,特别是内存较紧张的嵌入式系统,某些section是不能同时存在内存中的,所以他们之间不能相互引用.OUTPUT_ARCH(BFDARCH):设置输出文件的machine architecture(体系结构),BFDARCH为被BFD库使用的名字之一.可以用命令objdump -f查看.可通过man -S 1 ld查看ld的联机帮助, 里面也包括了对这些命令的介绍.6. 对符号的赋值--------------------------------------------------------------------------------在目标文件内定义的符号可以在链接脚本内被赋值. (注意和C语言中赋值的不同!) 此时该符号被定义为全局的. 每个符号都对应了一个地址, 此处的赋值是更改这个符号对应的地址.e.g. 通过下面的程序查看变量a的地址:/* a.c */#include <stdio.h>int a = 100;int main(void){printf( "&a=0x%p ", &a );return 0;}/* a.lds */a = 3;$ gcc -Wall -o a-without-lds a.c&a = 0x8049598$ gcc -Wall -o a-with-lds a.c a.lds&a = 0x3注意: 对符号的赋值只对全局变量起作用!一些简单的赋值语句能使用任何c语言内的赋值操作:SYMBOL = EXPRESSION ;SYMBOL += EXPRESSION ;SYMBOL -= EXPRESSION ;SYMBOL *= EXPRESSION ;SYMBOL /= EXPRESSION ;SYMBOL <<= EXPRESSION ;SYMBOL >>= EXPRESSION ;SYMBOL &= EXPRESSION ;SYMBOL |= EXPRESSION ;除了第一类表达式外, 使用其他表达式需要SYMBOL被定义于某目标文件.. 是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置(或某section内的偏移,如果它在SECTIONS命令内的某section描述内),该符号只能在SECTIONS命令内使用.注意:赋值语句包含4个语法元素:符号名、操作符、表达式、分号;一个也不能少.被赋值后,符号所属的section被设值为表达式EXPRESSION所属的SECTION(参看11. 脚本内的表达式)赋值语句可以出现在连接脚本的三处地方:SECTIONS命令内,SECTIONS命令内的section描述内和全局位置;如下,floating_point = 0; /* 全局位置*/SECTIONS{.text :{*(.text)_etext = .; /* section描述内*/}_bdata = (. + 3) & ~ 4; /* SECTIONS命令内*/.data : { *(.data) }}PROVIDE关键字该关键字用于定义这类符号:在目标文件内被引用,但没有在任何目标文件内被定义的符号.例子:SECTIONS{.text :{*(.text)_etext = .;PROVIDE(etext = .);}}当目标文件内引用了etext符号,确没有定义它时,etext符号对应的地址被定义为.text section之后的第一个字节的地址.7. SECTIONS命令--------------------------------------------------------------------------------SECTIONS命令告诉ld如何把输入文件的sections映射到输出文件的各个section: 如何将输入section合为输出section; 如何把输出section放入程序地址空间(VMA)和进程地址空间(LMA).该命令格式如下:SECTIONS{SECTIONS-COMMANDSECTIONS-COMMAND...}SECTION-COMMAND有四种:(1) ENTRY命令(2) 符号赋值语句(3) 一个输出section的描述(output section description)(4) 一个section叠加描述(overlay description)如果整个连接脚本内没有SECTIONS命令, 那么ld将所有同名输入section合成为一个输出section内, 各输入section的顺序为它们被连接器发现的顺序.如果某输入section没有在SECTIONS命令中提到, 那么该section将被直接拷贝成输出section.输出section描述输出section描述具有如下格式:SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]{OUTPUT-SECTION-COMMANDOUTPUT-SECTION-COMMAND...} [>REGION] [AT>LMA_REGION] [:PHDR :PHDR ...] [=FILLEXP][ ]内的内容为可选选项, 一般不需要.SECTION:section名字SECTION左右的空白、圆括号、冒号是必须的,换行符和其他空格是可选的.每个OUTPUT-SECTION-COMMAND为以下四种之一,符号赋值语句一个输入section描述直接包含的数据值一个特殊的输出section关键字输出section名字(SECTION):输出section名字必须符合输出文件格式要求,比如:a.out格式的文件只允许存在.text、.data和.bss section名.而有的格式只允许存在数字名字,那么此时应该用引号将所有名字内的数字组合在一起;另外,还有一些格式允许任何序列的字符存在于section名字内,此时如果名字内包含特殊字符(比如空格、逗号等),那么需要用引号将其组合在一起.输出section地址(ADDRESS):ADDRESS是一个表达式,它的值用于设置VMA.如果没有该选项且有REGION选项,那么连接器将根据REGION设置VMA;如果也没有REGION选项,那么连接器将根据定位符号‘.’的值设置该section的VMA,将定位符号的值调整到满足输出section对齐要求后的值,输出section的对齐要求为:该输出section描述内用到的所有输入section的对齐要求中最严格的.例子:.text . : { *(.text) }和.text : { *(.text) }这两个描述是截然不同的,第一个将.text section的VMA设置为定位符号的值,而第二个则是设置成定位符号的修调值,满足对齐要求后的.ADDRESS可以是一个任意表达式,比如ALIGN(0x10)这将把该section的VMA设置成定位符号的修调值,满足16字节对齐后的.注意:设置ADDRESS值,将更改定位符号的值.输入section描述:最常见的输出section描述命令是输入section描述.输入section描述是最基本的连接脚本描述.输入section描述基础:基本语法:FILENAME([EXCLUDE_FILE (FILENAME1 FILENAME2 ...) SECTION1 SECTION2 ...)FILENAME文件名,可以是一个特定的文件的名字,也可以是一个字符串模式.SECTION名字,可以是一个特定的section名字,也可以是一个字符串模式例子是最能说明问题的,*(.text) :表示所有输入文件的.text section(*(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors)) :表示除crtend.o、otherfile.o文件外的所有输入文件的.ctors section.data.o(.data) :表示data.o文件的.data sectiondata.o :表示data.o文件的所有section*(.text .data) :表示所有文件的.text section和.data section,顺序是:第一个文件的.text section,第一个文件的.data section,第二个文件的.text section,第二个文件的.data section,...*(.text) *(.data) :表示所有文件的.text section和.data section,顺序是:第一个文件的.text section,第二个文件的.text section,...,最后一个文件的.text section,第一个文件的.data section,第二个文件的.data section,...,最后一个文件的.data section下面看连接器是如何找到对应的文件的.当FILENAME是一个特定的文件名时,连接器会查看它是否在连接命令行内出现或在INPUT命令中出现.当FILENAME是一个字符串模式时,连接器仅仅只查看它是否在连接命令行内出现.注意:如果连接器发现某文件在INPUT命令内出现,那么它会在-L指定的路径内搜寻该文件.字符串模式内可存在以下通配符:* :表示任意多个字符? :表示任意一个字符[CHARS] :表示任意一个CHARS内的字符,可用-号表示范围,如:a-z:表示引用下一个紧跟的字符在文件名内,通配符不匹配文件夹分隔符/,但当字符串模式仅包含通配符*时除外.任何一个文件的任意section只能在SECTIONS命令内出现一次.看如下例子,SECTIONS {.data : { *(.data) }.data1 : { data.o(.data) }}data.o文件的.data section在第一个OUTPUT-SECTION-COMMAND命令内被使用了,那么在第二个OUTPUT-SECTION-COMMAND命令内将不会再被使用,也就是说即使连接器不报错,输出文件的.data1 section的内容也是空的.再次强调:连接器依次扫描每个OUTPUT-SECTION-COMMAND命令内的文件名,任何一个文件的任何一个section都只能使用一次.读者可以用-M连接命令选项来产生一个map文件,它包含了所有输入section到输出section的组合信息.再看个例子,SECTIONS {.text : { *(.text) }.DATA : { [A-Z]*(.data) }.data : { *(.data) }.bss : { *(.bss) }}这个例子中说明,所有文件的输入.text section组成输出.text section;所有以大写字母开头的文件的.data section组成输出.DATA section,其他文件的.data section组成输出.data section;所有文件的输入.bss section组成输出.bss section.可以用SORT()关键字对满足字符串模式的所有名字进行递增排序,如SORT(.text*).通用符号(common symbol)的输入section:在许多目标文件格式中,通用符号并没有占用一个section.连接器认为:输入文件的所有通用符号在名为COMMON的section内.例子,.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.ofoo.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内.在输出section存放数据命令:能够显示地在输出section内填入你想要填入的信息(这样是不是可以自己通过连接脚本写程序?当然是简单的程序).BYTE(EXPRESSION) 1 字节SHORT(EXPRESSION) 2 字节LOGN(EXPRESSION) 4 字节QUAD(EXPRESSION) 8 字节SQUAD(EXPRESSION) 64位处理器的代码时,8 字节输出文件的字节顺序big endianness 或little endianness,可以由输出目标文件的格式决定;如果输出目标文件的格式不能决定字节顺序,那么字节顺序与第一个输入文件的字节顺序相同.如:BYTE(1)、LANG(addr).注意,这些命令只能放在输出section描述内,其他地方不行.错误:SECTIONS { .text : { *(.text) } LONG(1) .data : { *(.data) } }正确:SECTIONS { .text : { *(.text) LONG(1) } .data : { *(.data) } }在当前输出section内可能存在未描述的存储区域(比如由于对齐造成的空隙),可以用FILL(EXPRESSION)命令决定这些存储区域的内容,EXPRESSION的前两字节有效,这两字节在必要时可以重复被使用以填充这类存储区域.如FILE(0x9090).在输出section描述中可以有=FILEEXP属性,它的作用如同FILE()命令,但是FILE命令只作用于该FILE指令之后的section区域,而=FILEEXP属性作用于整个输出section区域,且FILE命令的优先级更高!!!输出section内命令的关键字:CREATE_OBJECT_SYMBOLS :为每个输入文件建立一个符号,符号名为输入文件的名字.每个符号所在的section是出现该关键字的section.CONSTRUCTORS :与c++内的(全局对象的)构造函数和(全局对像的)析构函数相关,下面将它们简称为全局构造和全局析构.对于a.out目标文件格式,连接器用一些不寻常的方法实现c++的全局构造和全局析构.当连接器生成的目标文件格式不支持任意section名字时,比如说ECOFF、XCOFF格式,连接器将通过名字来识别全局构造和全局析构,对于这些文件格式,连接器把与全局构造和全局析构的相关信息放入出现CONSTRUCTORS关键字的输出section内.符号__CTORS_LIST__表示全局构造信息的的开始处,__CTORS_END__表示全局构造信息的结束处.符号__DTORS_LIST__表示全局构造信息的的开始处,__DTORS_END__表示全局构造信息的结束处.这两块信息的开始处是一字长的信息,表示该块信息有多少项数据,然后以值为零的一字长数据结束.一般来说,GNU C++在函数__main内安排全局构造代码的运行,而__main函数被初始化代码(在main函数调用之前执行)调用.是不是对于某些目标文件格式才这样???对于支持任意section名的目标文件格式,比如COFF、ELF格式,GNU C++将全局构造和全局析构信息分别放入.ctors section和.dtors section内,然后在连接脚本内加入如下,__CTOR_LIST__ = .;LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)*(.ctors)LONG(0)__CTOR_END__ = .;__DTOR_LIST__ = .;LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)*(.dtors)LONG(0)__DTOR_END__ = .;如果使用GNU C++提供的初始化优先级支持(它能控制每个全局构造函数调用的先后顺序),那么请在连接脚本内把CONSTRUCTORS替换成SORT (CONSTRUCTS),把*(.ctors)换成*(SORT(.ctors)),把*(.dtors)换成*(SORT(.dtors)).一般来说,默认的连接脚本已作好的这些工作.输出section的丢弃:例子,.foo { *(.foo) },如果没有任何一个输入文件包含.foo section,那么连接器将不会创建.foo输出section.但是如果在这些输出section描述内包含了非输入section描述命令(如符号赋值语句),那么连接器将总是创建该输出section.有一个特殊的输出section,名为/DISCARD/,被该section引用的任何输入section将不会出现在输出文件内,这就是DISCARD的意思吧.如果/DISCARD/ section被它自己引用呢?想想看.输出section属性:终于讲到这里了,呵呵.我们再回顾以下输出section描述的文法:SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]{OUTPUT-SECTION-COMMANDOUTPUT-SECTION-COMMAND...} [>REGION] [AT>LMA_REGION] [:PHDR :PHDR ...] [=FILLEXP]前面我们浏览了SECTION、ADDRESS、OUTPUT-SECTION-COMMAND相关信息,下面我们将浏览其他属性.TYPE :每个输出section都有一个类型,如果没有指定TYPE类型,那么连接器根据输出section引用的输入section的类型设置该输出section的类型.它可以为以下五种值,NOLOAD :该section在程序运行时,不被载入内存.DSECT,COPY,INFO,OVERLAY :这些类型很少被使用,为了向后兼容才被保留下来.这种类型的section必须被标记为“不可加载的”,以便在程序运行不为它们分配内存.输出section的LMA :默认情况下,LMA等于VMA,但可以通过关键字AT()指定LMA.用关键字AT()指定,括号内包含表达式,表达式的值用于设置LMA.如果不用AT()关键字,那么可用AT>LMA_REGION表达式设置指定该section加载地址的范围.这个属性主要用于构件ROM境象.例子,SECTIONS{.text 0x1000 : { *(.text) _etext = . ; }.mdata 0x2000 :AT ( ADDR (.text) + SIZEOF (.text) ){ _data = . ; *(.data); _edata = . ; }.bss 0x3000 :{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}}程序如下,extern char _etext, _data, _edata, _bstart, _bend;char *src = &_etext;char *dst = &_data;/* ROM has data at end of text; copy it. */while (dst < &_edata) {*dst++ = *src++;}/* Zero bss */for (dst = &_bstart; dst< &_bend; dst++)*dst = 0;此程序将处于ROM内的已初始化数据拷贝到该数据应在的位置(VMA地址),并将为初始化数据置零.读者应该认真的自己分析以上连接脚本和程序的作用.输出section区域:可以将输出section放入预先定义的内存区域内,例子,MEMORY { rom : ORIGIN = 0x1000, LENGTH = 0x1000 }SECTIONS { ROM : { *(.text) } >rom }输出section所在的程序段:可以将输出section放入预先定义的程序段(program segment)内.如果某个输出section设置了它所在的一个或多个程序段,那么接下来定义的输出section的默认程序段与该输出section的相同.除非再次显示地指定.例子,PHDRS { text PT_LOAD ; }SECTIONS { .text : { *(.text) } :text }可以通过:NONE指定连接器不把该section放入任何程序段内.详情请查看PHDRS命令输出section的填充模版:这个在前面提到过,任何输出section描述内的未指定的内存区域,连接器用该模版填充该区域.用法:=FILEEXP,前两字节有效,当区域大于两字节时,重复使用这两字节以将其填满.例子,SECTIONS { .text : { *(.text) } =0x9090 }覆盖图(overlay)描述:覆盖图描述使两个或多个不同的section占用同一块程序地址空间.覆盖图管理代码负责将section的拷入和拷出.考虑这种情况,当某存储块的访问速度比其他存储块要快时,那么如果将section拷到该存储块来执行或访问,那么速度将会有所提高,覆盖图描述就很适合这种情形.文法如下,SECTIONS {...OVERLAY [START] : [NOCROSSREFS] [AT ( LDADDR )]{SECNAME1{OUTPUT-SECTION-COMMANDOUTPUT-SECTION-COMMAND...} [:PHDR...] [=FILL]SECNAME2{OUTPUT-SECTION-COMMANDOUTPUT-SECTION-COMMAND...} [:PHDR...] [=FILL]...} [>REGION] [:PHDR...] [=FILL]...}由以上文法可以看出,同一覆盖图内的section具有相同的VMA.SECNAME2的LMA为SECTNAME1的LMA加上SECNAME1的大小,同理计算SECNAME2,3,4...的LMA.SECNAME1的LMA由LDADDR 决定,如果它没有被指定,那么由START决定,如果它也没有被指定,那么由当前定位符号的值决定.NOCROSSREFS关键字指定各section之间不能交叉引用,否则报错.对于OVERLAY描述的每个section,连接器将定义两个符号__load_start_SECNAME和__load_stop_SECNAME,这两个符号的值分别代表SECNAME section的LMA地址的开始和结束.连接器处理完OVERLAY描述语句后,将定位符号的值加上所有覆盖图内section大小的最大值.看个例子吧,SECTIONS{...OVERLAY 0x1000 : AT (0x4000){.text0 { o1/*.o(.text) }.text1 { o2/*.o(.text) }}...}.text0 section和.text1 section的VMA地址是0x1000,.text0 section加载于地址0x4000,.text1 section紧跟在其后.程序代码,拷贝.text1 section代码,extern char __load_start_text1, __load_stop_text1;memcpy ((char *) 0x1000, &__load_start_text1,&__load_stop_text1 - &__load_start_text1);8. 内存区域命令---------------注意:以下存储区域指的是在程序地址空间内的.在默认情形下,连接器可以为section分配任意位置的存储区域.你也可以用MEMORY命令定义存储区域,并通过输出section描述的> REGION属性显示地将该输出section限定于某块存储区域,当存储区域大小不能满足要求时,连接器会报告该错误.MEMORY命令的文法如下,MEMORY {NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2...}NAME :存储区域的名字,这个名字可以与符号名、文件名、section名重复,因为它处于一个独立的名字空间.ATTR :定义该存储区域的属性,在讲述SECTIONS命令时提到,当某输入section没有在SECTIONS命令内引用时,连接器会把该输入section直接拷贝成输出section,然后将该输出section放入内存区域内.如果设置了内存区域设置了ATTR属性,那么该区域只接受满足该属性的section(怎么判断该section是否满足?输出section描述内好象没有记录该section的读写执行属性).ATTR属性内可以出现以下7个字符,R 只读sectionW 读/写sectionX 可执行sectionA ‘可分配的’sectionI 初始化了的sectionL 同I! 不满足该字符之后的任何一个属性的sectionORIGIN :关键字,区域的开始地址,可简写成org或oLENGTH :关键字,区域的大小,可简写成len或l例子,MEMORY{rom (rx) : ORIGIN = 0, LENGTH = 256Kram (!rx) : org = 0x40000000, l = 4M}此例中,把在SECTIONS命令内*未*引用的且具有读属性或写属性的输入section放入rom区域内,把其他未引用的输入section放入ram.如果某输出section要被放入某内存区域内,而该输出section又没有指明ADDRESS属性,那么连接器将该输出section放在该区域内下一个能使用位置.9. PHDRS命令------------该命令仅在产生ELF目标文件时有效.ELF目标文件格式用program headers程序头(程序头内包含一个或多个segment程序段描述)来描述程序如何被载入内存.可以用objdump -p命令查看.当在本地ELF系统运行ELF目标文件格式的程序时,系统加载器通过读取程序头信息以知道如何将程序加载到内存.要了解系统加载器如何解析程序头,请参考ELF ABI文档.在连接脚本内不指定PHDRS命令时,连接器能够很好的创建程序头,但是有时需要更精确的描述程序头,那么PAHDRS命令就派上用场了.注意:一旦在连接脚本内使用了PHDRS命令,那么连接器**仅会**创建PHDRS命令指定的信息,所以使用时须谨慎.。
GNU make中文手册ver - 3.8翻译整理:徐海兵2004-09-11目录Table of ContentsGNU make中文手册 (1)ver - 3.8 (1)第一章:概述 (7)1.1概述 (7)1.2准备知识 (8)第二章 GNU make 介绍 (9)2GNU make 介绍 (9)2.1Makefile简介 (10)2.2Makefile规则介绍 (11)2.3简单的示例 (12)2.4make如何工作 (13)2.5指定变量 (15)2.6自动推导规则 (16)2.7另类风格的makefile (17)2.8清除工作目录过程文件 (18)第三章:Makefile 总述 (20)3Makefile总述 (20)3.1Makefile的内容 (20)3.2makefile文件的命名 (21)3.3包含其它makefile文件 (22)3.4变量 MAKEFILES (24)3.5变量 MAKEFILE_LIST (26)3.6其他特殊变量 (26)3.7makefile文件的重建 (27)3.8重载另外一个makefile (28)3.9make如何解析makefile文件 (30)3.9.1变量取值 (30)3.9.2条件语句 (31)3.9.3规则的定义 (31)3.10总结 (31)第四章:Makefile的规则 (33)4Makefile规则 (33)4.1一个例子 (33)4.2规则语法 (34)4.3依赖的类型 (35)4.4文件名使用通配符 (36)4.4.1统配符使用举例 (37)4.4.2通配符存在的缺陷 (38)4.4.3函数wildcard (38)4.5目录搜寻 (39)4.5.1一般搜索(变量VPATH) (39)4.5.2选择性搜索(关键字vpath) (40)4.5.3目录搜索的机制 (41)4.5.4命令行和搜索目录 (44)4.5.5隐含规则和搜索目录 (44)4.5.6库文件和搜索目录 (45)4.7强制目标(没有命令或依赖的规则) (50)4.8空目标文件 (50)4.9Makefile的特殊目标 (51)4.10多目标 (54)4.11多规则目标 (55)4.12静态模式 (56)4.12.1静态模式规则的语法 (56)4.12.2静态模式和隐含规则 (58)4.13双冒号规则 (59)4.14自动产生依赖 (60)第五章:规则的命令 (63)5为规则书写命令 (63)5.1命令回显 (63)5.2命令的执行 (64)5.3并发执行命令 (65)5.4命令执行的错误 (67)5.5中断make的执行 (68)5.6make的递归执行 (69)5.6.1变量MAKE (70)5.6.2变量和递归 (71)5.6.3命令行选项和递归 (75)5.6.4-w选项 (77)5.7定义命令包 (78)5.8空命令 (80)第六章:Makefile中的变量 (81)6使用变量 (81)6.1变量的引用 (82)6.2两种变量定义(赋值) (83)6.2.1递归展开式变量 (83)6.2.2直接展开式变量 (85)6.2.3定义一个空格 (86)6.2.4“?=”操作符 (87)6.3变量的高级用法 (88)6.3.1变量的替换引用 (88)6.3.2变量的套嵌引用 (88)6.4变量取值 (92)6.5如何设置变量 (93)6.6追加变量值 (94)6.7override 指示符 (96)6.8多行定义 (98)6.9系统环境变量 (99)6.10目标指定变量 (101)6.11模式指定变量 (103)第七章:Makefile的条件执行 (104)7Makefile的条件判断 (104)7.1一个例子 (104)7.2条件判断的基本语法 (105)7.3标记测试的条件语句 (108)第八章:make的内嵌函数 (109)8make的函数 (109)8.2文本处理函数 (110)8.2.1$(subst FROM,TO,TEXT) (110)8.2.2$(patsubst PATTERN,REPLACEMENT,TEXT) (110)8.2.3$(strip STRINT) (112)8.2.4$(findstring FIND,IN) (112)8.2.5$(filter PATTERN...,TEXT).. (112)8.2.6$(filter-out PATTERN...,TEXT).. (113)8.2.7$(sort LIST) (113)8.2.8$(word N,TEXT) (114)8.2.9$(wordlist S,E,TEXT) (114)8.2.10$(words TEXT) (114)8.2.11$(firstword NAMES...).. (115)8.3文件名处理函数 (115)8.3.1$(dir NAMES...). (115)8.3.2$(notdir NAMES...).. (116)8.3.3$(suffix NAMES...).. (116)8.3.4$(basename NAMES...) (117)8.3.5$(addsuffix SUFFIX,NAMES...) (117)8.3.6$(addprefix PREFIX,NAMES...) (118)8.3.7$(join LIST1,LIST2) (118)8.3.8$(wildcard PATTERN) (119)8.4foreach 函数 (119)8.5if 函数 (120)8.6call函数 (121)8.7value函数 (123)8.8eval函数 (124)8.9origin函数 (125)8.10shell函数 (127)8.11make的控制函数 (128)8.11.1$(error TEXT...). (128)8.11.2$(warning TEXT...).. (129)第九章:执行make (130)9执行make (130)9.1指定makefile文件 (130)9.2指定终极目标 (131)9.3替代命令的执行 (133)9.4防止特定文件重建 (135)9.5替换变量定义 (136)9.6使用make进行编译测试 (137)9.7T make的命令行选项 (138)第十章:make的隐含规则 (143)10使用隐含规则 (143)10.1隐含规则的使用 (143)10.2make的隐含规则一览 (145)10.3隐含变量 (148)10.3.1代表命令的变量 (149)10.3.2命令参数的变量 (150)10.4make隐含规则链 (151)10.5模式规则 (153)10.5.1模式规则介绍 (153)10.5.2模式规则示例 (155)10.5.3自动化变量 (156)10.5.5万用规则 (160)10.5.6重建内嵌隐含规则 (161)10.6缺省规则 (162)10.7后缀规则 (162)10.8隐含规则搜索算法 (164)第十一章:使用make更新静态库文件 (166)11更新静态库文件 (166)11.1库成员作为目标 (166)11.2静态库的更新 (167)11.2.1更新静态库的符号索引表 (168)11.3make静态库的注意事项 (168)11.4静态库的后缀规则 (169)第十二章: GNU make的特点 (170)12GNU make的一些特点 (170)12.1源自System v的特点 (170)12.2源自其他版本的特点 (171)12.3GNU make自身的特点 (172)第十三章和其它版本的兼容 (174)13不兼容性 (174)第十四章 Makefile的约定 (176)14书写约定 (176)14.1基本的约定 (176)14.2规则命令行的约定 (178)14.3代表命令变量 (179)14.4安装目录变量 (180)14.5Makefile的标准目标名 (185)14.6安装命令分类 (190)第十五章 make的常见错误信息 (193)15make产生的错误信息 (193)附录1:关键字索引 (196)GNU make可识别的指示符: (196)GNU make函数: (197)GNU make的自动化变量 (197)GNU make环境变量 (198)后序 (198)关于本书本文瑾献给所有热爱Linux的程序员!本中文文档版权所有。
ld是Unix系统下的链接器,它主要用于将编译后的目标文件(object files)连接在一起生成可执行文件或库文件。
以下是一些常用的ld编译参数:1. -o output_file:指定输出文件的名称。
如果不指定该选项,ld默认将输出文件命名为a.out。
2. -L search_path:指定库文件的搜索路径。
ld会在指定的路径下查找需要的库文件。
3. -l library:指定需要链接的库文件的名称。
ld会在指定的库文件搜索路径下查找该库文件,并将其链接到输出文件中。
4. -T script_file:指定链接脚本文件的名称。
链接脚本文件描述了如何将各个目标文件和库文件连接在一起生成输出文件。
5. -e entry_point:指定程序的入口点。
如果不指定该选项,ld默认将程序的入口点设置为main函数。
6. -M:生成映射文件。
映射文件描述了输出文件中各个段(section)的地址和大小信息,有助于调试和程序分析。
7. --warn-common:当有多个目标文件定义了相同的公共符号(common symbol)时,输出警告信息。
这有助于发现潜在的符号冲突问题。
8. --verbose:输出详细的链接过程信息,包括搜索路径、链接的库文件、符号解析等。
这有助于调试链接过程中的问题。
9. --gc-sections:删除未使用的段。
这有助于减小输出文件的大小,提高程序的执行效率。
10. --strip-debug:从输出文件中删除调试信息。
这有助于减小输出文件的大小,但会降低调试的便利性。
以上是ld的一些常用编译参数,可以根据需要进行选择和组合使用。
需要注意的是,不同的编译器和操作系统可能支持不同的编译参数,具体请参考相关的文档和手册。
gcc,ldGCCgcc除了具备基本的c⽂件编译功能外,还把其它⼯具的功能也集成了进来,⽐如as的汇编功能,ld的链接功能。
因此,gcc也可以通过-Wa, option,将option传给汇编器as;也可以通过-Wl, option,将option传给链接器ld。
-N,gcc⼿册中没看到该选项,这是属于链接器ld的选项,gcc并没有。
该选项⽤于将text设为writable,见后⾯ld部分介绍。
-L,gcc⼿册中只有-Ldir⽤来设置搜索库⽂件的⽬录,单独⽤-L没看该选项基本选项-S,⼤写Compile only; do not assemble or link,输出汇编⽂件.s-c,⼩写Compile and assemble, but do not link.如果不加-c,那么gcc会直接编译+链接为可执⾏⽂件。
-o <file>Place the output into <file>-vPrint (on standard error output) the commands executed to run the stages of compilation. Also print the version number of the compiler driver program and of the preprocessorand the compiler proper. 下⾯为⼀个例⼦:sparc-elf-gcc.exe -v -c ../src/main.c -o ../obj/main.oReading specs from /cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/specsConfigured with: ../gcc-3.2.3/configure --target=sparc-elf --prefix=/opt/sparc-elf-3.2.3 --with-gnu-as --with-gnu-ld --verbose --enable-languages=c,c++ --disable-shared --disable-nls --with-cpu=leonThread model: singlegcc version 3.2.3/cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/cc1.exe -lang-c -v -iprefix /cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/ -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=3 -D__GXX_ABI_VERSION= GNU CPP version 3.2.3 (cpplib) (sparc ELF)GNU C version 3.2.3 (sparc-elf)compiled by GNU C version 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125).ignoring nonexistent directory "/cygdrive/c/SPE-C2.5/sparc-elf/sys-include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/sys-include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/include"#include "..." search starts here:#include <...> search starts here:/cygdrive/c/SPE-C2.5/lib/gcc-lib/sparc-elf/3.2.3/include/cygdrive/c/SPE-C2.5/sparc-elf/includeEnd of search list./cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/bin/as.exe --traditional-format -V -Qy -s -o ../obj/main.o /cygdrive/c/user/default/AppData/Local/Temp/ccuy9Z2h.sGNU assembler version 2.13.2.1 (sparc-elf) using BFD version 2.13.2.1View Code关于搜索路径的选项-IdirAdd the directory dir to the head of the list of directories to be searched for header files.This can be used to override a system header file, substituting your own version, since thesedirectories are searched before the system header file directories. If you use more than one`-I' option, the directories are scanned in left-to-right order; the standard systemdirectories come after.-LdirAdd directory dir to the list of directories to be searched for `-l'-Bprefix这个和-I,-L有什么关系呢?感觉有点重复。
gcc-ld 用法-回复gccld 是一款用于编译C 和C++ 代码的开源编译器,被广泛应用于各种操作系统和平台上。
在本文中,将一步一步回答关于gccld 的用法。
1. 安装gccldgccld 是GNU Compiler Collection(GCC)的一部分,因此我们首先需要安装GCC。
对于Linux 系统,可以通过包管理器(如apt、yum 或dnf)来安装GCC。
在终端中运行以下命令即可:sudo apt install gcc对于Windows 系统,可以通过MinGW(Minimalist GNU for Windows)来安装GCC。
可以访问MinGW 的官方网站下载安装程序进行安装。
安装完成后,请确保将GCC 的可执行文件路径添加到系统环境变量中。
2. 编写代码使用gccld 编译C 或C++ 代码之前,我们首先需要编写代码。
可以使用任何文本编辑器来创建一个以 .c 或 .cpp 为扩展名的源代码文件。
以下是一个简单的示例C 代码:c#include <stdio.h>int main() {printf("Hello, World!");return 0;}将以上代码保存为`hello.c`。
3. 编译代码进入终端,并导航到保存`hello.c` 文件的目录中。
使用gccld 命令来编译代码。
运行以下命令:gcc -o hello hello.c该命令中的`-o` 选项用于指定输出文件的名称(这里是`hello`),紧随其后的是源代码文件的名称(这里是`hello.c`)。
编译成功后,将在当前目录中生成一个名为`hello` 的可执行文件。
4. 运行程序通过gccld 编译的程序可以直接运行。
在终端中运行以下命令即可:./hello你将会看到输出:Hello, World!5. 其他常用选项gccld 提供了许多其他选项,来帮助我们更好地控制代码编译。
GNU make中文手册ver - 3.8译者:徐海兵2004-09-11目录GNU make中文手册 (1)ver - 3.8 (1)第一章:概述 (7)1.1Make之前基本知识: (7)1.1.1概述 (7)1.1.2准备知识 (8)1.2GNU make介绍 (8)1.2.1Makefile简介 (9)1.2.2Makefile规则介绍 (10)1.2.3简单的示例 (11)1.2.4make如何工作 (12)1.2.5指定变量 (13)1.2.6自动推导规则 (14)1.2.7另类风格的makefile (15)1.2.8清除工作目录过程文件 (16)第二章:Makefile 总述 (16)2Makefile概述 (16)2.1Makefile的内容 (16)2.2makefile文件的命名 (18)2.3包含其它makefile文件 (18)2.4变量MAKEFILES (20)2.5变量MAKEFILE_LIST (21)2.6其他特殊变量 (22)2.7makefile文件的重建 (22)2.8重载另外一个makefile (23)2.9make如何解析makefile文件 (24)2.9.1变量取值 (25)2.9.2条件语句 (25)2.9.3规则的定义 (25)2.10总结 (25)第三章:Makefile的规则 (26)3Makefile规则 (26)3.1一个例子 (27)3.2规则语法 (27)3.3依赖的类型 (28)3.4文件名使用通配符 (29)3.4.1统配符使用举例 (30)3.4.2通配符存在的缺陷 (30)3.4.3函数wildcard (31)3.5目录搜寻 (32)3.5.1一般搜索(变量VPATH) (32)3.5.2选择性搜索(关键字vpath) (32)3.5.3目录搜索的机制 (33)3.5.4命令行和搜索目录 (35)3.5.5隐含规则和搜索目录 (36)3.5.6库文件和搜索目录 (36)3.6Makefile伪目标 (37)3.7强制目标(没有命令或依赖的规则) (40)3.8空目标文件 (41)3.9Makefile的特殊目标 (41)3.10多目标 (44)3.11多规则目标 (44)3.12静态模式 (45)3.12.1静态模式规则的语法 (45)3.12.2静态模式和隐含规则 (47)3.13双冒号规则 (48)3.14自动产生依赖 (49)第四章:规则的命令 (51)4规则中书写命令 (51)4.1命令回显 (51)4.2命令的执行 (52)4.3并发执行命令 (53)4.4命令执行的错误 (54)4.5中断make的执行 (56)4.6make的递归执行 (56)4.6.1变量MAKE (57)4.6.2变量和递归 (58)4.6.3命令行选项和递归 (61)4.6.4-w选项 (63)4.7定义命令包 (63)4.8空命令 (65)第五章:Makefile中的变量 (65)5使用变量 (65)5.1变量的引用 (66)5.2两种变量定义(赋值) (68)5.2.1递归展开式变量 (68)5.2.2直接展开式变量 (69)5.2.3如何定义一个空格 (70)5.2.4“?=”操作符 (71)5.3变量的高级用法 (71)5.3.1变量的替换引用 (72)5.3.2变量的套嵌引用 (72)5.4变量取值 (76)5.5如何设置变量 (76)5.6追加变量值 (77)5.7override 指示符 (79)5.8多行定义 (80)5.9系统环境变量 (81)5.10目标指定变量 (83)5.11模式指定变量 (84)第六章:Makefile的条件执行 (85)6Makefile的条件判断 (85)6.1一个例子 (85)6.2条件判断的基本语法 (86)6.3标记测试的条件语句 (89)第七章:make的内嵌函数 (89)7make的函数 (89)7.1函数的调用语法 (90)7.2文本处理函数 (91)7.2.1$(subst FROM,TO,TEXT) (91)7.2.2$(patsubst PATTERN,REPLACEMENT,TEXT) (91)7.2.3$(strip STRINT) (92)7.2.4$(findstring FIND,IN) (92)7.2.5$(filter PATTERN...,TEXT). (93)7.2.6$(filter-out PATTERN...,TEXT). (93)7.2.7$(sort LIST) (94)7.2.8$(word N,TEXT) (94)7.2.9$(wordlist S,E,TEXT) (94)7.2.10$(words TEXT) (94)7.2.11$(firstword NAMES...). (95)7.3文件名处理函数 (95)7.3.1$(dir NAMES...) (95)7.3.2$(notdir NAMES...). (96)7.3.3$(suffix NAMES...). (96)7.3.4$(basename NAMES...).. (96)7.3.5$(addsuffix SUFFIX,NAMES...).. (97)7.3.6$(addprefix PREFIX,NAMES...).. (97)7.3.7$(join LIST1,LIST2) (98)7.3.8$(wildcard PATTERN) (98)7.4foreach 函数 (98)7.5if 函数 (100)7.6call函数 (100)7.7value函数 (102)7.8eval函数 (103)7.9origin函数 (104)7.10shell函数 (106)7.11make的控制函数 (106)7.11.1$(error TEXT...). (107)7.11.2$(warning TEXT...).. (107)第八章:执行make (108)8执行make (108)8.1指定makefile文件 (108)8.2指定终极目标 (109)8.3替代命令的执行 (111)8.4防止特定文件重建 (112)8.5替换变量定义 (113)8.6使用make进行编译测试 (114)8.7make的命令行选项 (115)第九章:make的隐含规则 (119)9使用隐含规则 (119)9.1隐含规则的使用 (119)9.2make的隐含规则一览 (121)9.3隐含变量 (124)9.3.1代表命令的变量 (124)9.3.2命令参数的变量 (125)9.4make隐含规则链 (126)9.5模式规则 (128)9.5.1模式规则介绍 (128)9.5.2模式规则示例 (129)9.5.3自动化变量 (130)9.5.4模式的匹配 (133)9.5.5万用规则 (133)9.5.6重建内嵌隐含规则 (134)9.6缺省规则 (135)9.7后缀规则 (135)9.8隐含规则搜索算法 (137)第十章:使用make更新静态库文件 (138)10更新静态库文件 (138)10.1库成员作为目标 (138)ARCHIVE(MEMBER) (138)10.2静态库的更新 (139)10.2.1更新静态库的符号索引表 (140)10.3make静态库的注意事项 (141)10.4静态库的后缀规则 (141)第十一章: GNU make的特点 (142)11GNU make的一些特点 (142)11.1源自System v的特点 (142)11.2源自其他版本的特点 (143)11.3GNU make自身的特点 (143)第十二章和其它版本的兼容 (144)12不兼容性 (144)第十三章 Makefile的约定 (146)13书写约定 (146)13.1基本的约定 (146)13.2规则命令行的约定 (147)13.3代表命令变量 (149)13.4安装目录变量 (150)13.5Makefile的标准目标名 (154)13.6安装命令分类 (159)第十四章 make的常见错误信息 (161)14 make产生的错误信息 (161)附录1:关键字索引 (163)GNU make可识别的指示符: (163)GNU make函数: (164)GNU make的自动化变量 (165)GNU make环境变量 (166)后序 (166)关于本书本文瑾献给所有热爱Linux的程序员!本文档版权所有,禁止用于任何商业行为。
ld中文使用手册完全版(译)-1、概述 (4)2、命令行选项 (5)2.1、连接器提供大量的命令行选项 (5)2.2、连接脚本 (5)2.3、对于名称是单个字符的选项 (5)2.4、对于名称是多个字符的选项,选项前可以有一个或两个破折号; (5)2.5、多字符选项的参数 (5)2.5、如果连接器通过,被编译器驱动来间接引用(比如GCC), (6)2.5.1、被GNU连接器接受的常用命令行开关的一个列表 (6)`-aKEYWORD' (6)`-AARCHITECTURE'`--architecture=ARCHITECTURE' (6)`-b INPUT-formAT'`--format=INPUT-formAT' (6)`-cMRI-COMMANDFILE' (6)`-d'`-dc'`-dp' (6)`-e ENTRY'`--entry=ENTRY' (6)`-E'`--export-dynamic' (6)`-EB'连接big-endian对象. 会影响缺省输出格式 (7)`-EL'连接little-endian对象. 会影响缺省输出格式 (7)`-g'忽略. 为了跟其它工具兼容而提供 (7)`-i'执行一个增量连接(跟'-r'等同) (7)`-init NAME' (7)`-lARCHIVE'`--library=ARCHIVE' (7)`-M'`--print-map'打印一个连接位图到标准输出 (7)`-n'`--nmagic', (7)`-N'`--omagic' (7)`--no-omagic' (7)`-o OUTPUT'`--output=OUTPUT' (7)`-O LEVEL' (7)`-q'`--emit-relocs' (7)`-r'`--relocateable' (7)`-R FILENAME'`--just-symbols=FILENAME' (8)`-s'`--strip-all',忽略输出文件中所有的符号信息 (8)`-S'`--strip-debug'忽略输出文件中所有的调试符号信息(但不是所有符号). (8)`-t'`--trace',打印ld处理的所有输入文件的名字 (8)`-T SCRIPTFILE'`--script=SCRIPTFILE' (8)`-u SYMBOL'`--undefined=SYMBOL' (8)`-Ur' (8)`--unique[=SECTION]' (8)`-v'`--version' `-V' (8)`-x'`--discard-all'删除所有的本地符号. (8)`-X'`--discard-locals' (8)`-y SYMBOL'`--trace-symbol=SYMBOL' (8)`-z KEYWORD' (8)`-( ARCHIVES -)'`--start-group ARCHIVES --end-group' (9)`--accept-unknown-input-arch' (9)`-assert KEYWORD'这个选项被忽略,只是用来跟SunOS保持兼容 (9)`-Bdynamic'`-dy'`-call_shared'连接动态链接库 (9)`-Bgroup' (9)'--no-undefined' (9)`-Bstatic'`-dn' `-non_shared' `-static' (9)`-Bsymbolic' (9)`--check-sections'`--no-check-sections' (10)`--cref' (10)`--no-define-common' (10)`--defsym SYMBOL=EXPRESSION' (10)`--demangle[=style]' `--no-demangle' (10)`--dynamic-linker FILE' (10)`--embedded-relocs' (10)`--fatal-warnings'把所有的警告视为错误 (10)`--force-exe-suffix'确保输出文件有一个.exe后缀 (10)`--no-gc-sections'`--gc-sections' (11)`--help'在标准输出上打印一个命令行选项概要,然后退出. (11)`--target-help' (11)`-Map MAPFILE' (11)`--no-keep-memory' (11)`--no-undefined'`-z defs' (11)`--allow-multiple-definition'`-z muldefs' (11)`--allow-shlib-undefined' `--no-allow-shlib-undefined' (11)`--no-undefined-version' (11)`--no-warn-mismatch' (11)`--no-whole-archive' (11)`--noinhibit-exec' (11)`-nostdlib' (12)`--oformat OUTPUT-formAT' (12)`-qmagic'这个选项被忽略,只是为了跟Linux保持兼容 (12)`-Qy'这个选项被忽略,只是为了跟SVR4保持兼容. (12)`--relax' (12)`--retain-symbols-file FILENAME' (12)'--retain-symbols-file' (12)`-rpath DIR' (12)`-rpath-link DIR' (12)`-shared'`-Bshareable' (13)`--sort-common' (13)`--split-by-file [SIZE]' (13)`--split-by-reloc [COUNT]' (13)`--traditional-format' (13)'--trafitinal-format'开关告诉ld 不要把相同的入口合并起来 (13)`--section-start SECTIONNAME=ORG' (13)`-Tbss ORG'`-Tdata ORG' `-Ttext ORG' (14)`--dll-verbose'`--verbose' (14)`--version-script=VERSION-SCRIPTFILE' (14)`--warn-common' (14)`--warn-constructors' (14)`--warn-multiple-gp' (15)`--warn-once' (15)`--warn-section-align' (15)`--whole-archive' (15)`--wrap SYMBOL' (15)`--enable-new-dtags'`--disable-new-dtags' (15)i386 PE平台的特定选项 (15)`--add-stdcall-alias' (16)`--base-file FILE' (16)`--enable-stdcall-fixup'`--disable-stdcall-fixup' (16)`--export-all-symbols' (16)3、环境变量 (16)`GNUTARGET' (16)`LDEMULATION' (16)4、连接脚本 (17)4.1、基本的连接脚本的概念 (17)4.1.1、三种节 (17)4.1.2、每一个loadable或allocatable的输出节有两个地址 (17)4.1.3、每一个目标文件还有一个关于符号的列表, 被称为'符号表' (17)4.2、连接脚本的格式 (18)4.3、简单的连接脚本示例 (18)4.4、简单的连接脚本命令 (19)4.4.1、设置入口点. (19)4.4.2、处理文件的命令. (19)`INCLUDE FILENAME' (19)`INPUT(FILE, FILE, ...)'`INPUT(FILE FILE ...)' (19)`GROUP(FILE, FILE, ...)'`GROUP(FILE FILE ...)' (19)`OUTPUT(FILENAME)' (19)`SEARCH_DIR(PATH)' (19)`STARTUP(FILENAME)' (20)4.5、处理目标文件格式的命令 (20)`OUTPUT_formAT(BFDNAME)'`OUTPUT_formAT(DEFAULT, BIG, LITTLE)' (20)`TARGET(BFDNAME)' (20)4.6、其它的连接脚本命令 (20)`EXTERN(SYMBOL SYMBOL ...)'. (20)`FORCE_COMMON_ALLOCATION' (20)`INHIBIT_COMMON_ALLOCATION' (20)`NOC ROSSREFS(SEC TION SEC TION ...)' . (20)`OUTPUT_ARC H(BFDARCH)' (21)4.6、为符号赋值 (21)4.7、SEC TIONS命令 (22)4.7.1、输出节描述 (22)4.7.2、输出节名 (23)4.7.3、输出节描述 (23)4.7.4、输入节描述 (23)4.7.4.1、输入节通配符 (24)4.7.4.2、输入节中的普通符号. (25)4.7.4.3、输入节和垃圾收集 (25)4.7.5、输出节数据 (26)4.7.5.1、输出节关键字 (27)4.7.5.2、输出节的丢弃。
矿产资源开发利用方案编写内容要求及审查大纲
矿产资源开发利用方案编写内容要求及《矿产资源开发利用方案》审查大纲一、概述
㈠矿区位置、隶属关系和企业性质。
如为改扩建矿山, 应说明矿山现状、
特点及存在的主要问题。
㈡编制依据
(1简述项目前期工作进展情况及与有关方面对项目的意向性协议情况。
(2 列出开发利用方案编制所依据的主要基础性资料的名称。
如经储量管理部门认定的矿区地质勘探报告、选矿试验报告、加工利用试验报告、工程地质初评资料、矿区水文资料和供水资料等。
对改、扩建矿山应有生产实际资料, 如矿山总平面现状图、矿床开拓系统图、采场现状图和主要采选设备清单等。
二、矿产品需求现状和预测
㈠该矿产在国内需求情况和市场供应情况
1、矿产品现状及加工利用趋向。
2、国内近、远期的需求量及主要销向预测。
㈡产品价格分析
1、国内矿产品价格现状。
2、矿产品价格稳定性及变化趋势。
三、矿产资源概况
㈠矿区总体概况
1、矿区总体规划情况。
2、矿区矿产资源概况。
3、该设计与矿区总体开发的关系。
㈡该设计项目的资源概况
1、矿床地质及构造特征。
2、矿床开采技术条件及水文地质条件。
标题: GLD中文手册--前言前段时间从每天十多个小时的工作时间中挤出那么点时间完成了NASM手册的翻译,之后得到了汇编版很多朋友的支持与关心,心中非常感激。
但是我们知道,NASM只是一个汇编器,只有它我们还无法完成我们的工作,NASM 功能很强大,能生成很多目标格式的文件,但是得不到我们最终想要的可执行文件。
对,我们还需要一个连接器。
可供选择的连接器有很多,它们当中也有很多是免费的,这在NASM的手册中也有介绍,这里我选择的是GNU的连接器ld,为了能更好地使用这个工具,就有了这篇翻译文档。
请不要误会,gld并不只能运行在unix/linux系统下面。
GCC的windows版本djgpp带有ld的windows版本,可以通过互联网免费下载。
希望这篇文档能对大家有所帮助,谢谢。
标题: GLD中文手册--(一)使用ld********本文档介绍GNU连接器ld的版本.本文档在GNU自由文档许可证下发行.在"GNU自由文档许可证"一章中有关于本许可证的一份拷贝.概述********'ld'把一定量的目标文件跟档案文件连接起来,并重定位它们的数据,连接符号引用.一般,在编译一个程序时,最后一步就是运行'ld'.'ld'能接受连接命令语言文件,这是一种用AT&T的连接编辑命令语言的超集写成的文件,用来在连接的整个过程中提供显式的,全局的控制.本版本的'ld'使用通用BFD库来操作目标文件.这就允许'ld'读取,合并,写入目标文件时,可以使用各种不同的格式,比如,COFF或''. 不同的格式可以被连接到一起产生一个有效的目标文件.除了它的灵活性,GNU连接器比其它连接器更有用的地方在于它提供了诊断信息. 许多连接器在碰到一个错误的时候立即放弃执行;但'ld'却能够继续执行,以让你发现其他的错误(或者,在某些情况下,得到一个带有错误的输出文件)引用**********GNU连接器'ld'能够处理大量的不同情况,并且跟其他的连接器保持尽可能的兼容.这样,你就拥有更多的选择来控制它的行为.命令行选项====================连接器提供大量的命令行选项,但是,在实际使用中,只有少数被经常使用.比如,'ld'的一个经常的使用场合是在一个标准的Unix系统上连接标准的Unix目标文件.在这样的一个系统上,连接文件''如下:ld -o OUTPUT /lib/ -lc这告诉'ld'产生一个叫OUTPUT的文件,作为连接文件'/lib/'和''和库''的结果.''来自标准的搜索路径.(参阅下文的关于'-l'选项的讨论).有些命令行选项可以在命令行的任何位置出现.但是,那些带有文件名的选项,比如'-l'或者'-T',会让文件在选项出现的位置上被读取. 对于非文件选项,以带不同的参数重复它,不会有进一步的效果,或者覆盖掉前面的相同项.那些多次出现时具有特殊含义的选项会在下文的描述中指出.无参数选项是那些被连接的目标文件和档案文件.它们可能紧随命令行选项,或在它们前面,或者跟它们夹杂在一起,但是一个目标文件参数是不会出现在一个选项跟它的参数之间的.通常,连接器至少引用一个目标文件,但是你可指定其它形式的二进制输入文件,这可以通过'-l','-R'或者脚本命令语言来实现.如果没有任何二进制文件被指定,连接器不会产生任何输出,并给出信息:"缺少输入文件."如果连接器不能识别目标文件的格式,它会假设这些只是连接脚本.以这种方式指定的脚本增加了连接用的主连接脚本的内容(主连接脚本即缺省连接脚本或使用'-T'指定的脚本). 这个特性可以允许连接器连接一些文件,它们看上去既像目标文件,又像档案文件,但实际上只是定义了一些符号值,或者使用'INPUT'或'GROUP'来载入其它的目标文件.需要注意的是,用这种方式指定一个脚本只是增加了主连接脚本的内容;要完全替换掉主连接脚本,需要使用'-T'.对于名称是单个字符的选项,选项参数必须紧跟在选项字母后面,中间不留空,或者也可留有一个空格.对于名称是多个字符的选项,选项前可以有一个或两个破折号;比如,'-trace-symbol'和`--trace-symbol'是等价的. 注意,对于这条规则有一个例外.那些以小写字母'o'开头的多字符选项前面只能是两个破折号,这是为了避免跟选项'-o'混淆. 比如'-omagic'把输出文件的名字定为'magic',而'--omagic'在输出文件中设置NMAGIC标志.多字符选项的参数必须跟选项名间以一个等于号分开,或者以一个空格分开.比如:`--trace-symbol foo'和`--trace-symbol=foo'是等价的. 多字符选项的名字唯一缩写符也是可以被接受的.注意,如果连接器通过被编译器驱动来间接引用(比如gcc), 那所有的连接器命令行选项前必须加上前缀'-Wl'(或者能被特定编译器驱动接受的其他前缀),就像下面这样:gcc -Wl,--startgroup -Wl,--endgroup这很重要,因为否则的话,编译器驱动程序会默认丢掉这些连接选项,产生一个错误的连接.下面是关于被GNU连接器接受的常用命令行开关的一个列表:`-aKEYWORD'这个选项在HP/UX兼容系统上被支持. 参数KEYWORD必须是下面字符串中的一个 :`archive', `shared', or `default'. `-aarchive'在功能上跟`-Bstatic'相同,而另外两个关键字功能上跟`-Bdynamic'相同. 这个选项可被多次使用.`-AARCHITECTURE'`--architecture=ARCHITECTURE'在最近发行版本的'ld'中,这个选项只在Intel 960系列架构上有用. 在那种'ld'配置中,参数ARCHITECTURE确定960系列的某一特定架构,启用某些安全措施,并修改档案库的搜索路径.将来的'ld'发行版可能为其它架构系列支持相似的功能.`-b INPUT-FORMAT'`--format=INPUT-FORMAT''ld'可以被配置为支持多于一种的目标文件.如果你的'ld'以这种方式被配置,你可以使用'-b'选项为输入目标文件指定二进制格式. 就算'ld'被配置为支持可选目标格式,你不必经常指定这一项,因为'ld'被配置为在每一台机子上把最常用的格式作为默认输入格式. INPUT-FORMAT是一个字符串, 你可能在连接一个不常用的二进制格式文件时需要这个参数.你也可使用'-b'来显式切换格式(在连接不同格式的目标文件时),方法是在每一组特定格式的目标前使用'-b INPUT-FORMAT'.缺省的格式是从环境变量'GNUTARGET'中得到的.你也可以从一个脚本中定义输入格式,使用的命令是'TARGET'.`-c MRI-COMMANDFILE'`--mri-script=MRI-COMMANDFILE'为了跟MRI生产的连接器兼容,'ld'接受另一种用受限命令语言写成的脚本文件,通过选项'-c'引入MRI脚本文件;使用'-T'选项是运行用普通'ld'脚本语言写的连接脚本.如果MRI-CMDFILE不存在,'ld'在'-L'指定的目录中寻找.`-d'`-dc'`-dp'这三个选项是等价的; 多字符形式是为了跟其他连接器兼容才被支持的.它们给普通符号分配空间,即使一个重定位输出文件已经被指定(通过'-r'). 脚本命令`FORCE_COMMON_ALLOCATION'具有同样的效果.`-e ENTRY'`--entry=ENTRY'使用符号ENTRY作为你的程序的开始执行点,而不是使用缺省的进入点.如果没有叫做ENTRY的符号,连接器会企图把ENTRY作为一个数字进行分析,并使用它作为入口地址(数字会被解释为10进制的;你可以使用前导的'0x'强制为16进制,或'0'作为8进制.)`-E'`--export-dynamic'当创建一个动态连接的可执行程序时, 把所有的符号加到动态符号表中.动态符号表是一个符号集,这些符号对于运行时的动态对象是可见的.如果你不使用这个选项,动态符号表中就会只含有那些连接进来的动态对象中用到的符号如果你使用'dlopen'来载入动态对象,它需要引用程序中的符号,那你可能需要在连接程序时用到这个选项.你也可以使用版本脚本来控制哪些符号应当被加到动态符号表中.`-EB'连接big-endian对象. 这会影响缺省输出格式.`-EL'连接little-endian对象. 这会影响缺省输出格式.`-g'忽略. 为了跟其它工具兼容而提供.`-i'执行一个增量连接(跟'-r'等同)`-init NAME'当创建一个ELF可执行文件或共享对象时,当可执行文件或共享对象被加载时,调用NAME, 这是通过把DT_INIT设置成函数的地址实现的. 缺省情况下,连接器使用'_init'作为调用的函数.`-lARCHIVE'`--library=ARCHIVE'增加一个档案文件ARCHIVE到连接的文件列表中.这个选项可以被多次使用. 'ld'会为每一个指定的ARCHIVE搜索它的路径列表,寻找`'对于支持共享库的系统, 'ld'可能还会搜索扩展名不是'.a'库.特别的,在ELF和SunOS系统上,'ld'会在搜索带有'.a'扩展名的库前搜索带'.so'扩展名的库.`-M'`--print-map'打印一个连接位图到标准输出.一个连接位图提供的关于连接的信息有如下一些:* 目标文件和符号被映射到内存的哪些地方.* 普通符号如何被分配空间.* 所有被连接进来的档案文件,还有导致档案文件被包含进来的那个符号.`-n'`--nmagic'关闭所有节的页对齐,如果可能,把输出格式标识为'NMAGIC'.`-N'`--omagic'把text和data节设置为可读写.同时,取消数据节的页对齐,同时,取消对共享库的连接.如果输出格式支持Unix风格的magic number, 把输出标志为'OMAGIC'.`--no-omagic'这个选项执行的操作大部分正好跟'-N'相反.它设置text节只读,强制data 节页对齐. 但是,这个选项并不开启连接共享库的功能. 使用'-Bdynamic'开启这个功能.`-o OUTPUT'`--output=OUTPUT'使用OUTPUT作为'ld'产生的程序的名字;如果这个选项没有指定,缺省的输出文件名是''.脚本命令'OUTPUT'也可以被用来指定输出文件的文件名.`-O LEVEL'如果LEVEL是一个比0大的数值, 'ld'优化输出.这可能会明显多占用时间,所以只有在生成最后的文件时使用.`-q'`--emit-relocs'把重定位节和内容留在完全连接后的可执行文件中. 连接分析和优化工具可能需要这些信息用来进行正确的修改与执行. 这在大的可执行文件中有用.这个选项目前只支持ELF平台.`-r'`--relocateable'产生可重定位的输出, 比如,产生一个输出文件它可再次作为'ld'的输入.这经常被叫做"部分连接".作为一个副作用,在支持标准Unix魔数的环境中,这个选项会把输出文件的魔数设置为'OMAGIC'. 如果这个选项没有被指定,一个绝对文件就会被产生.当连接C++程序时,这个选项就不会解析构造函数的引用;要解析,必须使用'-Ur'如果输入文件跟输出文件的格式不同,只有在输入文件不含有重定位信息的时候部分连接才被支持.输出格式不同的时候会有更多的限制.比如,有些''的格式在输入文件是其他格式的时候完全不支持部分连接.这个选项跟'-i'等效.`-R FILENAME'`--just-symbols=FILENAME'从FILENAME中读取符号名跟它们的值,但不重位这个文件,或者根本不把它包含在输出文件中.这就允许你的输出文件引用其它程序中定义的绝对内存地址.你可以多次使用这个选项.为了跟其他ELF连接器兼容,如果'-R'选项后面跟有一个目录名,而不是一个文件名,它会被处理成'-rpath'选项.`-s'`--strip-all'忽略输出文件中所有的符号信息.`-S'`--strip-debug'忽略输出文件中所有的调试符号信息(但不是所有符号).`-t'`--trace'打印'ld'处理的所有输入文件的名字.`-T SCRIPTFILE'`--script=SCRIPTFILE'把SCRIPTFILE作为连接脚本使用. 这个脚本会替代'ld'的缺省连接脚本(而不是增加它的内容),所以命令文件必须指定所有需要的东西以精确描述输出文件.如果SCRIPTFILE在当前目录下不存在,'ld'会在'-L'选项指定的所有目录下去寻找.多个'-T'选项会使内容累积.`-u SYMBOL'`--undefined=SYMBOL'强制SYMBOL在输出文件中作为一个无定义的符号被输入.这样做会有一些效果,比如,会引发从标准库中连接更多的模块. '-u'可以以不同的参数反复使用,以输入多个无定义的符号.这个选项跟连接脚本命令中的'EXTERN'是等效的.`-Ur'对于不是C++的程序,这个选项跟'-r'是等效的: 它产生可重定位的输出,比如,一个输出文件它可以再次作为'ld'的输入. 当连接C++程序时,'-Ur'解析构造函数的引用,跟'-r'不同. 但如果在一些用'-Ur'连接过的文件上再次使用'-Ur',它不会工作,因为一旦构造函数表被建立,它不能被添加内容.请只在最后一遍连接的时候使用'-Ur', 对其它的,只使用'-r'.`--unique[=SECTION]'对于所有匹配SECTION的输入节,在输出文件中都各自创建单独的节,或者,如果可选的通配符SECTION参数丢失了,为每一个孤儿输入节创建一个输出节. 一个孤儿节是一个连接脚本中没有指定的节.你可以在命令行上多次使用这个选项; 阻止对同名输入节的合并,在连接脚本中重载输出节分配.`-v'`--version'`-V'显示'ld'的版本. '-V'选项同时会列出支持的模拟器.`-x'`--discard-all'删除所有的本地符号.`-X'`--discard-locals'删除所有的临时本地符号.对于大多数目标平台,就是所有的名字以'L'开头的本地符号.`-y SYMBOL'`--trace-symbol=SYMBOL'打印出所有SYMBOL出现的被连接文件的名字. 这个选项可以被多次使用. 在很多系统中,这在预先确定底线时很有必要.当你拥有一个未定义的符号,但不知道这个引用出自哪里的时候,这个选项很有用.`-Y PATH'为缺省的库搜索路径增加一条路径.这个选项是为了跟Solaris兼容.`-z KEYWORD'能被识别的关键字包括'initfirst', 'interpose', 'loadfltr',`nodefaultlib', `nodelete', `nodlopen', `nodump', `now',`origin',`combreloc', `nocombreloc' and `nocopyreloc'. 为了跟Solaris兼容,所有其它的关键字都被忽略. 'initfirst'标志一个对象,使它在运行时,在所有其他对象之前被初始化. 'interpose'标志一个对象,使它的符号表放在所有其他符号之前,作为主要的执行者. 'loadfltr'标志一个对象,使它的过滤器在运行时立即被处理.'nodefaultlib'标志一个对象,使在搜索本对象所依赖的库时,忽略所有缺省库搜索路径. 'nodelete'标志一个对象,使它在运行时不会被从内存中删除.'nodlopen'标志一个对象,使这个对象不可以通过'dlopen'载入.'nodump'标志一个对象,使它不能被'dldump'转储. 'now'标志一个对象,使它成为非懒惰运行时绑定对象. 'origin'标志一些可能含有$ORIGIN 的对象,'defs'不允许无定义符号. 'muldefs'允许重定义. 'comberloc'组合多个重定位节,重新排布它们,让动态符号可见. 'nocomberloc'使多个重定位节组合无效. 'nocopyreloc'使重定位拷贝后的结果无效.--标题: GLD中文手册--(二)`-( ARCHIVES -)'`--start-group ARCHIVES --end-group'ARCHIVES应当是一个关于档案文件的列表. 它们可以是显式的文件名,或者'-l'选项.这些指定的档案文件会被多遍搜索,直到没有新的无定义引用被创建. 通常,一个档案文件只会被搜索一次. 但如果这个档案文件中的一个符号需要被用来解析一个档案中的目标引用到的无定义的符号,而这个符号在命令行上的后面某个档案文件中出现, 连接器不能解析这个引用. 把这些档案文件分组后,它们都可被反复搜索直到所有可能的引用都被解析了为止.使用这个选项有一个很大的运行开销. 只有在无法避免在多个档案文件中使用循环引用时才用它.`--accept-unknown-input-arch'`--no-accept-unknown-input-arch'告诉连接器接受那些架构不能被识别的输入文件. 但前提假设是用户知道他们在做什么,并且是故意要连接这些未知的输入文件. 在版本之前,这个是连接器的缺省行为. 从版本以后的,缺省行为是拒绝这类输入文件, 所以`--accept-unknown-input-arch'选项被用来恢复旧的行为.`-assert KEYWORD'这个选项被忽略,只是用来跟SunOS保持兼容.`-Bdynamic'`-dy'`-call_shared'连接动态链接库. 这个仅仅在支持共享库的平台上有用.在这些平台上,这个选项通常是默认行为. 这个选项的不同形式是为了跟不同的系统保持兼容. 你可以在命令行上多次使用这个选项:它影响紧随其后的'-l'选项的库搜索.`-Bgroup'在动态节的'DT_FLAGS_1'入口上设置'DF_1_GROUP'标志.这会让运行时连接器在处理在这个对象和它的相关部分搜索时只在组中. '--no-undefined'是隐式的. 这个选项只在支持共享库的ELF平台上有用.`-Bstatic'`-dn'`-non_shared'`-static'不连接共享库. 这个仅仅在支持共享库的平台上有用. 这个选项的不同形式是为了跟不同的系统保持兼容. 你可以在命令行上多次使用这个选项:它影响紧随其后的'-l'选项的库搜索.`-Bsymbolic'当创建一个共享库时, 把对全局符号的引用绑定到共享库中的定义(如果有),通常, 一个连接共享库的程序重载共享库中的定义是可能的. 这个选项只在支持共享库的ELF平台上有用.`--check-sections'`--no-check-sections'让连接器在节地址被分配后不要去检查节地址是否重叠.通常,连接器会执行这种检查,如果它发现了任何重叠,它会产生相应的错误信息. 连接器知道也允许节的重叠. 缺省的行为可以使用命令行开关`--check-sections'来恢复.`--cref'输出一个交叉引用表. 如果一个连接器位图文件被产生, 交叉引用表被打印到位图文件. 否则, 它被打印到标准输出.表的格式相当的简单, 所以,如果需要,可以通过一个脚本很轻易地处理它. 符号是以名字被打印输出,存储. 对于每一个符号,给出一个文件名列表. 如果符号被定义了, 列出的第一个文件是符号定义的所在. 接下来的文件包含符号的引用.`--no-define-common'这个选项限制对普通符号的地址分配. 脚本命令`INHIBIT_COMMON_ALLOCATION'具有同等的效果.`--no-define-common'选项允许从输出文件的类型选择中确定对普通符号的地址分配; 否则, 一个非重定位输出类型强制为普通符号分配地址. 使用'--no-define-common'允许那些从共享库中引用的普通符号只在主程序中被分配地址. 这会消除在共享库中的无用的副本的空间, 同时,也防止了在有多个指定了搜索路径的动态模块在进行运行时符号解析时引起的混乱.`--defsym SYMBOL=EXPRESSION'在输出文件中建立一个全局符号,这个符号拥有一个EXPRESSION指定的绝对地址. 你可以多次使用这个选项定义多个符号. EXPRESSION支持一个受限形式的算术运算:你可以给出一个十六进制常数或者一个已存在符号的名字,或者使用'+'和'-'来加或减十六进制常数或符号. 如果你需要更多的表达式,可以考虑在脚本中使用连接器命令语言, 注意在SYMBOL,=和EXPRESSION之间不允许有空格.`--demangle[=STYLE]'`--no-demangle'这些选项控制是否在错误信息和其它的输出中重组符号名. 当连接器被告知要重组, 它会试图把符号名以一种可读的形式的展现: 如果符号被以目标文件格式使用,它剥去前导的下划线,并且把C++形式的符号名转换成用户可读的名字.不同的编译器有不同的重组形式. 可选的重组形式参数可以被用来为你的编译器选择一个相应的重组形式. 连接器会以缺省形式重组直至环境变量`COLLECT_NO_DEMANGLE'被设置. 这些选项可以被用来重载缺省的设置.`--dynamic-linker FILE'设置动态连接器的名字. 这个只在产生动态连接的ELF可执行文件时有效. 缺省的动态连接器通常是正确的; 除非你知道你在干什么,不要使用这个选项.`--embedded-relocs'这个选项只在连接MIPS嵌入式PIC代码时有效, 这些代码必须是由GNU的编译器跟汇编器通过-membedded-pic选项生成的. 它导致连接器产生一个表,这个表被用来在运行时重定位所有的被静态初始化为指针值的数据.`--fatal-warnings'把所有的警告视为错误.`--force-exe-suffix'确保输出文件有一个.exe后缀.如果一个被成功完整连接的输出文件不带有一个'.exe'或'.dll'后缀, 这个选项确保连接器把输出文件拷贝成带有'.exe'后缀的同名文件. 这个选项在使用微软系统来编译未经修改的Unix的makefile时很有用, 因为有些版本的windows不会运行一个不带有'.exe'后缀的映像.`--no-gc-sections'`--gc-sections'允许对未使用的输入节的碎片收集. 在不支持这个选项的平台上,被忽略. 这个选项不能跟 '-r'选项共存也不能被用来进行动态连接. 缺省行为可以用`--no-gc-sections'进行恢复.`--help'在标准输出上打印一个命令行选项概要,然后退出.`--target-help'打印一个所有目标平台相关的选项的概要,然后退出.`-Map MAPFILE'打印一个连接位图到文件MAPFILE中. 参阅上面关于'-M'选项的描述.`--no-keep-memory''ld'通常会以速度优先于内存使用的方式优化程序,这是通过把输入文件的符号表放在内存缓冲中实现的,这个选项告诉'ld'以内存使用优先来优化, 尽可能的减小符号表的重读. 这在'ld'在连接一个大文件时超出内存限制时有用.`--no-undefined'`-z defs'通常,当创建一个非符号共享库时, 无定义的符号允许出现,并留待运行时连接器去解决. 这个选项关闭这样的无定义符号的使用. 开关`--no-allow-shlib-undefined'控制共享对象被连接进共享库时的行为.`--allow-multiple-definition'`-z muldefs'通常,当一个符号被定义多次时, 连接器会报告一个致命错误. 这些选项允许重定义并且第一个定义被使用`--allow-shlib-undefined'`--no-allow-shlib-undefined'允许(缺省)或不允许无定义符号存在于共享对象中. 这个开关的设置会重载'--no-undefined',这里只关注共享对象. 这样,如果'--no-undefined'被设置,但'--no-allow-shlib-undefined'未被设置, 连锁反应是存在于规则对象文件中的无定义的符号会引起一个错误,但是在共享对象中的未定义的符号会被忽略.把`--allow-shlib-undefined'设置为缺省的原因是在连接时指定的共享对象并不一定是载入时可载入的那个,所以,符号可能要到载入时间才被解析.`--no-undefined-version'通常当一个符号有一个未定义的版本时,连接器会忽略它. 这个选项不允许符号有未定义的版本,并且碰到这种情况,会报告一个严重错误.`--no-warn-mismatch'通常, 如果你因为一些原因,企图把一些不匹配的输入文件连接起来的时候, 'ld'会给出一个错误,可能这些文件是因为由不同的处理器编译. 这个选项告诉'ld'应当对这样的错误默认允许. 这个选项必须小心使用.`--no-whole-archive'为后面的档案文件关闭'--whole-archive'选项的影响.`--noinhibit-exec'当一个可执行文件还可以使用时,就保留它. 通常,连接器如果在连接过程中遇到了错误,就不会产生输出文件;当它遇上错误时,它会退出而不写输出文件.`-nostdlib'仅搜索那些在命令行上显式指定的库路径. 在连接脚本中(包含在命令行上指定的连接脚本)指定的库路径都被忽略.`--oformat OUTPUT-FORMAT''ld'可以被配置为支持多于一种的目标文件. 如果你的'ld'以这种方式被配置,你可以使用'--oformat'选项来指定输出目标文件的二进制格式.就算'ld'被配置为支持多种目标格式,你也不必指定这个项,因为'ld'应当被配置为把最常用的输出格式作为默认格式. OUTPUT-FORMAT是一个文本串,是被BFD库支持的一个特定格式的名字.脚本命令'OUTPUT_FORMAT'也可以指定输出格式,但这个选项可以覆盖它.`-qmagic'这个选项被忽略,只是为了跟Linux保持兼容.`-Qy'这个选项被忽略,只是为了跟SVR4保持兼容.`--relax'一个机器相关的选项. 只有在少数平台上,这个选项被支持.在某些平台上,'--relax'选项在连接器解析程序中的地址时执行可能的全局优化, 比如松散地址模式和在输出文件中合成新的指令.在某些平台上,连接时全局优化会进行符号调试导致程序不能运行.在不支持这个选项的平台上,'--relax'被接受,但被忽略.`--retain-symbols-file FILENAME'只保留在FILENAME中列出的那些符号,丢弃所有其他的. FILENAME是一个简单地平坦模式文件, 一个符号占一行.这个选项在那些会逐步积累起一个大的全局符号表的系统中(比如 VxWorks)会很有用,它能有效地节约内存空间.'--retain-symbols-file'不丢弃未定义的符号,和需要重定位的符号.你可能在命令行上只指定'--retain-symbol-file'一次, 它覆盖'-s'和'-S'的功能.`-rpath DIR'为运行时库的搜索路径增加一个目录. 这个在连接带有共享库的ELF可执行文件时有用. '-rpath'的所有参数会被连接起来传递给运行时连接器, 运行时连接器在运行时用它们定位共享对象. '-rpath'选项在定位那些在连接参数指定的共享对象需要的共享对象时也很有用; 参阅关于'-rpath-link'选项的描述, 如果在连接一个ELF可执行文件时不使用'-rpath'选项,那些环境变量'LD_RUN_PATH'选项就会被使用.'-rptah'选项也可以使用在SunOS上. 缺省地,在SunOS上,连接器会从所有的'-L'选项中形成一个运行时搜索路径.如果使用了'-rpath'选项, 那运行时搜索路径就只从'-rpath'选项中得到, 忽略'-L'选项. 这在使用GCC时非常有用, 它会用上很多的'-L'选项,而这些路径很可能就是NFS挂上去的文件系统中.为了同ELF的连接器兼容, 如果'-R'选面后面跟有一个目录名, 而不是一个文件名,那它也会被处理成'-rpath'选项.`-rpath-link DIR'当在SunOS上使用ELF时,一个共享库可能会用到另一个共享库. 当'ld-share'把一个共享库作为一个输入文件连接时就有可能发生这种情况.当一个连接器在作非共享,不可重定位连接时,如果遇上这种依赖情况,它会自动定位需要的共享库,然后把它包含在连接中, 如果在这种情况中,它没有被显式包含, 那'-rpath-link'选项指定优先搜索的一组路径名.。
解释一个ld.script资料GNU ld (GNU Binutils for Ubuntu)2.20.1-system.20100303Supported emulations:elf_i386i386linuxelf_x86_64elf_l1omusing internal linker script:============================================== ====/* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386", "elf32-i386","elf32-i386")OUTPUT_ARCH(i386)ENTRY(_start)SEARCH_DIR("/usr/i486-linux-gnu/lib32");SEARCH_DIR("/usr/local/lib32");SEARCH_DIR("/lib32"); SEARCH_DIR("/usr/lib32"); SEARCH_DIR("/usr/i486-linux-gnu/lib");SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");SEARCH_DIR("/usr/lib");SECTIONS{/* Read-only sections, merged into text segment: */ PROVIDE (__executable_start =SEGMENT_START("text-segment", 0x08048000));. = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;.interp : { *(.interp) }.note.gnu.build-id : { *(.note.gnu.build-id) }.hash : { *(.hash) }.gnu.hash : { *(.gnu.hash) }.dynsym : { *(.dynsym) }.dynstr : { *(.dynstr) }.gnu.version : { *(.gnu.version) }.gnu.version_d : { *(.gnu.version_d) }.gnu.version_r : { *(.gnu.version_r) }.rel.dyn :{*(.rel.init)*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)*(.rel.fini)*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)*(.rel.ctors)*(.rel.dtors)*(.rel.got)*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)*(.rel.ifunc)}.rel.plt :{*(.rel.plt)PROVIDE_HIDDEN (__rel_iplt_start = .);*(.rel.iplt)PROVIDE_HIDDEN (__rel_iplt_end = .);}.init :{KEEP (*(.init))} =0x90909090.plt : { *(.plt) *(.iplt) }.text :{*(.text.unlikely .text.*_unlikely)*(.text .stub .text.* .gnu.linkonce.t.*)/* .gnu.warning sections are handled specially by elf32.em. */*(.gnu.warning)} =0x90909090.fini :{KEEP (*(.fini))} =0x90909090PROVIDE (__etext = .);PROVIDE (_etext = .);PROVIDE (etext = .);.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) }.eh_frame_hdr : { *(.eh_frame_hdr) }.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RO{ *(.gcc_except_table .gcc_except_table.*) }/* Adjust the address for the data segment. We want to adjust up tothe same address within the page on the next page up. */ . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));/* Exception handling */.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RW{ *(.gcc_except_table .gcc_except_table.*) }/* Thread Local Storage sections */.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*)*(.tcommon) }.preinit_array :{PROVIDE_HIDDEN (__preinit_array_start = .);KEEP (*(.preinit_array))PROVIDE_HIDDEN (__preinit_array_end = .);}.init_array :{PROVIDE_HIDDEN (__init_array_start = .);KEEP (*(SORT(.init_array.*)))KEEP (*(.init_array))PROVIDE_HIDDEN (__init_array_end = .); }.fini_array :{PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array))KEEP (*(SORT(.fini_array.*)))PROVIDE_HIDDEN (__fini_array_end = .); }.ctors :{/* gcc uses crtbegin.o to find the start ofthe constructors, so we make sure it isfirst. Because this is a wildcard, itdoesn't matter if the user does notactually link against crtbegin.o; thelinker won't look for a match awildcard. The wildcard also means that itdoesn't matter which directory crtbegin.ois in. */KEEP (*crtbegin.o(.ctors))KEEP (*crtbegin?.o(.ctors))/* We don't want to include the .ctor section fromthe crtend.o after the sorted ctors.The .ctor section from the crtend theend of ctors marker and it must be last */KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*)))KEEP (*(.ctors))}.dtors :{KEEP (*crtbegin.o(.dtors))KEEP (*crtbegin?.o(.dtors))KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*)))KEEP (*(.dtors))}.jcr : { KEEP (*(.jcr)) }.data.rel.ro :{ *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)*(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }.dynamic : { *(.dynamic) }.got : { *(.got) *(.igot) }. = DATA_SEGMENT_RELRO_END (12, .);.got.plt : { *(.got.plt) *(.igot.plt) }.data :{*(.data .data.* .gnu.linkonce.d.*)SORT(CONSTRUCTORS)}.data1 : { *(.data1) }_edata = .; PROVIDE (edata = .);__bss_start = .;.bss :{*(.dynbss)*(.bss .bss.* .gnu.linkonce.b.*)*(COMMON)/* Align here to ensure that the .bss section occupies space up to_end. Align after .bss to ensure correct alignment even if the.bss section disappears because there are no input sections.FIXME: Why do we need it? When there is no .bss section, we don'tpad the .data section. */. = ALIGN(. != 0 ? 32 / 8 : 1);}. = ALIGN(32 / 8);. = ALIGN(32 / 8);_end = .; PROVIDE (end = .);. = DATA_SEGMENT_END (.);/* 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 beginningof 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) }/* DWARF 3 */.debug_pubtypes 0 : { *(.debug_pubtypes) }.debug_ranges 0 : { *(.debug_ranges) }.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink)*(.gnu.lto_*) }}============================================== ====下面逐句解释。
GNU工具链简介(全)2012-01-13 14:24:00分类:原文地址:GNU工具链简介(全)作者:piaoyizuMips GNU工具链简介1 . 总括本文分三部分来介绍mips的工具链,首先工具链的总括,其次是每个工具链的简介,最后是各工具链的实际应用举例。
我们的项目使用的工具链就如图1所示, 声明,本文所述的内容实乃GNU工具链的九牛之一毛, 日后会陆续更新。
图12. 工具链简介下边就以列表的方式,对每一个工具链的作用进行介绍,在下一章进行实例演示。
mips-linux-gnu-addr2line :把程序地址转换为文件名和行号。
在命令行中给它一个地址和一个可执行文件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。
mips-linux-gnu-gcc:符合ISO标准的C编译器, 这个大家都在用,不再赘述。
mips-linux-gnu-objcopy:把一种目标文件中的内容复制到另一种类型的目标文件中。
mips-linux-gnu-ar:建立、修改、提取归档文件。
归档文件是包含多个文件内容的一个大文件,其结构保证了可以恢复原始文件内容。
mips-linux-gnu-gcov:gcov是一个保险测试工具。
当构建一个程序时,gcov会监视一个程序的执行,并且会标识出执行了哪一行源码,哪一行没有执行。
mips-linux-gnu-objdump:显示一个或者更多目标文件的信息。
使用选项来控制其显示的信息。
它所显示的信息通常只有编写编译工具的人才感兴趣。
mips-linux-gnu-as:是 GNU 汇编器,主要用来编译 GNU C 编译器 gcc 输出的汇编文件,它将汇编代码转换成二进制代码,并存放到一个object 文件中,该目标文件将由连接器 ld连接mips-linux-gnu-gdb:GNU调试器。
允许调试用C\C++和其他语言编写的应用程序。
它的基本运行方式是在shell环境下用命令方式进行调试程序和显示数据。
gcc lds规则-回复gcc是GNU编译器套件中的一个重要组成部分,是一款用于编译C、C++等程序语言的强大工具。
而lds(链接脚本)是gcc中一个重要的功能模块,负责控制可执行文件或共享库的链接过程。
本文将详细介绍gcc的lds 规则,解释其作用和使用方法。
一、gcc的基本概述1.1 gcc简介GCC(GNU Compiler Collection)是一套由GNU开源组织开发的编程语言编译器,支持多种编程语言,如C、C++、Objective-C、Fortran、Ada等。
它是许多现代操作系统的默认编译器,包括Linux和Mac OS X。
1.2 gcc的功能GCC具有强大的功能,可以编译源代码并生成可执行文件或共享库。
它提供了许多优化选项和扩展特性,可以根据特定的需求对程序进行优化和定制。
二、lds规则的作用2.1 链接过程简介在编译C或C++程序时,源代码会首先被编译为目标文件,其中包含了相应的函数和变量定义。
链接过程将这些目标文件与库文件一起组合,生成最终的可执行文件或共享库。
2.2 lds的作用有时,我们需要在链接过程中进行一些定制化的操作,比如指定程序的入口点、控制内存映射、定义符号的位于的内存地址,这就需要使用到lds (链接脚本)。
三、gcc lds规则的使用方法3.1 编写lds脚本文件首先,我们需要创建一个lds脚本文件,通常以.ld或者.x文件作为后缀名。
这个文件包含了一系列用于指导链接过程的命令和规则。
3.2 定义程序的入口点通常情况下,程序的入口点是由操作系统指定的,但是我们也可以使用lds 脚本文件来自定义程序的入口点。
通过在脚本文件中使用ENTRY命令,指定程序的入口函数的名称。
3.3 控制内存映射使用gcc的lds规则,我们可以控制程序在内存中的布局。
通过在脚本文件中使用MEMORY命令,可以为不同的段(如.text段、.data段、.bss段)指定它们在内存中的位置和大小。