Ich portiere ein kleines akademisches Betriebssystem von TriCore auf ARM Cortex (Thumb-2 Befehlssatz). Damit der Scheduler funktioniert, muss ich manchmal direkt zu einer anderen Funktion springen, ohne den Stack oder das Link-Register zu verändern.
Auf TriCore (oder besser gesagt, auf tricore-g++) funktioniert diese Wrapper-Vorlage (für jede Drei-Argument-Funktion):
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 );
}
//example for using the template:
JUMP3( superDispatch, this, me, next );
Dies würde den Assembler-Befehl erzeugen J
(auch bekannt als JUMP) anstelle von CALL
, wobei der Stack und die CSAs beim Sprung zur (ansonsten normalen) C++-Funktion unverändert bleiben superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to)
.
Jetzt brauche ich ein gleichwertiges Verhalten auf ARM Cortex (oder besser gesagt, für arm-none-linux-gnueabi-g++), d.h. eine B
(auch bekannt als BRANCH-Befehl) anstelle von BLX
(a.k.a. BRANCH mit Link und Austausch). Aber es gibt keine interrupt_handler
Attribut für arm-g++ und ich konnte kein gleichwertiges Attribut finden.
Also habe ich versucht, auf asm volatile
und den asm-Code direkt zu schreiben:
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 weit, so gut, zumindest in meiner Theorie. Thumb-2 verlangt, dass Funktionsargumente in den Registern übergeben werden, d.h. r0..r2 in diesem Fall, also sollte es funktionieren.
Aber dann stirbt der Linker mit
undefined reference to `r6'
auf der schließenden Klammer der asm-Anweisung ... und ich weiß nicht, was ich davon halten soll. OK, ich bin kein Experte in C++, und die asm-Syntax ist nicht sehr einfach... hat also jemand einen Tipp für mich? Ein Hinweis auf die richtige __attribute__
für arm-g++ wäre eine Möglichkeit, ein Hinweis auf die Korrektur des asm-Codes eine andere. Ein anderer Weg wäre vielleicht, dem Compiler zu sagen, dass a1..a3
sollte sich bereits in den Registern befinden r0..r2
wenn die asm-Anweisung eingegeben wird (ich habe das ein wenig untersucht, aber keinen Hinweis gefunden).