gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Problem calling function pointer from IWRAM

#21676 - mclysenk - Wed Jun 02, 2004 10:20 pm

I have the following code:

Code:

void (*p_func_ptr)();

void not_in_iwram()
{
     p_func_ptr();
}

void __attribute__ ((section (".iwram"), long_call)) code_in_iwram()
{
     p_func_ptr();
}


Both of these compile just fine, but when it comes time to link, I get the following error:

relocation truncated to fit: R_ARM_THM_PC22 _call_via_r2
collect2: ld returned 1 exit status

The error only occurs in the IWRAM function and I can't figure out why.

#21678 - Miked0801 - Wed Jun 02, 2004 10:23 pm

Are you compiling with interworking on? That error usually means either no interworking or that the function pointer is beign access wrong and turned into a local jump even though it won't work as such.

#21679 - mclysenk - Wed Jun 02, 2004 10:35 pm

I am compiling with the command:
arm-elf-gcc -MMD -g -Wall -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork -o test.o -c test.c

and linking with the command
ld -g -mthumb -mthumb-interwork -specs=gba.specs test.o -o test.elf

#21680 - poslundc - Wed Jun 02, 2004 10:40 pm

Can you compile with the -S flag and post the assembly output the compiler is generating? That may shed some light on the situation.

Dan.

#21681 - mclysenk - Wed Jun 02, 2004 11:03 pm

Here is the generated assembly for both functions:

Code:

   .align   2
   .global   not_in_iwram
   .code 16
   .thumb_func
   .type   not_in_iwram, %function
not_in_iwram:
.LFB2:
   .file 1 "test.c"
   .loc 1 4 0
   push   {r7, lr}
.LCFI0:
   mov   r7, sp
.LCFI1:
   .loc 1 5 0
   ldr   r3, .L2
   ldr   r3, [r3]
   bl   _call_via_r3
   .loc 1 6 0
   mov   sp, r7
   @ sp needed for prologue
   pop   {r7}
   pop   {r0}
   bx   r0
.L3:
   .align   2
.L2:
   .word   p_func_ptr

Code:

   .size   not_in_iwram, .-not_in_iwram
   .section   .iwram,"ax",%progbits
   .align   2
   .global   code_in_iwram
   .code 16
   .thumb_func
   .type   code_in_iwram, %function
code_in_iwram:
.LFB3:
   .loc 1 9 0
   push   {r7, lr}
.LCFI2:
   mov   r7, sp
.LCFI3:
   .loc 1 10 0
   ldr   r3, .L5
   ldr   r3, [r3]
   bl   _call_via_r3
   .loc 1 11 0
   mov   sp, r7
   @ sp needed for prologue
   pop   {r7}
   pop   {r0}
   bx   r0
.L6:
   .align   2
.L5:
   .word   p_func_ptr

Both seem to be using _call_via_r3 to call the function pointer, but for some odd reason, the linker does not like that when the function is in iwram. Is there anyway to fix this?

#21687 - dagamer34 - Thu Jun 03, 2004 12:40 am

The solution is on the www.devrs.com/gba webpage. I think you can't have your IWRAM function in the same file as your main function (only a guess). Try moving it to its own file and see what happens.
_________________
Little kids and Playstation 2's don't mix. :(

#21712 - mclysenk - Thu Jun 03, 2004 1:24 pm

I finally fixed it. As it turns out, devrs' solution doesn't work either; the real problem was a bug in the linkscript for DevkitARM. I fixed the problem by switching my project over to HAM and now everything compiles and links just fine.

#21718 - tepples - Thu Jun 03, 2004 6:44 pm

Could you reduce the bug to a minimal test case and then PM wintermute about it?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#21755 - mclysenk - Fri Jun 04, 2004 3:20 pm

Actually, I determined the error occurs whenever you have two different functions, each with their own section, in the same file. For some odd reason, the linker gets messed up and only the ROM functions can be called. I wish I there were some tutorials or documents about putting things in IWRAM, EWRAM or ROM.

#21766 - wintermute - Fri Jun 04, 2004 5:31 pm

the link error occurs because the distance between iwram and rom is greater than the maximum branch offset allowed by the ARM chip. You don't get a compile error because the addresses are unknown until link time.

the issue is related to interworking code which uses call_via_rx stubs in libgcc. Unfortunately the stubs are in rom so neither iwram nor ewram code can reach them.

I'm currently looking at a workaround for this for the next release.


Last edited by wintermute on Fri Jun 04, 2004 5:59 pm; edited 1 time in total

#21769 - tepples - Fri Jun 04, 2004 5:42 pm

wintermute wrote:
You call call iwram functions from rom but not the other way round.

Is there a specific reason that a function in IWRAM can't long_call a function in ROM?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#21772 - wintermute - Fri Jun 04, 2004 6:01 pm

tepples wrote:
wintermute wrote:
You call call iwram functions from rom but not the other way round.

Is there a specific reason that a function in IWRAM can't long_call a function in ROM?


heh, got me mid edit :)

the functions gcc uses to perform this are in libgcc. Those functions go in the normal text segment

#21774 - tepples - Fri Jun 04, 2004 6:25 pm

I wonder why it even needs a stub and can't just inline the call_via_rx.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#21788 - wintermute - Sat Jun 05, 2004 12:10 pm

mclysenk wrote:
I finally fixed it. As it turns out, devrs' solution doesn't work either; the real problem was a bug in the linkscript for DevkitARM. I fixed the problem by switching my project over to HAM and now everything compiles and links just fine.


It's not a linkscript bug

#21970 - pentagram - Thu Jun 10, 2004 12:06 pm

tepples wrote:
Is there a specific reason that a function in IWRAM can't long_call a function in ROM?

No there isn't, provided you declare the ROM function as long_call, in same manner as you declare long_call an IWRAM function being called from ROM.
In fact, the long_call label is only needed when the caller and callee are placed in different sections, that is, an IWRAM function that is only called by another IWRAM function does not need to be declared as long_call.

#21971 - wintermute - Thu Jun 10, 2004 2:01 pm

pentagram wrote:
tepples wrote:
Is there a specific reason that a function in IWRAM can't long_call a function in ROM?

No there isn't, provided you declare the ROM function as long_call, in same manner as you declare long_call an IWRAM function being called from ROM.
In fact, the long_call label is only needed when the caller and callee are placed in different sections, that is, an IWRAM function that is only called by another IWRAM function does not need to be declared as long_call.


Yes there is. long_call uses the _call_via_rx stubs in libgcc, those stubs are placed in ROM so IRWAM and EWRAM code can't use them.

As I said earlier I'm testing a patch to get around this problem.

#21992 - mclysenk - Thu Jun 10, 2004 10:09 pm

Ok, thanks for clearing that up. I was completely confused by the bug the first time I smacked into it.

I really do like DevKitARM and it's minimal interface, and I can't wait until the patch is ready to use.

#22019 - pentagram - Fri Jun 11, 2004 9:40 am

wintermute wrote:
Yes there is. long_call uses the _call_via_rx stubs in libgcc, those stubs are placed in ROM so IRWAM and EWRAM code can't use them.


Ok, I see. I'm not an expert in the gcc internals, and made my post based on my tests. All I can say is that I have code that makes calls from IWRAM to ROM and it works. I have checked the .map and assembler files to make sure that nothing gets inlined.
I also have tested a forced long_call from IWRAM to IWRAM and it works too.

#22023 - wintermute - Fri Jun 11, 2004 2:29 pm

pentagram wrote:
wintermute wrote:
Yes there is. long_call uses the _call_via_rx stubs in libgcc, those stubs are placed in ROM so IRWAM and EWRAM code can't use them.


Ok, I see. I'm not an expert in the gcc internals, and made my post based on my tests. All I can say is that I have code that makes calls from IWRAM to ROM and it works. I have checked the .map and assembler files to make sure that nothing gets inlined.
I also have tested a forced long_call from IWRAM to IWRAM and it works too.


you didn't make your tests with unadulterated FSF sources or with the toolchain the question was about therefore they are irrelevant.

#22035 - pentagram - Fri Jun 11, 2004 6:25 pm

wintermute wrote:

you didn't make your tests with unadulterated FSF sources or with the toolchain the question was about therefore they are irrelevant.


Irrelevant? I'm not sure....
Yes, my toolchain is different, it is DKA R5b3, based on gcc v3.2.2, and looking closer at the assembly output and comparing it with the code from mclysenk it turns that DKA's calling protocol is absolutely different and does not use the stubs. Are those stubs really necessary? Aren't they adding overhead to the call?

#22045 - wintermute - Sat Jun 12, 2004 3:24 am

pentagram wrote:
wintermute wrote:

you didn't make your tests with unadulterated FSF sources or with the toolchain the question was about therefore they are irrelevant.


Irrelevant? I'm not sure....
Yes, my toolchain is different, it is DKA R5b3, based on gcc v3.2.2, and looking closer at the assembly output and comparing it with the code from mclysenk it turns that DKA's calling protocol is absolutely different and does not use the stubs. Are those stubs really necessary? Aren't they adding overhead to the call?


There's something missing in your 'tests' then - dka r5b3 has the same 'relocation truncated to fit' error - I've just tested it here. DKA's calling protocol is no different - there's actually an option which effectively inlines the call_via_rx stubs - you're using that option to get the code to work.

devkitARM_r6a now emits similar code.

The stubs actually *remove* overhead, requiring 2 extra instructions per function call without the stubs.

No they're not necessary but will reduce the size of the binary if they're within range.