Я портирую небольшую академическую ОС с TriCore на ARM Cortex (набор инструкций Thumb-2). Чтобы планировщик работал, мне иногда нужно перейти непосредственно к другой функции, не изменяя ни стек, ни регистр ссылок.
В TriCore (или, скорее, в tricore-g ++) этот шаблон оболочки (для любой функции с тремя аргументами) работает:
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 );
Это сгенерирует инструкцию на ассемблере J
(a.k.a. JUMP) вместо CALL
, оставляя стек и CSA неизменными при переходе к (в остальном нормальному) функции C ++ superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to)
.
Теперь мне нужно эквивалентное поведение в ARM Cortex (или, скорее, для arm-none-linux-gnueabi-g ++), т.е. генерировать инструкцию B
(он же BRANCH) вместо BLX
(он же BRANCH со ссылкой и обмен). Но для arm-g ++ нет атрибута interrupt_handler
, и я не смог найти эквивалентного атрибута.
Итак, я попытался прибегнуть к asm volatile
и написать код asm напрямую:
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"
);
}
Пока все хорошо, по крайней мере, в моей теории. Thumb-2 требует, чтобы аргументы функции передавались в регистры, т.е. в этом случае r0..r2, поэтому он должен работать.
Но тогда компоновщик умрет с
undefined reference to `r6'
на закрывающей скобке оператора asm ... и я не знаю, что с этим делать. Хорошо, я не эксперт в C ++, и синтаксис asm не очень прост ... так у кого-нибудь есть подсказка для меня? Подсказка к правильному __attribute__
для arm-g ++ будет одним из способов, подсказка для исправления кода asm будет другим. Другой способ, возможно, заключался бы в сообщении компилятору, что a1..a3
уже должен быть в регистрах r0..r2
при вводе оператора asm (я немного разбирался в этом, но не нашел ни одной подсказки).