Search code examples
assemblyarmthumb

Function address in ARM assembly have one byte offset?


For example, I have the following assembly code got by objdump. The address of f() is 080001d4. But printf("%x", f) outputs 080001d5. And f() can be done by (*((int (*)())080001d5))() but (*((int (*)())080001d4))().

Why there is one byte offset in function address?

080001d4 <f>:
 80001d4:   2000        movs    r0, #0
 80001d6:   4770        bx  lr

Solution

  • ARM has two instruction modes, and the least-significant bit of the address is used to indicate which mode a given function uses. Odd addresses for Thumb mode, and even addresses for ARM mode.

    The address will be even if you recompile it using the -marm switch.

    Section A4.1.1 "Changing between Thumb state and ARM state" in [1] states the following:

    A processor in Thumb state can enter ARM state by executing any of the following instructions: BX , BLX , or an LDR or LDM that loads the PC.

    ....

    The target instruction set is either encoded directly in the instruction (for the immediate offset version of BLX ), or is held as bit[0] of an interworking address.


    [1] ARM® Architecture Reference Manual: ARMv7-A and ARMv7-R edition. ARM, 2014. DDI 0406C.c. [Online]. Available: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c/index.html. [Accessed 26 Aug. 2019].