答疑解惑哪家强?当属咱们EEPW最强。。。接下来持续咱们的答疑解惑系列。
58. 为什么一个看起来很简略的程序,链接的时分却要花费很长的时刻?
导致这种现象的最主要的原因是类型兼并(type merging)。那什么是类型兼并呢?举个简略的比如,在头文件types.h中界说了结构sss,且一切的.c中中都引用了这个types.h。因而在编译之后,描绘sss的调试类型信息被包括到每个方针文件之中(除非运用了–symdebug:none来禁用调试信息),因而在链接的时分,链接器会发现有很多个sss类型的副本;默许情况下,链接器运用类型兼并把这么多sss类型兼并为一个,然后使得终究输出的.out文件中只要一个sss类型,而不是很多个重复的副本,抵达减小代码尺度的意图,而且使得CCS在加载.out文件时也会花费更少的时刻。然后,类型兼并这个过程中需求很多的核算,因而导致了链接看起来需求花费很长的时刻。
处理的办法有两个:
1. 禁用类型兼并:运用链接器的-b选项(意义请参阅http://www.eepw.com.cn/article/249328.htm)。这样做的成果是链接的时刻变短,可是.out文件变大,需求更长的时刻来加载;假如在这个比如中sss的副本十分多,有或许需求很差的时刻来加载.out文件。
2. 运用–symdebug:none选项来彻底制止把调试信息写入.out文件。这样做既能够减小链接时刻,又能够减小.out的尺度和缩短加载时刻,但成果是代码的调试功用被大大削弱了。
59. 怎么运用一个.cmd文件在含有不同的内部存储空间的芯片上来完结段的优先级?
假设有下面的情况:
器材1有64kb快速的内部存储,而器材2有128kb。现在咱们有4个要害的代码段:
.text:_a : 20kb
.text:_b : 30kb
.text:_c : 20kb
.text:_d : 10kb
其间段a的运算重要性最高,段b的次之,以此类推。
给片内的快速存储器命名为IRAM,而片外的慢速存储器命名为SDRAM。假设在器材1上,咱们有必要把.text:_a和.text:_b保存在IRAM中以确保运转速度,而.text:_c和.text:_d则既能够保存在IRAM,也能够保存在SDRAM中。在器材2中,由于片上存储明显增大,能够把abcd四个段都保存在SDRAM中。此刻咱们能够运用下面的办法,运用同一个.cmd文件来完结段的分配:
这一段句子的效果有两个:
(1) 在分配存储空间时,依照次序来确保配段的优先级。在.cmd文件中,假如需求确保段的优先级,则有必要运用GROUP这个指令;假如不运用则段之间不会有优先级的联系,此刻链接器会有用把长度最大的那个段优先分配空间,以最大程度地削减存储空间中的空地。
(2) 主动在不相邻的存储空间IRAM和SDRAM中区分输出的段。两个大于号“>>”也是链接器的内部指令,它用来标明GROUP中的段能够被区分到不同的存储空间里。例如,当链接器在器材1上,发现在分配完.text:_a和.text:_b到IRAM中之后,发现.text:_c有20kb,IRAM的空间现已不足以寄存它时,它会跳过把text:_c分配到IRAM上,而是把text:_c分配到SDRAM中;接下来链接器会持续测验把text:_d给分配到IRAM中(假如text:_d的长度满足小的话)。而在器材2上,编译器会发现空间满足寄存abcd四个段的时分,就把它们四个一同保存到IRAM中了。
假如咱们运用下面的两种办法,成果会是什么样的呢?
运用这个办法依然能够做到段的切割,即上面的第二条,可是它们之间空间分配的优先级没有办法确保,很有或许使得程序的功能受到影响。
运用这个办法依然能够做到段的优先级,即上面的第一条,可是在器材1上这些段将无法悉数保存到IRAM中,终究导致链接器的过错。。
60. 为什么需求敞开链接器–w选项?
-w的意义是:在未界说的输出段被创立时发生正告信息。因而,假如咱们在程序中创立了段,例如:
可是在cmd文件中没有清晰段的类型(例如.text、.bss等),则链接器将有或许恣意地给咱们自界说的段分配一个地址操控,这将导致严峻的运转时过错。例如,链接器有或许恣意地把咱们自界说的段给分配为FLASH这个段类型,可是实际上它们并不在Flash中运转,成果导致代码彻底不履行。
运用-w选项将使得链接器有必要提示咱们有关段未界说的信息,然后防止上述问题的发生。
61. 链接器地址映射文件中的trampolines代表什么意义?
在链接之后,翻开生成的.map文件,能够检查地址映射信息,如下图所示。
其间的TRAMPOLINES在英语里是“蹦床”的有意思,在这里的意义则是代表非直接跳转的向量。它的意义与蹦床运动是相同的,代码履行到trampoline之后会马上跳转出,或许回弹。当跳转指令无法抵达意图地时,链接器会主动发生trampoline, 然后咱们就能够看到上图所示的那些信息了,它们的意义是:
callee:函数被调用。
addr:callee的地址。
tramp:链接器主动为trampoline所发生的姓名。
addr:trampoline在存储器中的地址。
call addr:从trampoline发生的调用所运用的地址列表。
call info:包括开始调用的方针文件和输入段。假如方针文件保存在某个库中,则会把库文件的姓名也显示出来。
62. 在C编译器中运用内联的汇编指令的情况下,为何代码的实时运转犯错了?
在C代码中,咱们能够运用asm()指令来刺进汇编代码。假如刺进的这段汇编代码修改了C代码所运用的运转环境中的寄存器,则会损坏C代码的数据,导致运转时犯错。一切在C代码中运用内联的汇编代码时必须当心,不要损坏了程序的完整性。