Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

objdump produces wrong branch opcode interpretation

See the following objdump line of a specific object file of a specific function (func):

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

Now, the opcode e03a in the target system (ARMv6-M) says jump to the location of PC + 0x78. A correct interpretation will be:

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

Every other function and file contains proper b.n interpretations with proper values calculations in their objdump dump. For some reason, only this function causes objdump to be "confused".

Note: funcstarts at 0x0.

I could not think of any reason for this situation. And since I have tools that parse and uses the objdump dump, this causes great problem for me. Is there any reasonable reason for that?

toolchain: gcc-arm-none-eabi-4_9-2015q3

platform running this toolchain: Ubuntu 16.04.2 LTS


EDIT: I'm attaching partial dump:

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
like image 518
izac89 Avatar asked Aug 13 '19 12:08

izac89


Video Answer


1 Answers

Looks like a bug; each time the jump is between jumps, that are subject to relocation like here

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

or here

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

the calculation is wrong.

There is no legitimate reason for this; a report to the bugtracking system http://www.sourceware.org/bugzilla/ is probably appropriate (after verifying, that the latest versions also suffer from this bug)

EDIT: I had some time to look deeper into this bug.

The problem is, that if the instruction before the b.n is any 32-bit instruction and the instruction after the b.n is subject to relocation, objdump falsely assumes that the b.n instruction has a relocation associated with it and sets the relative pc to 0 for the offset calculation.

This code part from binutils/objdump.c is the culprit:

              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;
                }

The comment says it all: this parser guesses from the previous 32-bit instruction, that the next instruction is also 32-bit (which it isn't!). The relocation is targeted for 3e and the disassembler assumes, that the next instruction is from 3c to 3f, so the b.n is flagged with INSN_HAS_RELOC, which in turn leads to the incorrect offset calculation. Looks, like this will not be easy to fix up.

However, you could try and patch your objdump like this:

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

This might produce inaccuracies the other way round, but that should be rare cases and maybe that is better acceptable for you.

like image 72
Ctx Avatar answered Oct 19 '22 01:10

Ctx