[[ I hope this is the right forum for this post, apologies if not ]]
I'm writing a function which I want to execute from RAM rather than flash. Provided the function is written in C all is well, but if it's written in assembler the linker seems to insert a bad veneer which uses ARM32 instructions (which aren't available on the RP2040) rather than the Thumb instructions used for the C version. As a result the code crashes.
Do I need to do something else to tell the linker that the veneer must use Thumb instructions, or is this a linker bug?
My minimal example code is split into three files:
I don't think that post is related, or if it is, I've missed the point!
It definitely is possible to execute code from RAM on the RP2040. For C code you do it by declaring the function __no_inline_not_in_flash_func (and it makes quite a bit of difference under some circumstances). It's also possible to do it with assembler code, but the linker makes this harder than it ought to be.
I don't know whether it's possible on the ATmega, as discussed in that thread.
I suggest you move the question to the RPi Pico forums, where there is significantly deeper knowledge of such obscure functionality.
Here are some suggestions for further debugging, even if they're just grasping at straws:
What happens if you use the Philhower core instead of the Arduino core? It's a bit (a lot) closer to "raw sdk." Perhaps the mbed core is missing a linker switch needed to identify the cpu type.
Same question, using the RPi SDK and build process, directly.
I don't understand why a "veneer" is needed in the first place. gcc wil happily generate "mov reg, #target; blx reg" sequences to permit calls to anywhere in the address space, were it not specifically turned off to save space and registers (-mshort-calls, I think,) There's a function attribute to force this: __attribute__((long_call)) - I wonder why the __no_inline... macro doesn't seem to use it?
(man, sometimes the m0 instruction set looks particularly sucky!)
Heh, __attribute__((long_call)) sounded really promising, but the linker's foiled things again by setting the LSB to zero in the address, so the blx tries to switch to ARM32 mode!
Well, I got the veneer case to work by adding some additional directives to jane.S
(I used -S to see what the assembly functions produced by emma.cpp looked like, and pretty much copied all of them to jane.S)
.thumb
.section .time_critical.jane
.global jane
.thumb_func
.syntax unified
.align 1
.arch armv6 - m
.code 16
.type jane, % function
.cfi_startproc
jane:
bx lr
.cfi_endproc
I have no idea how much of that should be necessary.
EDIT: It looks like those changes cause the long_call version to produce correct code as well:
I also noticed that the compile command for the .S file did not include any of -march=armv6-m -mcpu=cortex-m0plus -mthumb, but adding them did not seem to change anything.