I am moving a small academic OS from TriCore to ARM Cortex (Thumb-2 instruction set). In order for the scheduler to work, sometimes I need to directly connect JUMP to another function without changing the stack or register of links.
In TriCore (or rather tricore-g ++) this shell template (for any function with three arguments) works:
template< class A1, class A2, class A3 > inline void __attribute__((always_inline)) JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) { typedef void (* __attribute__((interrupt_handler)) Jump3)( A1, A2, A3); ( (Jump3)func )( a1, a2, a3 ); }
This will lead to the generation of the assembler command J (aka JUMP) instead of CALL , leaving the stack and CSA unchanged when switching to the (otherwise normal) C ++ function superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to)
Now I need equivalent behavior on ARM Cortex (or rather for arm-none-linux-gnueabi-g ++), i.e. generate command B (aka BRANCH) instead of BLX (aka BRANCH with reference and exchange). But the interrupt_handler attribute for arm-g ++ is missing, and I could not find the equivalent attribute.
So I tried resorting to asm volatile and writing asm code directly:
template< class A1, class A2, class A3 > inline void __attribute__((always_inline)) JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) { asm volatile ( "mov.w r0, %1;" "mov.w r1, %2;" "mov.w r2, %3;" "b %0;" : : "r"(func), "r"(a1), "r"(a2), "r"(a3) : "r0", "r1", "r2" ); }
So far, so good, in my theory, at least. Thumb-2 requires that function arguments be passed in this register, i.e. R0..r2, so it should work.
But then the linker dies with
undefined reference to `r6'
on the closing bracket of the asm operator ... and I don't know what to do with it. Ok, I'm not an expert in C ++, and the asm syntax is not very simple ... so did anyone get a hint for me? A hint for the correct __attribute__ for arm-g ++ would be in one case, a hint for fixing the asm code would be different. Another way would probably be to tell the compiler that a1..a3 should already be in the r0..r2 registers when the asm operator was introduced (I studied this a bit, but did not find any hint).