2

I want to decoding a blx instruction on arm, and I have found a good answer here: Decoding BLX instruction on ARM/Thumb (IOS)

But in my case, I follow this tip step by step, and get the wrong result, can anyone tell me why?

This is my test:

.plt: 000083F0  sub_83F0       ...
...
.text:00008436  FF F7 DC EF    BLX sub_83F0

I parse the machine code 'FF F7 DC EF' by follow:

   F7 FF EF DC

   11110  1  1111111111  11  1  0  1  1111101110  0  
          S    imm10H        J1    J2   imm10L  

   I1 = NOT(J1 EOR S) = 1  
   I2 = NOT(J2 EOR S) = 1  

   imm32 = SignExtend(S:I1:I2:imm10H:imm10L:00)  
         = SignExtend(1111111111111111110111000)  
         = SignExtend(0x1FFFFB8)  
         = ?  

So the offset is 0xFFB8?
But 0x83F0-0X8436-4=0xFFB6
I need your help!!!

Community
  • 1
  • 1
Neil.L
  • 103
  • 1
  • 9

2 Answers2

3

When the target of a BLX is 32-bit ARM code, the immediate value encoded in the BLX instruction is added to align(PC,4), not the raw value of PC.

  • PC during execution of the BLX instruction is 0x8436 + 4 == 0x843a due to the ARM pipeline
  • align(0x843a, 4) == 0x8438

So:

  • 0x00008438 + 0ffffffb8 == 0x83f0

The ARM ARM mentions this in the assembler syntax for the <label> part of the instruction:

For BLX (encodings T2, A2), the assembler calculates the required value of the offset from the Align(PC,4) value of the BLX instruction to this label, then selects an encoding that sets imm32 to that offset.

The alignment requirement can also be found by careful reading of the Operation pseudocode in the ARM ARM:

if ConditionPassed() then
    EncodingSpecificOperations();
    if CurrentInstrSet == InstrSet_ARM then
        next_instr_addr = PC - 4;
        LR = next_instr_addr;
    else
        next_instr_addr = PC;
        LR = next_instr_addr<31:1> : ‘1’;
    if toARM then
        SelectInstrSet(InstrSet_ARM);
        BranchWritePC(Align(PC,4) + imm32);   // <--- alignment of the current PC when BLX to non-Thumb ARM code
    else
        SelectInstrSet(InstrSet_Thumb);
        BranchWritePC(PC + imm32);
Jens
  • 8,423
  • 9
  • 58
  • 78
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Thanks very much for your explanation. But I still have a question: the arithmetic of Align(PC,4). You write align(0x843a, 4) == 0x8438, why not 0x843C? And the arithmetic of SignExtend(number)... – Neil.L Jul 01 '13 at 08:44
  • `Align()` is defined as `Align(x,y) = y * (x DIV y)` - so basically a round down. `SignExtend(x,i)` is x extended to a length of i bits, by adding sufficient copies of its leftmost bit to its left. Strictly speaking, the `SignExtend()` operations in your example should have a second operand of 32. These are in the ARM Reference Manual's "Pseudocode Definition" appendix. – Michael Burr Jul 01 '13 at 15:20
  • Thank you. I admire your knowledge. – Neil.L Jul 02 '13 at 02:23
0
F7FF
1111011111111111
111 10 11111111111 h = 10 offset upper = 11111111111

EFDC
1110111111011100
111 01 11111011100 h = 01 blx offset upper 11111011100

offset = 1111111111111111011100<<1 
sign extended = 0xFFFFFFB8

0x00008436 + 2 + 0xFFFFFFB8 = 1000083F0
clip to 32 bits 0x000083F0
old_timer
  • 69,149
  • 8
  • 89
  • 168