Linker links to a wrong address (ARM, GNU LD)

Programming, for all ages and all languages.
Post Reply
RedEagle
Member
Member
Posts: 31
Joined: Sat Nov 04, 2006 5:38 am
Location: Earth
Contact:

Linker links to a wrong address (ARM, GNU LD)

Post by RedEagle »

Hi :)
I have a Problem with my linker, I explain the problem at the function stCalibrateVref out of a proprietary library called simplemac. The problem appears everywhere inside the library. The processor is a cortex-m3.

The stCalibrateVref function out of the library:

Code: Select all

arm-none-eabi-objdump -d -j .text libsimplemac.a > libsimplemac.dump
00000076 <stCalibrateVref>:
  76:   b530            push    {r4, r5, lr}
  78:   b087            sub     sp, #28
  7a:   230a            movs    r3, #10
  7c:   227f            movs    r2, #127        ; 0x7f
  7e:   f85f 0004       ldr.w   r0, [pc, #-4]   ; 650 <??DataTable15_4>
  82:   8801            ldrh    r1, [r0, #0]
  84:   a803            add     r0, sp, #12
  86:   f7ff fffe       bl      0 <halInternalGetMfgTokenData>
  8a:   f8bd 1012       ldrh.w  r1, [sp, #18]
  8e:   f85f 5004       ldr.w   r5, [pc, #-4]   ; 64c <??DataTable15_3>
  92:   f64f 72ff       movw    r2, #65535      ; 0xffff
  96:   4291            cmp     r1, r2
  98:   d002            beq.n   a0 <??stCalibrateVref_0>
  9a:   7b28            ldrb    r0, [r5, #12]
  9c:   07c0            lsls    r0, r0, #31
  9e:   d57c            bpl.n   19a <??stCalibrateVref_1>

The stCalibrateVref function after linking:

Code: Select all

arm-none-eabi-objdump -d -j .text binary.elf > binary.dump
08007972 <stCalibrateVref>:
 8007972:       b530            push    {r4, r5, lr}
 8007974:       b087            sub     sp, #28
 8007976:       230a            movs    r3, #10
 8007978:       227f            movs    r2, #127        ; 0x7f
 800797a:       f8df 05ce       ldr.w   r0, [pc, #1486] ; 8007f4a <??DataTable15_3+0x2>
 800797e:       8801            ldrh    r1, [r0, #0]
 8007980:       a803            add     r0, sp, #12
 8007982:       f7fc faf5       bl      8003f70 <halInternalGetMfgTokenData>
 8007986:       f8bd 1012       ldrh.w  r1, [sp, #18]
 800798a:       f8df 55ba       ldr.w   r5, [pc, #1466] ; 8007f46 <??DataTable15_2+0x2>
 800798e:       f64f 72ff       movw    r2, #65535      ; 0xffff
 8007992:       4291            cmp     r1, r2
 8007994:       d002            beq.n   800799c <??stCalibrateVref_0>
 8007996:       7b28            ldrb    r0, [r5, #12]
 8007998:       07c0            lsls    r0, r0, #31
 800799a:       d57c            bpl.n   8007a96 <??stCalibrateVref_1>
Stack after crash

Code: Select all

  xPSR: 0x01000000
    PC: 0x0800797E
    LR: 0x08004AD7
   R12: 0x88000081
   R3 : 0x0000000A
   R2 : 0x0000007F
   R1 : 0x00000001
   R0 : 0xF4042000
So, the program crashs at address 0x0800797E.
Problem: r0 contains a wrong value. This wrong value comes from the instruction above. (@ 0x0800797a)

It reads a value from PC+1486 = 0x08007F4A (At the time, the address gets calculated, the PC points at the second half-word of the
instruction) which points to the value 0xF4042000

Code: Select all

 (gdb) x/x 0x8007f4A
 0x8007f4a <??DataTable15_3+2>:  0xf4042000
Increasing this invalid address by 2 leads to 0x8007F4C
At this address the wished value is stored, that is addressed in the libraries dump

Code: Select all

 (gdb) x/x 0x8007f4C
 0x8007f4c <??DataTable15_4>:    0x0800f404
This values points to data which seems to be the a valid argument for the following function-call (halInternalGetMfgTokenData)

Code: Select all

 (gdb) x/x 0x800f404
 0x800f404 <TOKEN_MFG_ANALOG_TRIM_BOTH>: 0x07dc07d2
So, why the hell does the linker link to <??DataTable15_3+2> and not to <??DataTable15_4>?

I use the following setup:

Code: Select all

 CFLAGS="-Wall -nostdlib -fno-common -fno-builtin -O0 -g -mcpu=cortex-m3 -mthumb -c -std=c99 -fshort-wchar $DEFINES $HEADERPATHES"
 LDFLAGS="-nostartfiles -nostdlib -static -A cortex-m3 -T$LDFILE $LIBPATHES"
I tested it with the following versions (same result with both)

Code: Select all

 arm-none-eabi-ld --version
 -> GNU ld (GNU Binutils) 2.23.1
 -> GNU ld (GNU Binutils) 2.21.1
 arm-none-eabi-gcc --version
 -> arm-none-eabi-gcc (Linaro GCC 4.7-2013.01) 4.7.3 20130102
 -> arm-none-eabi-gcc (Linaro GCC 4.6-2011.10) 4.6.2 20111004
This is my linker-script

Code: Select all

/*based on stm32_flash.ld form STM*/
ENTRY(Reset_Handler)

_estack = 0x20004000;
_Min_Heap_Size = 0x100;
_Min_Stack_Size = 4K;
_stack_size = _Min_Stack_Size;

MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 256K
  RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 16K
}

SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } >FLASH

  .text :
  {
    . = ALIGN(4);
    *(.text)
    *(.text*)
    *(.rodata)
    *(.rodata*)
    *(.glue_7)
    *(.glue_7t)
    *(.eh_frame)
    *(.constdata)
    *(.rev16_text)
    *(.revsh_text)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;
  } >FLASH

  _sidata = .;

  .data : AT ( _sidata )
  {
    . = ALIGN(4);
    _sdata = .;
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } >RAM

  . = ALIGN(4);
  .bss :
  {
    _sbss = .;
    __bss_start__ = _sbss;

    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;
    __bss_end__ = _ebss;
  } >RAM

  ._user_heap_stack :
  {
    . = ALIGN(4);
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM


/* source: http://eehusky.wordpress.com/2012/12/17/using-gcc-with-the-ti-stellaris-launchpad-newlib/ */
    _heap_bottom = .;
    heap_low = _heap_bottom;
    _heap_top = ORIGIN(RAM) + LENGTH(RAM) - _stack_size;
    heap_top = _heap_top;

    _stack_bottom = _heap_top;
    _stack_top = ORIGIN(RAM) + LENGTH(RAM);

  .ARM.attributes 0 : { *(.ARM.attributes) }
}
Some information about the ABI:
analogue.o is part of the libsimplemac.a

Code: Select all

readelf -a analogue.o | grep ABI
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Flags:                             0x5000000, Version5 EABI
  Tag_ABI_PCS_GOT_use: direct
  Tag_ABI_FP_denormal: Sign only
  Tag_ABI_FP_number_model: Finite
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_optimization_goals: Aggressive Size
  Tag_ABI_PCS_GOT_use: direct
  Tag_ABI_PCS_wchar_t: 2
  Tag_ABI_FP_denormal: Sign only
  Tag_ABI_FP_number_model: Finite
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: small
  Tag_ABI_optimization_goals: Prefer Size
The code which uses the library

Code: Select all

readelf -a main.o | grep ABI
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Flags:                             0x5000000, Version5 EABI
  Tag_ABI_PCS_wchar_t: 2
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: small
  Tag_ABI_optimization_goals: Aggressive Debug
I hope someone has a good idea or a hint :)
mfg.: RedEagle
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Linker links to a wrong address (ARM, GNU LD)

Post by sortie »

Hi, this is an overwhelming amount of debugging information, but good to have it. :-)

I can't spot your problem, but perhaps the problem seems to be related to position independent code since it loads the address relative to the program counter. Perhaps there is some problem with alignment or it thinks it is being linked at a wrong location.

In addition, you are passing some bad flags to your compiler, but that is likely irrelevant to this problem. You shouldn't pass the -fno-builtin option as it allows the compiler to optimize your code knowing what common functions do (assuming your standard functions such as 'strlen' does what one would expect). Note how -nostdlib is equal to -nodefaultlibs -nostartfiles, so your additional -nostartfiles is redundant.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Linker links to a wrong address (ARM, GNU LD)

Post by jnc100 »

Could you display the output of the disassembly of the object file with the relocation types too? (i.e. objdump -dr ...)

Do you have access to the source for this library? If so, perhaps you could try compiling it in ARM mode (rather than thumb) and seeing if that helps.

Regards,
John
RedEagle
Member
Member
Posts: 31
Joined: Sat Nov 04, 2006 5:38 am
Location: Earth
Contact:

Re: Linker links to a wrong address (ARM, GNU LD)

Post by RedEagle »

I forgot to mention that I tried . = ALIGN(4); and . = ALIGN(2); but it didn't change anything.

@jnc100: No, there is no source code for this library available :(
arm-none-eabi-objdump -dr libsimplemac.a

Code: Select all

00000076 <stCalibrateVref>:
  76:   b530            push    {r4, r5, lr}
  78:   b087            sub     sp, #28
  7a:   230a            movs    r3, #10
  7c:   227f            movs    r2, #127        ; 0x7f
  7e:   f85f 0004       ldr.w   r0, [pc, #-4]   ; 650 <??DataTable15_4>
                        7e: R_ARM_THM_PC12      ??DataTable15_4
  82:   8801            ldrh    r1, [r0, #0]
  84:   a803            add     r0, sp, #12
  86:   f7ff fffe       bl      0 <halInternalGetMfgTokenData>
                        86: R_ARM_THM_CALL      halInternalGetMfgTokenData
  8a:   f8bd 1012       ldrh.w  r1, [sp, #18]
  8e:   f85f 5004       ldr.w   r5, [pc, #-4]   ; 64c <??DataTable15_3>
                        8e: R_ARM_THM_PC12      ??DataTable15_3
  92:   f64f 72ff       movw    r2, #65535      ; 0xffff
  96:   4291            cmp     r1, r2
  98:   d002            beq.n   a0 <??stCalibrateVref_0>
  9a:   7b28            ldrb    r0, [r5, #12]
  9c:   07c0            lsls    r0, r0, #31
  9e:   d57c            bpl.n   19a <??stCalibrateVref_1>
mfg.: RedEagle
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Linker links to a wrong address (ARM, GNU LD)

Post by jnc100 »

I am no expert on the Thumb instruction set (I've only worked with 32-bit ARM instructions), but I wonder whether ld is at fault here (or you're missing some options that I can't seem to find):

According to the ARM manual, the Thumb32 encoding of ldr.w (literal) calculates the target address as Align(PC, 4) + SignExtend(imm12). Given that in Thumb mode, PC is 4 bytes ahead of the current instruction, this equates (in the output binary) to: Align(0x0800797e, 4) + 0x000005ce = 0x0800797c + 0x000005ce = 0x08007f4a, which as observed is wrong. The reason here I think is that the calculation used to generate the 0x5ce is wrong.

According to the ARM ELF supplement, R_ARM_THM_PC12 is calculated as S + A - Pa, where S is the target (i.e. 0x08007f4c), A is the addend (here -4 to account for the fact that PC is 4 bytes ahead in Thumb mode) and Pa = P & 0xfffffffc, where P is the place being relocated (here 0x0800797a, thus Pa = 0x08007978). The reason Pa is used instead of P is to account for the alignment of PC in the ldr.w instruction above.

S + A - Pa = 0x5d0, which when added to 0x0800797c gives the correct address.
S + A - P = 0x5ce, which doesn't. I wonder whether this is the calculation ld is using here.

Did ALIGN(4) cause the stCalibrateVref function to be aligned on a 4 byte boundary? If not, trying to enforce this is the only other thing I can suggest. Other than this, unless anyone else has any suggestions, perhaps you could ask on the binutils mailing list?

Regards,
John.
speedyxvn
Posts: 1
Joined: Wed Jan 28, 2015 7:35 am

Re: Linker links to a wrong address (ARM, GNU LD)

Post by speedyxvn »

Heh, I just registered on this forum learning about ABI-s and other terms in embedded software development. Nonetheless, I will post something more like a question.

It looks like the library is compiled for hardware floating point support (by looking in Tag_ABI_FP_number_model: Finite); while the code that needs to use it compiles for a target with software floating point: Tag_ABI_FP_number_model: IEEE 754. Does this work? I am a beginner so this may seem a bit idiotic. :o In case you know general details about this, please explain.

Thanks!
Post Reply