Assembly 为什么正向参考ADR指令在Thumb代码中的偏移量是偶数?

Assembly 为什么正向参考ADR指令在Thumb代码中的偏移量是偶数?,assembly,arm,gnu-assembler,thumb,Assembly,Arm,Gnu Assembler,Thumb,要bx使用Thumb函数,需要设置地址的最低有效位。GNU as文档说明了当地址是从adr伪指令生成时,它是如何工作的: 药品不良反应 此指令将标签地址加载到指定的寄存器中。[……] 如果标签是thumb功能符号,则thumb互通已完成 通过-mthumb interwork选项启用,然后是 将设置存储在寄存器中的值。这允许以下顺序按预期工作: adr r0,拇指功能 blx r0 所以听起来事情应该就这么办了。然而,在一些反汇编中,某些地址似乎没有设置底部位 例如,组装和链接: .syntax

bx
使用Thumb函数,需要设置地址的最低有效位。GNU as文档说明了当地址是从
adr
伪指令生成时,它是如何工作的:

药品不良反应

此指令将标签地址加载到指定的寄存器中。[……]

如果标签是thumb功能符号,则thumb互通已完成 通过
-mthumb interwork
选项启用,然后是 将设置存储在寄存器中的值。这允许以下顺序按预期工作:

adr r0,拇指功能

blx r0

所以听起来事情应该就这么办了。然而,在一些反汇编中,某些地址似乎没有设置底部位

例如,组装和链接:

.syntax unified
.thumb

.align 2
table:
    .4byte f1
    .4byte f2
    .4byte f3

.align 2
.type f1, %function
.thumb_func
f1:
    adr r1, f1
    adr r2, f2
    adr r3, f3
    bx r1

.align 2
.type f2, %function
.thumb_func
f2:
    adr r1, f1
    adr r2, f2
    adr r3, f3
    bx r2

.align 2
.type f3, %function
.thumb_func
f3:
    adr r1, f1
    adr r2, f2
    adr r3, f3
    bx r3
与:

使用
arm none eabi objdump-D a.out检查,我得到:

00008000 <table>:
    8000:   0000800d    .word   0x0000800d
    8004:   00008019    .word   0x00008019
    8008:   00008025    .word   0x00008025

0000800c <f1>:
    800c:   f2af 0103   subw    r1, pc, #3
    8010:   a201        add r2, pc, #4  ; (adr r2, 8018 <f2>)
    8012:   a304        add r3, pc, #16 ; (adr r3, 8024 <f3>)
    8014:   4708        bx  r1
    8016:   46c0        nop         ; (mov r8, r8)

00008018 <f2>:
    8018:   f2af 010f   subw    r1, pc, #15
    801c:   f2af 0207   subw    r2, pc, #7
    8020:   a300        add r3, pc, #0  ; (adr r3, 8024 <f3>)
    8022:   4710        bx  r2

00008024 <f3>:
    8024:   f2af 011b   subw    r1, pc, #27
    8028:   f2af 0213   subw    r2, pc, #19
    802c:   f2af 030b   subw    r3, pc, #11
    8030:   4718        bx  r3
    8032:   46c0        nop         ; (mov r8, r8)
00008000:
8000:0000800d。字0x0000800d
8004:00008019.字0x00008019
8008:00008025.字0x00008025
0000800c:
800c:f2af 0103 subw r1,pc,#3
8010:a201添加r2,pc,#4;(adr r2,8018)
8012:a304添加r3,pc,#16;(adr r3,8024)
8014:4708 bx r1
8016:46c0 nop;(mov r8,r8)
00008018 :
8018:f2af 010f地下室r1,pc,#15
801c:f2af 0207子图纸r2,pc,第7页
8020:a300加r3,pc,#0;(adr r3,8024)
8022:4710 bx r2
00008024 :
8024:f2af 011b subw r1,pc,#27
8028:f2af 0213 subw r2,个人电脑,19
802c:f2af 030b subw r3,pc,#11
8030:4718 bx r3
8032:46c0 nop;(mov r8,r8)
有几件事需要注意:

  • 中,
    f1
    f2
    f3
    的绝对地址都是奇数,如预期的那样。因此,显然,汇编器和链接器知道这三个函数应该是Thumb
  • 对于反向引用,
    adr
    伪指令向下汇编为
    subw
    ,偏移量是奇数,正如预期的那样
  • 但是对于正向引用,如果
    adr
    伪指令汇编成
    add
    ,则偏移量是偶数

  • 我遗漏了什么?

    您遗漏了ARM文档中的以下内容:

    如果使用ADR为BX或BLX指令生成目标,则如果目标包含Thumb指令,则您有责任设置地址的Thumb位(位0)

    正向引用ADR指令使用ADD指令的16位Thumb“ADD Rd,pc,#imm”形式。此指令的立即数在0-1020的范围内,并且必须是字对齐的(即,它用8位字段编码并乘以4)。使用的PC值也将较低的两位设置为0,因此它无法生成奇数地址


    强制汇编程序始终使用带有ADR.W的32位Thumb指令应该会导致它在使用函数标签时始终生成奇数地址,但我不知道您是否可以依赖于此。最好只显式设置较低的位。

    回到这个问题。问题其实很简单:

      if (inst.relocs[0].exp.X_op == O_symbol
          && inst.relocs[0].exp.X_add_symbol != NULL
          && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
          && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
        inst.relocs[0].exp.X_add_number += 1;
    
    在do_t_adr()函数中

    S_IS_DEFINED检查符号是否已定义,当在此时间点进行正向参考时,符号未定义,因此线不会通过,它不会添加一个非常干扰清洁度的符号,但不管是什么。对于向后参考,定义符号以便进行调整。(当然,如果没有定义的符号,THUMB_IS_FUNC也无法工作)

    ADR转换为BFD_RELOC_ARM_THUMB_ADD。这把我们带到了这里

    case BFD_RELOC_ARM_THUMB_ADD:
      /* This is a complicated relocation, since we use it for all of
     the following immediate relocations:
    
        3bit ADD/SUB
        8bit ADD/SUB
        9bit ADD/SUB SP word-aligned
       10bit ADD PC/SP word-aligned
    
     The type of instruction being processed is encoded in the
     instruction field:
    
       0x8000  SUB
       0x00F0  Rd
       0x000F  Rs
      */
    
    在这里面

    else if (rs == REG_PC || rs == REG_SP)
      {
        /* PR gas/18541.  If the addition is for a defined symbol
           within range of an ADR instruction then accept it.  */
    
    在以后的过程中发生的代码(在定义符号并可以找到符号之后)不会修补立即数/偏移量

    我发现如果没有语法统一,它就无法处理这个问题,这更令人不安/有问题

    .thumb
    .thumb_func
    zero:
        adr r0,zero
    
    即使使用.syntax统一,他们也没有完成T16的ADR实现。只需在那里输入一个错误,并称其为“完成”。(当然可以在T16中实现,例如添加rx、pc、#0、sub rx、#offset。)

    即使他们修复了它,我也会避免ADR指令。但很明显,他们并没有真正完成这个伪指令的实现

    注意,在arm模式下,它们有相同的错误,在错误的时间检查符号

      if (support_interwork
          && inst.relocs[0].exp.X_op == O_symbol
          && inst.relocs[0].exp.X_add_symbol != NULL
          && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
          && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
        inst.relocs[0].exp.X_add_number |= 1;
    
    请注意,ORR没有添加一个更好/不同的作者,但没有完全考虑这个解决方案

    如果我删除S_IS_定义和THUMB_IS_FUNC检查

    .arm
    zero:
        adr r0,two
    .thumb
    .thumb_func
    two:
        nop
    

    00000000 <zero>:
       0:   e24f0004    sub r0, pc, #4
    
    00000004 <two>:
       4:   46c0        nop         ; (mov r8, r8)
       6:   46c0        nop         ; (mov r8, r8)
    
    给予

    (该错误与您指出的错误位于同一代码段中)


    首先看看其他汇编程序的文档中关于ADR和thumb的内容,然后看看他们是否真的按照该文档实现了它,和/或带着错误或警告退出了。您是否尝试过查看一些C代码(例如静态或本地函数指针数组)的GCC输出看看是否有额外的指令用于确保汇编器知道它是函数符号?或者,如果在这种情况下asm最终没有得到奇数地址,adr.w将生成一个T3变体,如armv7-m文档中所述。它允许从0到4095的任何偏移量,不限于四次方,比如T1编码,没有统一语法,它是为我而不是为t3生成T1编码。@PeterCordes C编译器不生成adr指令,它们以其他方式解决这个问题,或者是由链接器填充并与pc相对负载一起使用的字,或者蹦床(gnu ld确实有蹦床的问题,所以不要依赖它们)。或者,如果您只是想再次使用C代码中的地址,则会留出一个单词
    00000000 <zero>:
       0:   e24f0004    sub r0, pc, #4
    
    00000004 <two>:
       4:   46c0        nop         ; (mov r8, r8)
       6:   46c0        nop         ; (mov r8, r8)
    
    00000000 <zero>:
       0:   e24f0003    sub r0, pc, #3
    
    00000004 <two>:
       4:   46c0        nop         ; (mov r8, r8)
       6:   46c0        nop         ; (mov r8, r8)
    
    .syntax unified
    
    .thumb
        adr r0,two
        nop
        nop
    .thumb_func
    two:
        nop
    
    00000000 <two-0x8>:
       0:   f20f 0005   addw    r0, pc, #5
       4:   46c0        nop         ; (mov r8, r8)
       6:   46c0        nop         ; (mov r8, r8)
    
    00000008 <two>:
       8:   46c0        nop         ; (mov r8, r8)
    
    .syntax unified
    .cpu cortex-m0
    .thumb
        adr r0,two
        nop
        nop
    .thumb_func
    two:
        nop
    
    /path/so.s: Assembler messages:
    /path/so.s:5: Error: invalid immediate for address calculation (value = 0x00000003)