Непосредственно Переход к другой функции C++

Я портирую маленькую академическую ОС от TriCore до Коры ARM (Ползунок 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 (иначе. ПЕРЕХОД) вместо CALL, отъезд стека и CSAs неизменный при переходе к (в других отношениях нормальной) функции C++ superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to).

Теперь я нуждаюсь в эквивалентном поведении на Коре ARM (или, скорее для arm-none-linux-gnueabi-g ++), т.е. генерирую a B (иначе. ОТВЕТВЛЕНИЕ) инструкция вместо BLX (иначе. ОТВЕТВЛЕНИЕ со ссылкой и обмен). Но существует нет interrupt_handler атрибут для руки-g ++ и я не мог найти эквивалентный атрибут.

Таким образом, я пытался обратиться к 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"
                  );
}

Пока неплохо, в моей теории, по крайней мере. Ползунок 2 требует, чтобы аргументы функции были переданы в регистрах, т.е. r0.. r2 в этом случае, таким образом, это должно работать.

Но затем компоновщик умирает с

undefined reference to `r6'

на закрывающей скобке asm оператора... и я не знаю, что сделать из него. Хорошо, я не эксперт в C++, и asm синтаксис не очень прост..., таким образом, кто-либо получил подсказку для меня? Подсказка к корректному __attribute__ для руки-g ++ был бы один путь, подсказка для фиксации кода asm будет другим. Иначе, возможно, должен был бы сказать компилятор это a1..a3 должен уже быть в регистрах r0..r2 когда asm оператор вводится (я изучил это немного, но не нашел подсказки).

6
задан starblue 30 March 2010 в 11:22
поделиться

2 ответа

Ну, теперь я понял, что пошло не так.

Вся концепция перехода непосредственно к другой функции на ARM Cortex является спорной, потому что TriCore использует Context Save Area (CSA) для сохранения всего контекста процессора каждый раз, когда вы вызываете другую функцию. Думайте об этом как о втором, независимом стеке, который увеличивается с каждым CALL и уменьшается с каждым RET. И каждый блок CSA имеет постоянный размер.

ARM Cortex, с другой стороны, использует простой стандартный стек (хорошо, он знает о системном стеке и стеке потоков, но это здесь неважно) - и GCC просто сохраняет то, что ему нужно для каждой функции, поэтому каждый фрейм имеет разный размер. Поэтому о простом переходе к другой функции не может быть и речи, потому что стек будет поврежден, как только перешедшая функция начнет сохранять энергонезависимые регистры, которые она использует.

А насчет ошибки компоновщика с неопределенной ссылкой на r6... ну, мне следовало внимательнее читать документацию по набору инструкций. B - это безусловное ответвление на непосредственный адрес, BX - это инструкция, которая ожидает адрес ответвления в регистре. Я был одурачен списком инструкций в руководстве, где BX был коротко описан как "Branch with exchange". Я не хотел ничего обменивать, мне нужен был простой переход, поэтому я не стал читать дальше.

Итак, после замены B на BX в коде asm volatile, код скомпилировался. Но, как было указано выше, вся концепция не может работать так, как ожидалось. Возможно, кто-то еще сможет найти применение этому коду, мне же сейчас приходится прибегать к классическому вызову функций...

0
ответ дан 17 December 2019 в 22:11
поделиться

Ошибка ссылки вызвана попыткой использовать инструкция перехода для перехода к указателю. Это генерирует код типа b r6 , который не может установить связь, потому что r6 не является символом. Измените инструкцию перехода на mov pc,% 0 , и вы должны получить правильный переход.

Как я упоминал в комментариях, обработчики прерываний ARM объявляются с атрибутом interrupt , но, как вы обнаружили, это не влияет на то, как они вызываются. Я предполагаю, что это был специфический для платформы трюк, который оказался правильным на TriCore.

Вы можете попробовать объявить переменные в определенных регистрах, используя расширенный синтаксис GCC, register int reg0 asm ("r0") = a1; , а не инструкции volatile mov . Это может позволить компилятору сгенерировать лучший код.

1
ответ дан 17 December 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: