This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [ARM] Wrong BLX destination
- From: Christophe Lyon <christophe dot lyon at linaro dot org>
- To: Simon Marchi <simon dot marchi at polymtl dot ca>
- Cc: binutils at sourceware dot org
- Date: Wed, 9 Mar 2016 09:07:40 +0100
- Subject: Re: [ARM] Wrong BLX destination
- Authentication-results: sourceware.org; auth=none
On 8 March 2016 at 00:11, Simon Marchi <simon.marchi@polymtl.ca> wrote:
> 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?
>
Hi,
I haven't looked at this for a while, but:
- which relocations are encoded by gas? (objdump -r). I suspect you
have the ARM version of call (as opposed to the thumb one)
- I think you have to use the .thumb_func assembly directive right
before helloX definition, and probably give it a function type too
The linker will take care of making the call point to the right
address, provided it has the right relocations.
Christophe.
> Thanks!
>
> Simon