This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler: Linker fails to relocate R_ARM_THM_MOVT_ABS with offsets

Tool/software: TI C/C++ Compiler

Hello,

The GCC Compiler produces code like the following under certain circumstances:

	movw	r3, #:lower16:foo+24
	movt	r3, #:upper16:foo+24

This translates to the following (disassembly of the object file):

 9cc:	f240 0318 	movw	r3, #24
 9d0:	f2c0 0318 	movt	r3, #24

Please note, that both instructions contain the offset 24.

The final output (TI Linker ti-cgt-arm_5.2.9 and ti-cgt-arm_20.2.0.LTS) is:

017ec0: F6437388         MOVW.W          R3, #16264 ; 0x3F88 -> okay     (0x3F88 - 24 = 0x3F70)
017ec4: F6C00318         MOVT.W          R3, #2072  ; 0x0818 -> Not okay (0x0818 - 24 = 0x0800)

So the TI Linker has added the offset 24 to foo for both instructions MOVW and MOVT which is kind of okay (more later).
However, the expected result for the MOVT is:

MOVT.W          R3, #2048

The issue I think is in how the TI Linker implements the relocation R_ARM_THM_MOVT_ABS.

S + A means:

  • S (when used on its own) is the address of the symbol.
  • A is the addend for the relocation.

The addend is the value that is "already" in the imm16 filed of the MOVT instruction (24).

This would mean that the Linker has to calculate the following: 0x08003F70 + 24 = 0x08003F88 and take the upper 16 bits and put it in the imm16 field of the MOVT instruction ( ( ( 0x08003F70 + 24 ) & 0xFFFF0000 ) >> 16 or ( ( S + A ) & 0xFFFF0000 ) >> 16 ).

However it seems that it has calculated: ( ( 0x08003F70 & 0xFFFF0000 ) >> 16 ) + 24 or ( ( S & 0xFFFF0000 ) >> 16 ) + A

Best regards,
Christian

  • I failed to reproduce this behavior.  Thus, I am unable to turn in an entry the development team can use to investigate. 

    Unfortunately, the pictures you attached are not visible.

    Please supply a test case.  At a minimum, I need all the inputs to the linker, plus the entire linker command file.  Please use copy-n-paste of the text, and not a screen shot.  If it is easier, you are also welcome to submit a CCS project, or a makefile plus source files, or something similar.

    Thanks and regards,

    -George  

      

  • Hello George,

    Thanks for your reply. I updated my previous post to include the pictures.

    I also created some basic example to reproduce the issue. This time I tried the same with just the TI tool chain and for sue it works.

    Here is my example code (whole "project" is attached movt_test.zip):

    GNU TI
        .text
        .thumb
        .syntax unified
        .global startFunc
    startFunc:
        movw.w r0, :lower16:literalPool
        movt.w r0, :upper16:literalPool
        movw.w r1, :lower16:literalPool+4
        movt.w r1, :upper16:literalPool+4

    literalPool:
        .word 0x12345678
        .word 0xCAFECAFE

        .text
        .thumb

        .global startFunc
    startFunc:
        movw.w r0, literalPool
        movt.w r0, literalPool
        movw.w r1, literalPool+4
        movt.w r1, literalPool+4

    literalPool:
        .word 0x12345678
        .word 0xCAFECAFE

    Disassembly of the object file (left is from the object file generated with the GNU assembler, right is with the TI assembler):

    GNU TI
    TEXT Section .text, 0x18 bytes at 0x00000000
    000000:              startFunc:
    000000:               .thumb
    000000:              :
    000000: 40F20000         MOVW.W          R0, #0x0
    000004: C0F20000         MOVT.W          R0, #0x0
    000008: 40F20401         MOVW.W          R1, #0x4
    00000c: C0F20401         MOVT.W          R1, #0x4
    000010:              $d:
    000010:              literalPool:
    000010: 7856            .half         0x5678
    000012: 3412            .half         0x1234
    000014: FECA            .half         0xCAFE
    000016: FECA            .half         0xCAFE
    TEXT Section .text, 0x18 bytes at 0x00000000
    000000:              startFunc:
    000000:               .thumb

    000000: 40F20000         MOVW.W          R0, #0x0
    000004: C0F20000         MOVT.W          R0, #0x0
    000008: 40F20401         MOVW.W          R1, #0x4
    00000c: C0F20001         MOVT.W          R1, #0x0
    000010:              $d:
    000010:              literalPool:
    000010: 7856            .half         0x5678
    000012: 3412            .half         0x1234
    000014: FECA            .half         0xCAFE
    000016: FECA            .half         0xCAFE

    Relocation info of the object file(using GNU readelf):

    GNU TI
    Relocation section '.rel.text' at offset 0x120 contains 4 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    00000000  0000042f R_ARM_THM_MOVW_AB 00000010   literalPool
    00000004  00000430 R_ARM_THM_MOVT_AB 00000010   literalPool
    00000008  0000042f R_ARM_THM_MOVW_AB 00000010   literalPool
    0000000c  00000430 R_ARM_THM_MOVT_AB 00000010   literalPool
    Relocation section '.rel.text' at offset 0x12c contains 2 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    00000000  0000022f R_ARM_THM_MOVW_AB 00000010   literalPool
    00000008  0000022f R_ARM_THM_MOVW_AB 00000010   literalPool

    Relocation section '.rela.text' at offset 0x13c contains 2 entries:
     Offset     Info    Type            Sym.Value  Sym. Name + Addend
    00000004  00000230 R_ARM_THM_MOVT_AB 00000010   literalPool + 0
    0000000c  00000230 R_ARM_THM_MOVT_AB 00000010   literalPool + 4

    It seems that GNU and TI take to different approaches to represent the movt label + x instruction.

    Disassembly of the linked output (TI linker):

    GNU TI
    TEXT Section .text, 0x18 bytes at 0x00000020
    000020:              startFunc:
    000020:              __TI_static_base__:
    000020:               .thumb
    000020:              :
    000020: 40F23000         MOVW.W          R0, #0x30
    000024: C0F20000         MOVT.W          R0, #0x0
    000028: 40F23401         MOVW.W          R1, #0x34
    00002c: C0F20401         MOVT.W          R1, #0x4
    000030:              $d:
    000030:              literalPool:
    000030: 7856            .half         0x5678
    000032: 3412            .half         0x1234
    000034: FECA            .half         0xCAFE
    000036: FECA            .half         0xCAFE
    TEXT Section .text, 0x18 bytes at 0x00000020
    000020:              startFunc:
    000020:              __TI_static_base__:
    000020:               .thumb

    000020: 40F23000         MOVW.W          R0, #0x30
    000024: C0F20000         MOVT.W          R0, #0x0
    000028: 40F23401         MOVW.W          R1, #0x34
    00002c: C0F20001         MOVT.W          R1, #0x0
    000030:              $d:
    000030:              literalPool:
    000030: 7856            .half         0x5678
    000032: 3412            .half         0x1234
    000034: FECA            .half         0xCAFE
    000036: FECA            .half         0xCAFE

    It is visible that the instruction on the left (using the GNU object file) uses the wrong offset (4 instead of 0).

    And the same when linked with the GNU linker:

    GNU TI
    TEXT Section .text, 0x18 bytes at 0x00008000
    008000:              startFunc:
    008000:               .thumb
    008000:              :
    008000: 48F21000         MOVW.W          R0, #0x8010
    008004: C0F20000         MOVT.W          R0, #0x0
    008008: 48F21401         MOVW.W          R1, #0x8014
    00800c: C0F20001         MOVT.W          R1, #0x0
    008010:              $d:
    008010:              literalPool:
    008010: 7856            .half         0x5678
    008012: 3412            .half         0x1234
    008014: FECA            .half         0xCAFE
    008016: FECA            .half         0xCAFE
    TEXT Section .text, 0x18 bytes at 0x00008000
    008000:              startFunc:
    008000:               .thumb
    008000:              :
    008000: 48F21000         MOVW.W          R0, #0x8010
    008004: C0F20000         MOVT.W          R0, #0x0
    008008: 48F21401         MOVW.W          R1, #0x8014
    00800c: C0F20001         MOVT.W          R1, #0x0
    008010:              $d:
    008010:              literalPool:
    008010: 7856            .half         0x5678
    008012: 3412            .half         0x1234
    008014: FECA            .half         0xCAFE
    008016: FECA            .half         0xCAFE

    Here in both cases the correct output is generated.

    Best regards,
    Christian

  • Thank you for the test case.  I can reproduce the problem.  I filed the entry EXT_EP-9753 to have this issue investigated.  You are welcome to follow it with the link below in my signature.

    Thanks and regards,

    -George

  • Hello George,

    Thanks for creating the bug report.

    "The net result is that, when the GNU linker reads in the TI created object file, the final address is computed for this instruction ..."

    It is the other way around: ".., when the TI linker reads in the GNU created object file, ..."

    Best regards,
    Christian

  • Thank you.  I corrected the entry.

    Thanks and regards,

    -George