IAR学习:关于将编译模式从ARM修改为thumb时,出现链接错误error[Lp015]

近期在尝试将公司产品多模块的代码进行整合(之前是由多人负责开发,加上缺乏管理,各自为政,导致很多代码重复开发,版本不一致,硬件一样而代码不统一的问题),发现在IAR环境下,同一MCU,有的工程设置的processor mode是ARM,有的是THUMB。

MCU型号为:RM44Lx系列和RM48Lx系列(ARMV7架构,cortex-R系列)。

根据深入了解,因为MCU是32位处理器,所以ARM模式下执行效率更高,但code占用空间大。而thumb模式刚好相反,执行效率低,但code占用空间小。(thumb模式在16位MCU上执行效率比ARM高)。因为我们的项目对执行速度要求更高,而代码存储空间足够,所以我准备都改成ARM模式,但在实验对比过程中,出现以下问题:

1:在.icf文件中定义0x20大小的region,用来放置异常向量表。8条指令刚好32bytes。

2:在ARM mode下编译链接正常。

3:改为thumb模式,链接错误,报错:

Error[Lp015]: section placement failure: overcommitted content in [0x00000000-0x0000001f] 
 

上面意思是要放在这个0-0x1f空间的内容太多了,放不下。

我就查看要放在这个空间的代码,只有下面这个section,8条指令,不多也不少,空间够,为什么放不下。。。。。。

    section .intvecs:CODE
    arm

_resetEntry
        b   _c_int00
        b   0x00080004
        b   0x00080008
        b   0x0008000C
        b   0x00080010
        b   _reservedEntry
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]
    end

在代码中反复确认,没发现其他代码放在这个地址的设置,而且ARM mode下没问题,这个汇编文件还是限定为ARM指令,应该跟ARM模式没什么区别。

多方搜寻无果后,不死心打开了map文件,一看果然找到了元凶:

  Section                 Kind        Address    Size  Object
  -------                 ----        -------    ----  ------
"P1":                                            0x28
  .intvecs                         0x00000000    0x28  <Block>
    Veneer                ro code  0x00000000     0x8  - Linker created -
    .intvecs              ro code  0x00000008    0x20  sys_intvecs.o [1]
                                 - 0x00000028    0x28

 在P1这个region中,除了.intvecs外,还多了8B的Veneer,由linker创建。

Veneer是什么鬼?(英语释义为:虚饰,伪装。)

把编译器再改回ARM mode,果然这次没有Veneer了,编译通过。

  Section                 Kind        Address    Size  Object
  -------                 ----        -------    ----  ------
"P1":                                            0x20
  .intvecs                         0x00000000    0x20  <Block>
    .intvecs              ro code  0x00000000    0x20  sys_intvecs.o [1]
                                 - 0x00000020    0x20
 

 顺藤摸瓜,继续往下查。

打开IAR的开发手册,直接搜索veneer,结果如下:

 翻译如下:

ARM内核在两种情况下会用到veneer:

1:从ARM mode调用thumb function,或者从thumb mode调用ARM function时,veneer负责改变处理器的工作模式。被调用的function必须是一个interworking function。如果处理器支持BLX指令,则不需要veneer来改变处理器状态。

2:当调用一个function不在正常范围,veneer负责‘介绍代码’,以使调用能够顺利到达目的地。

继续问问题:

针对1:interworking function是什么? 我的MCU支持BLX吗?

针对2:调用function不能正常reach发生在什么情况下?veneer是怎么‘介绍代码’使其能够正常reach的?

我们继续深扒:

1:interworking即处理器允许代码是ARM和thumb混合代码。 我的理解就是处理器可以通过特殊的指令操作,在两个mode之间来回切,来实现ARM instruction和THUMB instruction混合执行。

2:MCU支持BLX指令,这个在架构手册中能够找到。

3:在调用function时,都是跳转指令将目的地址写入PC寄存器来达到跳转目的。而跳转指令都是有跳转范围限制的。ARM模式下B指令范围为±32M,THUMB模式下B指令有多种编码,跳转地址从256B至±16M。可见,在THUMB模式,B跳转范围大幅度减小。那么问题来了:此文件已经限定为ARM模式,那编译时候应该对应的是±32M,根据map文件,完全足够跳转到所有地址了,为什么会出现问题?

 查看map,reservedEntry的地址是0x000097dd,大约27K。

尝试直接跳转0x000097dd同样有问题,但当我直接跳转0x000097dc或者0x000097e0时问题出现。这两个地址一大一小,说明不是地址大小的问题,而是地址对齐的问题。

0x000097dd末尾是0xd=13,这就奇怪了,ARM和THUMB的地址应该是4、2字节对齐,为什么会分配13的函数地址?

此时求助大佬指点:在ARM和THUMB切换时,内核会根据加载到PC中的地址切换,如果末位是1就会切换到THUMB state。

所以,推测在ARM模式是不能直接加载THUMB function.

实验:当我在_reservedEntry前面限定__arm时,果然其地址变成了0x000097fc,并且在map中也没有了veneer。

那么接下来有两个问题需要确认:1:ARM和THUMB相互跳转的详细过程是怎么样的,为什么需要veneer?2:veneer到底是个什么东西,是以什么形式存在的?

我们先从第二个问题来,打开调试器,启动反汇编窗口,b reservedEnter这一条指令如下:

0x00000014        b  [PC, #1]
......
0X00000020        LDR PC [PC, #-0x4]
0x00000024        _reservedEntry

即B指令没有改变到thumb state的功能,但_reservedEntry又是一个thumb function,那怎么办?链接器只能曲线救国,先跳转到0x20,然后由LDR指令操作PC完成跳转,LDR的label存储在0x24供其使用。

至此,这个问题算是搞清楚了:当使用THUMB mode时,_reservedEntry被编译为thumb code。而.intvecs中是强制为ARM code,所以b _reservedEntry跳转就涉及到模式转换,所以也就符合linker产生veneer的条件1,然后将一条指令转换为三条指令,导致指令占用空间增加,其分配的存储空间不足。

解决方案有几种:

1:扩大分配空间。

2:将_reservedEntry限制为ARM code,即函数增加__arm修饰符。

我选择使用第二种,简单直接。

至于上面说道的第一个问题,就需要有空翻看各种手册慢慢学习了。

 

补充:

仿真查看了_reservedEntry在memory中的位置,如下:

 看到其真实位置为0x97FC,而map与跳转位置都是0x97fd, 根据跳转指令的说明可以得出结论:map中的0x97fd的非对齐操作是为了给内核在跳转的时候一个转换为thumb的标记,PC会自动忽略末位bit,直接跳转到0x97FC. 但也不能直接设置跳转到0x97FC,因为会缺乏模式转换操作,导致之后的执行错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值