section GNU attribute to put function in RAM cannot be stepped through

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

section GNU attribute to put function in RAM cannot be stepped through

6,388 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lucasrangit on Wed Jul 21 11:48:20 MST 2010
Following the suggestion from CodeRedSupport in topic 551 I am using the __section__ GNU attribute to tell the compiler to place a function in RAM; in my case I am using the .data section for convenience. However, when I do so I am not able to step or resume from a breakpoint within that function.

If I put a breakpoint after that function returns the program operates correctly. I have verified that the program counter goes into RAM (0x1000 0000+) and the function shows up in the .data memory map.

Is this a limitation in the debugger? And/Or is it because I am using the .data section?

__attribute__ ((__section__(".data")))
void ram_func(void) {
 :
}


Also, if I have a function call within the RAM function I get the following relocation error:

DescriptionResourcePathLocationType
relocation truncated to fit: R_ARM_THM_CALL against symbol `memset' defined in .text.memset section in c:/nxp/lpcxpresso_3.4/tools/bin/../lib/gcc/arm-none-eabi/4.3.3/../../../../arm-none-eabi/lib/thumb2\libcr_c.a(memset.o)main.c/srcline 250C/C++ Problem


Thanks for any help.

Original Attachment has been moved to: 1100557_lpc17xx_uart.zip

0 Kudos
Reply
10 Replies

3,589 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Fri Jul 23 00:01:34 MST 2010
Can you post you linker script?
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lucasrangit on Thu Jul 22 21:57:26 MST 2010
After doing a clean rebuild I notice that using either the ".data" or ".data.ramfunc" section attribute gives the following warning. This doesn't appear to impact the relocation into RAM. Can you explain it?

C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cc8zdhpT.s:2664: Warning: ignoring changed section attributes for .data
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lucasrangit on Thu Jul 22 18:23:41 MST 2010

Quote: CodeRedSupport
Are you saying that none of the three suggestions for debugging in my previous post work for you:

[LIST]
[*]Instruction level step into the veneer, then source level step.
[*]Set the breakpoint in the veneer rather than the ram function itself
[*]Use function pointer to call the ram function, rather than relying on the linker generated veneer
[/LIST]
??



I apologize for not being clearer. I have not tried the first two workarounds since the [U]third option works for me[/U].
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Thu Jul 22 14:26:29 MST 2010

Quote: lucasrangit
Thanks for looking further into this. Your suggestion does workaround the relocation link issue but still does not allow me to step into the RAM function or within it.



Are you saying that none of the three suggestions for debugging in my previous post work for you:

[LIST]
[*]Instruction level step into the veneer, then source level step.
[*]Set the breakpoint in the veneer rather than the ram function itself
[*]Use function pointer to call the ram function, rather than relying on the linker generated veneer
[/LIST]
??

Regards,
CodeRedSupport
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lucasrangit on Thu Jul 22 10:02:00 MST 2010

Quote: CodeRedSupport
After some more testing, I have found that you can also work around the  relocation issue caused by your call back from ram to flash by changing  the name of the section that you place your ram_func in. The following  allows the link to complete successfully

__attribute__ ((__section__(".data.ramfunc")))
void ram_func(void) {
 :



Thanks for looking further into this. Your suggestion does workaround the relocation link issue but still does not allow me to step into the RAM function or within it.

Regardless, in my case I cannot call back to flash from RAM because I am updating flash so I've worked around the relocation issue by eliminating any external dependencies in the RAM function.

Thanks again for all the help.
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Thu Jul 22 07:26:47 MST 2010

Quote: curtvm

The problem is the linker incorrectly using BLX, and until the linker is corrected a workaround is needed. I guess it also can be said objdump is happy decoding that incorrect BLX instruction when producing the lss file.


The issue your refer to is actually a Cortex-M0 specific issue, so only affects LPC11xx, not LPC13xx or LPC17xx.


Quote: curtvm

To CodeRedSupport-
any idea when the linker will be corrected? also will you be able to get the debugging to work for functions that run from ram?

(I am using 3.3.4, and I see 3.4.0 is available, so maybe its fixed already)


It is very  likely that later this year we will release  a version of the LPCXpresso IDE that encorporates a more recent version of gcc  than the current 4.3.3. Such a release will also include a linker with the CM0 BLX issue fixed. I cannot commit to a firm data for this though - so please don't ask!

With regards to debugging functions from RAM, I am afraid that at present I'm not actually 100% sure what is causing the behaviour that is been seen. The best workarounds I can see at present are:

[LIST=1]
[*]Instruction step into the RAM function (ie through the long branch veneer).  Once you have reached the RAM function, you appear to be able to debug "as normal".
[*]If you want to set a breakpoint on the RAM function, set it on the long branch veneer, rather than the function itself. If your ram function is called ram_func(), then the veneer will be '__ram_func_veneer'. Use the breakpoint view to set a breakpoint on this, either by using the symbol name, or by looking in the mapfile/disassembly file to find the address. Once you then hit the breakpoint in the veneer, you appear to be able to source step into the ram function without problem
[*]If possible, use function pointers to jump to the RAM function rather than relying upon the the linker's long branch veneer. Then you don't see any problem debugging the RAM function - as far as I can tell :)
[/LIST]
Regards,
CodeRedSupport
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by curtvm on Thu Jul 22 05:46:59 MST 2010
This thread has some more info-
http://knowledgebase.nxp.com/showthread.php?t=403

The problem is the linker incorrectly using BLX, and until the linker is corrected a workaround is needed. I guess it also can be said objdump is happy decoding that incorrect BLX instruction when producing the lss file.

You can create macros to help-
#define RAM_FUNC(r) ((void(*)(void))&r+1)()
#define FLASH_FUNC(f) RAM_FUNC(f) //same thing, different name
//example
//RAM_FUNC(my_ram_function); //calling ram from flash
//FLASH_FUNC(a_normal_func); //calling flash from ram

of course more macros needed depending on parameters and return values needed for the function typecast.

Notice the +1, which does two things- it prevents the linker(?) from being too smart and basically ignoring your function pointer (it will still incorrectly use BLX), and it also makes sure the lowest bit is set for thumb mode which is required for the resulting BLX which is correctly used when loading the address from a register.

To CodeRedSupport-
any idea when the linker will be corrected? also will you be able to get the debugging to work for functions that run from ram?

(I am using 3.3.4, and I see 3.4.0 is available, so maybe its fixed already)
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Thu Jul 22 00:33:45 MST 2010

Quote: lucasrangit
Thanks for the reply. I will try making use of the function pointers like you suggested to get around the relocation and debugging issues and report back.



After some more testing, I have found that you can also work around the  relocation issue caused by your call back from ram to flash by changing  the name of the section that you place your ram_func in. The following  allows the link to complete successfully

__attribute__ ((__section__(".data.ramfunc")))
void ram_func(void) {
 :

Quote: lucasrangit

In my case it is not an issue of performance. Sorry for not clarifying that. What I am trying to do with this function is create an IAP function that will complete an online software upgrade by overwriting the running application in flash with a new application written to a reserved flash sector.

What do you think of that approach?



Seems reasonable. It always helps to understand what you are trying to achieve when answering questions which don't necessarily provide the full story
Regards,
CodeRedSupport.
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lucasrangit on Wed Jul 21 15:11:27 MST 2010
Thanks for the reply. I will try making use of the function pointers like you suggested to get around the relocation and debugging issues and report back.


Quote:
However this does all leave the question as to why you want to do this? Typically you might want to put a performance critical into RAM so that it executes more quickly than it would from flash. However there has been some debate in previous forum threads as to whether this will actually work (ie give better performance) with the LPC parts. You might want to look into this.

And if you are putting a performance critical routine in RAM, do you really want to be calling back to a flash routine from within it??



In my case it is not an issue of performance. Sorry for not clarifying that. What I am trying to do with this function is create an IAP function that will complete an online software upgrade by overwriting the running application in flash with a new application written to a reserved flash sector.

What do you think of that approach?
0 Kudos
Reply

3,588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Wed Jul 21 13:59:12 MST 2010
I can replicate your "strange debug behaviour". We will look into this - but note from my experiments, you seem to be able to workaround this sometimes by using "Run to cursor" (select a line, then press ctrl-R) or stepping at the instruction level rather than the source level (toggle the "i->" icon on). Also see the comments about function pointers below for a potentially more useful workaround.

With regards to your problem with calling another function from within your ram based function, the reason for this is as follows...

When you place your function in RAM at this high address, the linker has to insert a "long branch veneer" to allow your code in flash to call the function in RAM. This veneer is being placed by the linker at the end of your code in flash.

When you then try to call back from your RAM function to a function in flash, the linker tries to create another long branch veneer to get back to the code in flash. However it is placing this in with the other veneer - which is in flash, and hence out of range of your function in RAM to reach. Hence you get a link error.

The simplest way to work around this is to call the function in flash from the function in RAM using a function pointer....

void flash_func(void);

__attribute__ ((__section__(".text.ram")))
void ram_func(void) {
  :
 void (*longfunc)(void) = &flash_func;
 (*longfunc)();
 : 
}
Note that if you also use a function point to call your function in RAM, then it would appear that this will avoid the debug issues discussed above.

However this does all leave the question as to why you want to do this?  Typically you might want to put a performance critical into RAM so that  it executes more quickly than it would from flash. However there has been some debate in previous  forum threads as to whether this will actually work (ie give better performance) with the LPC parts. You might want to look into this.

And if you are putting a performance critical routine in RAM, do you really want to be calling back to a flash routine from within it??

Regards,
CodeRedSupport
0 Kudos
Reply