网站挖掘工具,wordpress编辑器自动加p标签,有没有给做淘宝网站的,网站的建设背景官方文档#xff1a;https://sourceware.org/binutils/docs-2.30/ld/index.html#SEC_Contents 所有创建可执行文件的最后一步就是链接。它是由ld或者是用gcc间接调用ld来完成的。它主要任务和把外部库和应用程序的目标代码放到text段正确位置。以及创建程序中其它段#xff0…官方文档https://sourceware.org/binutils/docs-2.30/ld/index.html#SEC_Contents 所有创建可执行文件的最后一步就是链接。它是由ld或者是用gcc间接调用ld来完成的。它主要任务和把外部库和应用程序的目标代码放到text段正确位置。以及创建程序中其它段如data/bss段。
标准C程序的链接是一般是固定的。它是ld调用一个缺省的链接脚本来完成的。因此对于一般的应用开发者,几乎感觉不到ld以及链接脚本的存在。 但是如果在一些特殊情况下主要是底层非操作系统程序。里面很多代码特别是汇编代码。必须要链接到指定的位置。而且这个时候的程序入口不一定也不是main了。这种情况在bootloader,Linux内核以及裸机程序非操作系统的程序bootloader可以看成这类程序一个特例)。这时你就要手工编写lds文件了。 在lds文件中如果添加注释可以像C语言一样使用 /**/ 隔开即可。
从以前的经验链接脚本是嵌入式开发单片机开发相当重要的一个东西。它完成的工作是做PC机软件的同志们不用关心的但是也是很复杂的一项工作。总结来看链接脚本要告诉连接器
1输出什么
2输入是什么那么obj文件
3要用什么库库放在什么地方
4内存分布地址
5提供启动代码一些全局地址变量 一般来说链接脚本需要搞清楚这几样事情后才能编写那arm-gcc-ld的脚本也一定要实现这些功能。对于大多数的链接器来说对于简单的项目不需要脚本只是使用命令参数就可以完成了。 MEMORY
它是用来补充SECTIONS命令的用来描述目标CPU中可用的内存区域。它是可选的如果没有这个命令LD会认为SECTIONS描述的相邻的内存块之间有足够可用的内存。其实很容易理解但是却很少用我没用过嘿嘿在SECTIONS中每个段的分布都没有考虑ARM能够寻址的地址中ROMRAMFLASH是不是连续的。如果不是连续的怎么办MEMORY就是设置各个区的起始位置大小属性的命令在一个脚本中只能有一个。 举一个例子
如果你的板子有两段存储而且很遗憾的是不是连续的一段是从0x0开始大小为256K另一段是从0x40000000开始的大小为4M你可以在脚本中写入如下的代码来描述你的板子的内存信息。 1 MEMORY 2 { 3 rom (rx) : ORIGIN 0 , LENGTH 256K 4 ram ( ! rx) : org 0x40000000 , l 4M 5 } 很显然下面的一句用了简略标签这并不重要重要的是怎样使用它不过在那之前还是想再仔细研究下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)说实话没看懂。只知道用的时候用的比较多的是ALIGN4这样的标记表示排列地址的时候按4的倍数排列这样做的理由很简单系统会快。
ATaddr实现存放地址和加载地址不一致的功能AT表示在文件中存放的位置而在内存里呢按照普通方式存储。至于用处目前在下不知。
region好戏来了这个region就是前面说的MEMORY命令定义的位置信息。表明当前section所放置的mem有什么特点如果不符合会怎么样呢不晓得嘛。
其他略了吧累了主要是没中文资料屁话有了还用我刻薄吗其实有点日文资料也行啊英文我比较苦手。 注释 和C语言一样的哦/**/ 其它
其实ARM-GCC-LD脚本还真的和别的不一样它的功能要强一些从manual看它有三大功能
1设置入口函数
2定义一个变量并赋值
3描述输入输出文件的链接规则 其实上面的介绍是功能31和2都没有讲过。对于arm-gcc-ld脚本来说设置入口函数和定义变量可以在SECTIONS命令大括号里也可以在外面。语法是
ENTRY(symbol)
这个symbol应该是某个函数或者是汇编代码里的一个入口。然而其实ARM-GCC-LD有很多种方式定义入口所以当你看到你的脚本里没有这句话而板子运行的很正常的时候别大吃一斤。
1在连接的时候使用-e参数。
2在脚本里使用ENTRY
3如果定义过start这个入口如果你在汇编里如果本身就有这个名字叫start的入口那么不用特别的声明也可以
4SECTION中.text的第一个入口函数
5地址为0的指令
其实看了这个我们可以理解是ARM对入口的一个选择优先级1和2是一样的显示的指明入口这也是推荐的方法没人会觉得程序员故弄玄虚是什么好事情。3是连接器的智能吧而4和5就是无奈的选择了程序员没干好的事情CPU只要猜着来处理了有.text段的话就从它开始执行吧连.text都没有的就从0x00000000开始执行至于执行到哪里去了火星人知道。 关于定义变量其实一般的脚本都会有的目的只有一个给汇编启动代码提地址信息。比如说一段需要清零的区域在脚本里定义了而脚本自己不是变形金刚他不能主动给你清零的需要你自己的启动代码来清零清零的代码当然在汇编的启动代码里它怎么知道需要清零的内存在什么地方就靠脚本里定义的变量了。没错事情就是这样的那也就说一定会有一个提取地址的方法将地址赋给变量了哦yes就是小小的一个点.。
RAM_START .;
定义了一个RAM_START变量地址是当前的地址什么是当前的地址啊就是链接器在连接的时候根据前面的段排列后的当前位置。当然也可以设置当前位置的值不过最好不要小于前面排列需要的最小内存。
. 0x00000000
定义当前地址为0x0。 常用的基本上就这么多了看一个实例吧 1 SECTIONS 2 { 3 . 0x30000000 ; 4 .text : { * (.text) } 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 } 18 PROVIDE (__stack .); 19 end .; 20 _end .; 14 __bss_start__ .; 15 __bss_end__ .; 16 __EH_FRAME_BEGIN__ .; 17 __EH_FRAME_END__ .; 5 Image_RO_Limit .; 6 Image_RW_Base .; 7 Image_RO_Base .; 8 Image_RW_Limit .;