This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[ARM]ÂWrong BLX destination
- From: Simon Marchi <simon dot marchi at polymtl dot ca>
- To: binutils at sourceware dot org
- Date: Mon, 07 Mar 2016 18:11:35 -0500
- Subject: [ARM]ÂWrong BLX destination
- Authentication-results: sourceware.org; auth=none
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