1
votes

With gcc/clang for ARM cortex M, is there a way to pass a function address as a constant in Assembler Instructions with C Expression Operands ? More precisely I'd like to load R12 with function address (stored in the memory): ldr R12, =func within a C function, foe example like this one

// __attribute__((naked)) 
int loader(int fn)
{
__asm ("ldr R12, =%0"::??? (fn):"r12");
// ... then  SVC #0, and the R0 is the return value 
}

The question is what exactly I have to put for the Input Operand?

EDIT: Thanks for the comments! Actually I need to re-implement the KEIL's __svc_indirect(0) which loads R12 with function address and passes up to four arguments in R0..R3 (see __svc_indirect

1
Is there some reason you don't just ask for the function address in a register in the first place? Like (void*)fn to case your int to a pointer, or just ask for the int in a register, like "r"(fn). You can use register int fn asm("r12") to make the "r" constraint pick r12. How do you want your code to compile? Like you want this to inline into some caller so int fn can be a link-time constant that the compiler can embed into an instruction via a symbol name? But naked functions can't inline.Peter Cordes
Note that naked functions can't safely use Extended Asm, only Basic (no constraints/operands). And they need to manually return (e.g. end with bx lr) gcc.gnu.org/onlinedocs/gcc/…Peter Cordes
non-bitchy function returning int value, should place something into r0 register...user3124812
@peter-cordes, I need to re-implement the KEIL's __svc_indirect(0) which loads R12 with function address and passes up to four arguments in R0..R3IvanDi
Ok, then you should use an "r" constraint to have GCC do the ldr for you (with a register ... asm("r12") variable). And don't make a naked function; that's basically equivalent to using a separate .s file, except for name mangling.Peter Cordes

1 Answers

3
votes

Use an i constraint and manually prepend the = character:

__asm ("ldr r12, =%0" :: "i"(fn) : "r12");

Note that the inline assembly statement is still incorrect for other reasons, some of which were outlined in the comments on your question. Also consider using a register-constrainted variable for this sort of thing:

register int fn asm("r12");
__asm ("" :: "r"(fn));