I did find this link: Offset calculation for branch instruction in ARM

Which was quite helpful but also confusing for me. I tried few ways to get it working with my offsets but failed.

What I wanted to do, was create a BL instruction from 0x52F4D6 to 0x5BF368.

At 0x52F4D6 I wanted to write BL sub_5BF368 but how do I get the correct hex code (thumb) for it?

  • Example of manipulating ARM conditional branch instruction to patch an Android Shared LIB Android lib patching
    – Hilogic
    Apr 20, 2016 at 17:09

1 Answer 1


You can get this from the ARM manual; for example from the version linked at the link you found, https://ece.uwaterloo.ca/~ece222/ARM/ARM7-TDMI-manual-pt3.pdf.

First, a quick calculation 5BF358-52F4D6 yields 8FE82, so you see you have more than 12 bits, and need to use the long branch format in 5.19, which splits your BL into two instructions. The section says "The branch offset must take account of the prefetch operation, which causes the PC to be 1 word (4 bytes) ahead of the current instruction", so the offset you need is from 4 bytes behind 52F4D6 - 52F4DA, which means the offset for the instructions - the value you want to add to PC is 8FE7E.

The first part of the instruction shifts its partial offset left by 12 bits, and adds this to PC. The instruction format is 1111HXXXXXXXXXXX in binary, with H=0, so F000+XXXX in hex. What you want to add to PC in this step is 8F000, so the opcode for this instruction is F0 8F.

The second part shifts its partial offset left by one bit (remember thumb instructions are aligned to 16 bit, so the last bit of an offset is always 0, so it doesn't have to be represented in the hex opcode), and it has H=1, so the opcode is F800+XXXX. What you want to add in this step is E7E. Shift that right by one bit to get 73f, and add to your opcode to get FF 3F.

So, your BL instruction is F08F FF3F.

To confirm this, create an assembly program, assemble it, and check the result:

.arch armv7a
.syntax unified
.align 2
.org    0x52F4D6
bl  sub_5BF368
.org    0x5BF368

arm-linux-gnueabi-as -o y.o y.s
arm-linux-gnueabi-objdump -s y.o | grep -v "00000000 00000000 00000000 00000000"
 52f4d0 00000000 00008ff0 3fff0000 00000000  ........?.......

Remember words are byte-swapped due to little-endianness, and you'll find your F08F FF3F opcode there.

EDIT: I just fixed the address of the second .org since it seemed miss-typed just to avoid confusion. Now it looks consistent I think :)

  • Awesome! Thank you! I also wanted to ask if I can use BGT, BEQ, BNE, BLE, BGE, BLT inside the assembly program and then disassemble it?
    – Anthony
    Apr 20, 2016 at 15:16
  • Yes, this works for all instructions. Just remember that the offset part of the conditional branches is just 8 bit, so the target needs to be closer to the branch instruction than in the bl example above. Apr 20, 2016 at 15:31
  • Sorry, I answered my own question. But another question, why can't I branch backwards a few offsets? Always get this error: attempt to move .org backwards
    – Anthony
    Apr 21, 2016 at 14:06
  • That because, well, you can't move .org backwards. For a back jump, you need to put the .org/sub declaration in front of the .org/branch. Apr 21, 2016 at 17:30
  • Awesome! Would you happen to have the parts to add to the start of the program so we can get the x64 offset? :)
    – Anthony
    Apr 22, 2016 at 23:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.