objdump产生错误的分支操作码解释

时间:2019-08-13 12:12:08

标签: c assembly arm cortex-m objdump

请参阅特定功能(objdump)的特定对象文件的以下func行:

3c:   e03a            b.n     78 <func+0x78>

现在,目标系统(ARMv6-M)中的操作码e03a说跳转到PC + 0x78的位置。正确的解释是:

3c:   e03a            b.n     B4 <func+0xB4>

每个其他函数和文件在其b.n转储中都包含正确的objdump解释和正确的值计算。由于某些原因,只有此功能导致objdump被“混淆”。

注意:func0x0开始。

我想不出这种情况的任何原因。而且由于我有解析和使用objdump转储的工具,所以这给我带来了很大的问题。 有什么合理的理由吗?

工具链:gcc-arm-none-eabi-4_9-2015q3

运行该工具链的平台:Ubuntu 16.04.2 LTS


编辑:我要附加部分转储:

Disassembly of section i.func:

00000000 <func>:
   0:   b531        push    {r0, r4, r5, lr}
   2:   b088        sub sp, #32
   4:   2100        movs    r1, #0
   6:   9106        str r1, [sp, #24]
   8:   482c        ldr r0, [pc, #176]  ; (bc <func+0xbc>)
   a:   6800        ldr r0, [r0, #0]
   c:   6840        ldr r0, [r0, #4]
   e:   9103        str r1, [sp, #12]
  10:   1c40        adds    r0, r0, #1
  12:   9002        str r0, [sp, #8]
  14:   492a        ldr r1, [pc, #168]  ; (c0 <func+0xc0>)
  16:   2000        movs    r0, #0
  18:   9104        str r1, [sp, #16]
  1a:   9005        str r0, [sp, #20]
  1c:   a802        add r0, sp, #8
  1e:   f7ff fffe   bl  0 <random_func>
  22:   f7ff fffe   bl  0 <random_func2>
  26:   4604        mov r4, r0
  28:   4d26        ldr r5, [pc, #152]  ; (c4 <func+0xc4>)
  2a:   42ac        cmp r4, r5
  2c:   d007        beq.n   3e <func+0x3e>
  2e:   a326        add r3, pc, #152    ; (adr r3, c8 <func+0xc8>)
  30:   22ee        movs    r2, #238    ; 0xee
  32:   492c        ldr r1, [pc, #176]  ; (e4 <func+0xe4>)
  34:   2000        movs    r0, #0
  36:   9400        str r4, [sp, #0]
  38:   f7ff fffe   bl  0 <log_func>
  3c:   e03a        b.n 78 <func+0x78>   <---- PROBLEM IS HERE
  3e:   f7ff fffe   bl  0 <func>
  42:   9006        str r0, [sp, #24]
  44:   f3bf 8f5f   dmb sy
  48:   a808        add r0, sp, #32
  4a:   7800        ldrb    r0, [r0, #0]
  4c:   2800        cmp r0, #0
  4e:   d00f        beq.n   70 <func+0x70>
  50:   9806        ldr r0, [sp, #24]
  52:   2803        cmp r0, #3
  54:   d016        beq.n   84 <func+0x84>
  56:   f7ff fffe   bl  0 <some_hw_func>
  5a:   4604        mov r4, r0
  5c:   42ac        cmp r4, r5
  5e:   d01a        beq.n   96 <func+0x96>
  60:   a321        add r3, pc, #132    ; (adr r3, e8 <func+0xe8>)
  62:   22fa        movs    r2, #250    ; 0xfa
  64:   491f        ldr r1, [pc, #124]  ; (e4 <func+0xe4>)
  66:   2000        movs    r0, #0
  68:   9400        str r4, [sp, #0]
  6a:   f7ff fffe   bl  0 <log_func>
  6e:   e021        b.n 46 <random_delay+0x46>  <--- ALSO HERE SAME PROBLEM
  70:   f7ff fffe   bl  0 <random_delay>
  74:   2800        cmp r0, #0
  76:   d003        beq.n   80 <func+0x80>
  78:   a808        add r0, sp, #32
  7a:   7800        ldrb    r0, [r0, #0]
  7c:   2800        cmp r0, #0
  7e:   d018        beq.n   b2 <func+0xb2>
  80:   f7ff fffe   bl  0 <some_hw_func2>
  84:   f7ff fffe   bl  0 <random_delay>
  88:   2800        cmp r0, #0
  8a:   d002        beq.n   92 <func+0x92>
  8c:   9806        ldr r0, [sp, #24]
  8e:   2803        cmp r0, #3
  90:   d00f        beq.n   b2 <func+0xb2>
  92:   f7ff fffe   bl  0 <some_hw_func2>
  96:   f7ff fffe   bl  0 <func>
  9a:   4604        mov r4, r0
  9c:   42ac        cmp r4, r5
  9e:   d008        beq.n   b2 <func+0xb2>
  a0:   22ff        movs    r2, #255    ; 0xff
  a2:   a318        add r3, pc, #96 ; (adr r3, 104 <func+0x104>)
  a4:   3201        adds    r2, #1
  a6:   490f        ldr r1, [pc, #60]   ; (e4 <func+0xe4>)
  a8:   2000        movs    r0, #0
  aa:   9400        str r4, [sp, #0]
  ac:   f7ff fffe   bl  0 <log_func>
  b0:   e000        b.n b4 <func+0xb4>
  b2:   462c        mov r4, r5
  b4:   4620        mov r0, r4

1 个答案:

答案 0 :(得分:6)

看起来像个虫子;每次在两次跳转之间跳转时,都需要像这里一样重新定位

38:   f7ff fffe   bl  0 <log_func>
3c:   e03a        b.n 78 <func+0x78>   <---- PROBLEM IS HERE
3e:   f7ff fffe   bl  0 <func>

或这里

6a:   f7ff fffe   bl  0 <log_func>
6e:   e021        b.n 46 <random_delay+0x46>
70:   f7ff fffe   bl  0 <random_delay>

计算错误。

没有正当的理由;向错误跟踪系统http://www.sourceware.org/bugzilla/发送报告可能是适当的(在验证之后,最新版本也受到此错误的影响)

编辑:我有一些时间深入研究此错误。

问题是,如果b.n之前的指令是任意32位指令,而b.n的主体是 之后的指令,要重定位,objdump错误地假设b.n指令具有与其相关的重定位,并且将用于偏移量计算的相对pc设置为0。

binutils/objdump.c中的这段代码是罪魁祸首:

              bfd_signed_vma distance_to_rel;

              distance_to_rel = (**relppp)->address
                - (rel_offset + addr_offset);

              /* Check to see if the current reloc is associated with
                 the instruction that we are about to disassemble.  */
              if (distance_to_rel == 0
                  /* FIXME: This is wrong.  We are trying to catch
                     relocs that are addressed part way through the
                     current instruction, as might happen with a packed
                     VLIW instruction.  Unfortunately we do not know the
                     length of the current instruction since we have not
                     disassembled it yet.  Instead we take a guess based
                     upon the length of the previous instruction.  The
                     proper solution is to have a new target-specific
                     disassembler function which just returns the length
                     of an instruction at a given address without trying
                     to display its disassembly. */
                  || (distance_to_rel > 0
                      && distance_to_rel < (bfd_signed_vma) (previous_octets/ opb)))
                {
                  inf->flags |= INSN_HAS_RELOC;
                  aux->reloc = **relppp;
                }

注释说明了一切:此解析器从上一条32位指令中猜测,下一条指令也是32位(不是!)。重定位针对3e,并且反汇编程序假定下一条指令是从3c3f,因此b.n被标记为INSN_HAS_RELOC,进而导致错误的偏移量计算。看起来,这样修复起来并不容易。

但是,您可以尝试像这样修补objdump:

if (distance_to_rel == 0) {
              inf->flags |= INSN_HAS_RELOC;
              aux->reloc = **relppp;
}

这反过来可能会产生误差,但是这种情况很少见,也许您会更好。