Call To External Thumb Code (BLX with set Thumb Bit)

Asked by Peter Herter

I wan't to build a application for a cortex m.
the application should call a thumb function which address is defined in a linker script.
but the linker create always a call to an arm function. i've created a realy reduced example, that generates the same problem.

i've compiled following example:

content of test.c
==============
__asm(" .type extFunc, %function");
__asm(".thumb_func");
extern void extFunc(void);
void main(void) {
 extFunc();
}

content of link.ld
=============
extFunc = 0x1000 +1 ; /* Thumb Symbol */

I'm using following command lines:
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m3 -o test.o test.c
arm-none-eabi-gcc -nostartfiles -nostdlib -nodefaultlibs -mthumb -mcpu=cortex-m3 test.o -T link.ld -o Test.elf
arm-none-eabi-readelf Test.elf -s
arm-none-eabi-objdump Test.elf -d

The output of readelf looks great: The symbol address of the main function and extFunc is odd.
but when i'm looking at the dissasembly of objdump, there is a BLX <immidate> instruction to an even address. (this means it is arm code),
i'm expecting a BLX to an odd address or an a BL instruction.

what is missing in my example code? what am i doing wrong?

A workaround would be to replace
extern void extFunc(void);
by
#define extFunc() ((void(*)(void))(0x1001))()
it's not my prefered way, because i want to define the adresses in a linker script

My Versions:
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.7.3 20121207 (release) [ARM/embedded-4_7-branch revision 194305]
GNU objdump (GNU Tools for ARM Embedded Processors) 2.22.0.20121207
GNU readelf (GNU Tools for ARM Embedded Processors) 2.22.0.20121207

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Joey Ye
Solved:
Last query:
Last reply:
Revision history for this message
Peter Herter (peter-herter) said :
#2

Joey Ye
Thanks for the answer. There's no problem when the same function is in the same file, or when it is defined in an other object file. So your solution will not solve my Problem.
I try to explain my problem again.

I know only the signature of the external function and the absolute address of the function. In My Example:
The Signature: void extFunc(void); //It’s a Thumb Function
The Address: 0x1000 (Somewhere in the flash)

So I write the absolute address of the extFunc to the linker script and the signature to the C (or Header) File as an external function.

So its correct that the map files show the symbol extFunc to the correct address. But there is the wrong binary shown by objdump, and also false generated with objcopy. Is this a bug?

I'v seen some other threads talking about the same problem (but not realy a solution)
http://comments.gmane.org/gmane.comp.gcc.cross-compiling.arm/2350
http://communities.mentor.com/community/cs/archives/arm-gnu/msg01687.html
http://communities.mentor.com/community/cs/archives/arm-gnu/msg03586.html
http://communities.mentor.com/community/cs/archives/arm-gnu/msg02654.html

-----Ursprüngliche Nachricht-----
Von: <email address hidden> [mailto:<email address hidden>] Im Auftrag von Joey Ye
Gesendet: Mittwoch, 20. März 2013 07:51
An: Herter Peter
Betreff: Re: [Question #224550]: Call To External Thumb Code (BLX with set Thumb Bit)

Your question #224550 on GCC ARM Embedded changed:
https://answers.launchpad.net/gcc-arm-embedded/+question/224550

    Status: Open => Answered

Joey Ye proposed the following answer:
Peter,

I suspect it just objdump automatically removes bit 0 from address for readability. The logic is correct, which can be indicated by two proofs.

If you generate map file, you will see that extFunc is exactly a odd address.

If you remove all these abnormal __asm and ignore the assignment in link.ld, and try following example, the objdump still shows blx to an even address. And it executes.

int g;
__attribute__((noinline)) void ext2Func(void) {
 g = 1;
}
void main(void) {
 ext2Func();
}

--
If this answers your question, please go to the following page to let us know that it is solved:
https://answers.launchpad.net/gcc-arm-embedded/+question/224550/+confirm?answer_id=0

If you still need help, you can reply to this email or go to the following page to enter your feedback:
https://answers.launchpad.net/gcc-arm-embedded/+question/224550

You received this question notification because you asked the question.

Revision history for this message
Best Joey Ye (jinyun-ye) said :
#3

Peter,

Sorry for the mis-understanding of the problem. It looks an issue in linker. It basically doesn't know extFunc is a function symbol. Declaring __asm(" .type extFunc, %function") in reference place doesn't help. It might take some time to fix it, if maintainers are convinced it is a bug.

But I have a work around by removing the __asm in main.c and add following extFunc.c to your project:

$ cat extFunc.c
__attribute__((naked)) void extFunc(){}

As extFunc.o makes extFunc a function symbol, linker knows how to relocate it properly. Can you please try if it works for you?

- Joey

Revision history for this message
Peter Herter (peter-herter) said :
#4

Thanks a lot for the information about the workaround. It's a working possibility.

I tried an other workaround. I compile with the option -mlong-calls. this will also help to generate correct branches.

Wher can i found the tracker to the bug?

Revision history for this message
Terry Guo (terry.guo) said :
#5

I just reported it as a bug of GNU Linker at http://sourceware.org/bugzilla/show_bug.cgi?id=15302.

Revision history for this message
Joey Ye (jinyun-ye) said :
#6

> I tried an other workaround. I compile with the option -mlong-calls. this will also help to generate correct branches.
-mlong-calls works, but it introduces indirect call every time that hurts both performance and code size. Just for you consideration my workaround can avoid this overhead.