历史上的今天
返回首页

历史上的今天

今天是:2024年12月03日(星期二)

正在发生

2019年12月03日 | ARM-GCC-LD脚本

2019-12-03 来源:eefocus

从以前的经验,链接脚本是嵌入式开发,单片机开发相当重要的一个东西。它完成的工作是做PC机软件的同志们不用关心的,但是也是很复杂的一项工作。总结来看链接脚本要告诉连接器


1:输出什么


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


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


4:内存分布地址


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

 


一般来说链接脚本需要搞清楚这几样事情后才能编写,那arm-gcc-ld的脚本也一定要实现这些功能。对于大多数的链接器来说,对于简单的项目不需要脚本,只是使用命令参数就可以完成了。


MEMORY:


它是用来补充SECTIONS命令的,用来描述目标CPU中可用的内存区域。它是可选的,如果没有这个命令,LD会认为SECTIONS描述的相邻的内存块之间有足够可用的内存。其实很容易理解但是却很少用(我没用过,嘿嘿),在SECTIONS中每个段的分布都没有考虑ARM能够寻址的地址中,ROM,RAM,FLASH是不是连续的。如果不是连续的怎么办?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):说实话,没看懂。只知道用的时候用的比较多的是ALIGN(4)这样的标记,表示排列地址的时候按4的倍数排列,这样做的理由很简单,系统会快。


AT(addr):实现存放地址和加载地址不一致的功能,AT表示在文件中存放的位置,而在内存里呢,按照普通方式存储。至于用处,目前在下不知。


>region:好戏来了,这个region就是前面说的MEMORY命令定义的位置信息。表明当前section所放置的mem有什么特点,如果不符合会怎么样呢?不晓得嘛。


其他略了吧,累了,主要是没中文资料(屁话,有了还用我刻薄吗),其实有点日文资料也行啊,英文我比较苦手)。


注释:


和C语言一样的哦,/**/


其它:


其实ARM-GCC-LD脚本还真的和别的不一样,它的功能要强一些,从manual看,它有三大功能:


1:设置入口函数


2:定义一个变量并赋值


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


 


其实上面的介绍是功能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。



常用的基本上就这么多了,看一个实例吧:


 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 = .;


推荐阅读

史海拾趣

Aleph America Corporation公司的发展小趣事

Aleph America Corporation 是一家专注于光电传感器和光电开关解决方案的公司。以下是关于该公司发展的5个相关故事:

  1. 公司成立及发展: Aleph America Corporation 成立于1986年,总部位于美国新泽西州。公司专注于光电传感器技术的研发和生产,并提供广泛的光电开关产品线,包括光电接近传感器、光电开关、光电耦合器等。随着市场对自动化和安全系统需求的增长,Aleph 在行业内逐渐建立了良好的声誉。

  2. 技术创新与产品质量: Aleph America Corporation 致力于技术创新和产品质量的提升。公司拥有一支专业的研发团队,不断引入先进的光电传感技术,并且注重产品的生产工艺和质量控制,确保产品具有稳定的性能和可靠的品质。

  3. 应用领域广泛: Aleph 的产品广泛应用于各种工业和商业应用领域。光电传感器和光电开关被广泛应用于自动门、电梯、安防系统、自动化生产线等领域,为客户提供了安全可靠的解决方案。

  4. 全球市场拓展: 随着全球市场的不断扩大,Aleph 在海外市场的拓展也逐渐加强。除了在美国设立总部和生产基地外,公司还在欧洲、亚洲等地设立了销售办事处和代理商网络,以便更好地满足全球客户的需求。

  5. 参与行业标准和认证: Aleph America Corporation 积极参与行业标准的制定和产品认证工作。公司的产品符合国际标准和认证要求,如CE认证、UL认证等,确保产品在全球范围内的市场准入和使用安全。

以上故事展示了 Aleph America Corporation 在光电传感器和光电开关领域的发展历程和成就,突出了其在技术创新、产品质量、市场拓展和行业认证方面的重要贡献。

General Electric Company公司的发展小趣事
内部集成了频率补偿机制,确保在高频信号下电路的稳定性。
Floeth Electronic Ltd公司的发展小趣事
在工业自动化控制系统中,用于驱动高压电机、阀门等执行机构。
CDIL[Continental Device India Pvt. Ltd.]公司的发展小趣事

近年来,CDIL积极响应政府政策,利用生产挂钩激励计划(PLI)和电子元件和半导体制造促进计划(SPECS),计划将其产能从目前的5亿片基础上提高1亿片。同时,公司还计划在未来几年内建立两条新的ATMP生产线,以进一步提升产能和技术水平。此外,CDIL还在碳化硅(SiC)等新技术领域进行了深入研发,以满足电动汽车、电源管理设备等新兴市场的需求。

Equator Technologies公司的发展小趣事

随着智能手机市场的迅速崛起,Equator敏锐地捕捉到了这一市场机会。从XX年代后期开始,公司逐渐将业务重心转向手机图像处理领域。通过与手机厂商的合作,Equator成功地将其先进的视频处理技术应用于智能手机中,显著提升了手机的显示效果和用户体验。这一转型不仅为Equator带来了丰厚的回报,也进一步巩固了其在电子行业的地位。

HDP_Power公司的发展小趣事

面对日益激烈的市场竞争和技术变革,Equator始终保持着持续创新的精神。公司不断投入研发资源,探索新的技术方向和应用场景。例如,在人工智能和机器学习领域,Equator正在积极开展相关研究和实践工作,探索将这些先进技术应用于视频处理领域的可能性。通过持续创新和努力,Equator正致力于引领电子行业未来的发展方向。

问答坊 | AI 解惑

FPGA设计者的5项基本功

记得《佟林传》里,佟林练的基本功是“绕大树、解皮绳”,然后才练成了什么“鬼影随行、柳叶绵丝掌”。 在我看来,成为一名说得过去的FPGA设计者,需要练好5项基本功:仿真、综合、时序分析、调试、验证。 需要强调的一点是, ...…

查看全部问答>

上网“打酱油”

俺时不时地用QQ聊天、写博、泡坛子,自觉天天跟网络世界亲密接触,还不至于太out!一日,俺闲逛到一论坛,看斑竹发帖正告:请勿发了帖就跑,不要当事不关己发了帖就走人的“酱油”男女。俺泡坛子也不是一日两日了,可这“酱油”男女是什么意思?不是 ...…

查看全部问答>

华为FPGA设计流程指南.doc

本帖最后由 paulhyde 于 2014-9-15 08:55 编辑 华为FPGA设计流程指南.doc  …

查看全部问答>

LED发光字使用中常见问题的解决方法

replyreload += \',\' + 706991;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

智能电视静电保护技巧

高清数字内容过去只能承载于物理磁盘上,需要专用设备才可以播放;而今,宽带连接无处不在,高清数字内容可以从“云”端中以“流”的形式传送和定制到计算 机、智能手机或任何其它连网设备上。传统电视是一种独立的终端,只能接收广播电视节目,由于 ...…

查看全部问答>

LM3S的ADC

LM3S系列的ADC都是10位的,请问与其他厂商的12位ADC相比精度上有什么不同?…

查看全部问答>

Fpga/Cpld的基本概念

推荐几种最基本的电路。模拟的 大家一起学习。。…

查看全部问答>

msp430g2553不能用sqrt()函数吗??

只要一用那个函数就报错 ./lnk_msp430g2553.cmd\", line 56: error #10099-D: program will not fit into    available memory.  run placement with alignment fails for section \".bss\"    size 0x302 .  ...…

查看全部问答>

电脑上的串口调试软件给stm32发协议需要连发两次!

电脑上的串口调试软件给stm32发协议需要连发两次!这个问题困扰我好久了,不知道有没有人遇到过给点参考意见!…

查看全部问答>

【SensorTag】之蓝牙生活精灵项目提交

自从获得了SensorTag传感器组件,便提交了自个的方案:蓝牙生活精灵。一开始进展很顺利,了解SensorTag传感器组件,找来个苹果手机安装演示软件apk,功能很正常,心下很是欣喜,想着自个的东东一定可以实现。可惜苹果手机不是自个的,也没有来得及 ...…

查看全部问答>