[ARM] Wrong BLX destination

Simon Marchi simon.marchi@polymtl.ca
Mon Mar 7 23:11:00 GMT 2016


Hi,

I noticed a behavior I can't explain while playing with gas and ld on 
ARM, I thought this list would be the best place to ask for help.  There 
is nothing mission-critical, I would just like an explanation to satisfy 
my curiosity.

My initial question was if it was possible to have a BLX instruction 
(the version that takes a an immediate value) that jumps from ARM code 
to Thumb code, to an address that is not a multiple of 4.  The ARM 
instruction set seems to support it (because of the H bit in the 
instruction's encoding), so I wanted to try to make gas generate it.

It seems like C functions (even in Thumb mode) are always placed on PCs 
multiples of four, so I decided to generate symbols by hand in assembly. 
  I just want to see the generated instruction, I don't intend to run it, 
so the data at these location is garbage.

So I made this little test.S:

   .arm

   hello1:
   .hword 0x1111

   hello2:
   .hword 0x2222

   hello3:
   .hword 0x3333

   # Space things out a bit
   .fill 20, 4, 0

   .align 4

   blx hello1
   blx hello2
   blx hello3

I compile it like this (main.c is just an empty main function):

   gcc -g3 -O0  main.c test.S

This is the relevant disassembly:

   000083d0 <hello1>:
       83d0:       1111            asrs    r1, r2, #4

   000083d2 <hello2>:
       83d2:       2222            movs    r2, #34 ; 0x22

   000083d4 <hello3>:
       83d4:       3333            adds    r3, #51 ; 0x33
           ...
       8426:       0000            .short  0x0000
       8428:       e320f000        nop     {0}
       842c:       e320f000        nop     {0}
       8430:       faffffe6        blx     83d0 <hello1>
       8434:       fbffffe5        blx     83d2 <hello2>
       8438:       faffffe5        blx     83d4 <hello3>
       843c:       e320f000        nop     {0}

Everything looks good, we can see that the call to hello2 points indeed 
to an address that isn't a multiple of 4.

I then tried to do the same thing, except I placed the target symbols in 
another compilation unit (IOW, ld is now involved in linking/patching 
the instructions).  So I now have test.S with only the calls:

   .arm

   .align 4

   blx hello1
   blx hello2
   blx hello3

   # Space things out a bit
   .fill 20, 4, 0

and test2.S with the labels:

   .arm

   .global hello1
   .global hello2
   .global hello3

   hello1:
   .hword 0x1111

   hello2:
   .hword 0x2222

   hello3:
   .hword 0x3333

   # Space things out a bit
   .fill 20, 4, 0

This is the resulting disassembly:

       83d0:       fa000016        blx     8430 <hello1>
       83d4:       fa000015        blx     8430 <hello1>  <---- WRONG 
TARGET
       83d8:       fa000015        blx     8434 <hello3>
           ...
       842c:       e320f000        nop     {0}

   00008430 <hello1>:
       8430:       22221111        eorcs   r1, r2, #1073741828     ; 
0x40000004

   00008432 <hello2>:
       8432:       33332222        teqcc   r3, #536870914  ; 0x20000002

   00008434 <hello3>:
       8434:       00003333        andeq   r3, r0, r3, lsr r3

As you can see, the second blx instruction points to hello1, whereas it 
should point to hello2.

Do you know if this is the intended behavior, and if so, what explains 
it?  Is there some alignment requirements that differs in both cases?

Thanks!

Simon



More information about the Binutils mailing list