Вызовите адрес функции const, переданной встроенному ассемблеру gcc (avr-gcc)

Я пишу RPC-библиотеку для AVR, и мне нужно передать адрес функции некоторому встроенному коду ассемблера и вызвать функцию из кода ассемблера. Однако ассемблер жалуется, когда я пытаюсь вызвать функцию напрямую.

Этот минимальный пример test.cpp иллюстрирует проблему (в данном случае я передаю аргументы, а функция является экземпляром статического члена шаблонного класса):

void bar () {
return;
}

void foo() {
asm volatile (
"call %0" "\n":
: "p" (bar)
);
}

Компилирование с avr-gcc -S test.cpp -o test.S -mmcu=atmega328p работает нормально, но когда я пытаюсь собрать с avr-gcc -c test.S -o test.o -mmcu=atmega328p avr-as жалуется:

test.c: Assembler messages:
test.c:38: Error: garbage at end of line

Я понятия не имею, почему он пишет «test.c», файл, на который он ссылается, это test.S, который содержит это в строке 38:

call gs(_Z3barv)

Я перепробовал все даже отдаленно разумные ограничения на параметр для встроенного ассемблера, которые я мог найти Вот но никто из тех, кого я пробовал, не работал.

Я представляю, если часть gs () была удалена, все должно работать, но все ограничения, кажется, добавляют ее. Я понятия не имею, что он делает.

Странно то, что выполнение косвенного вызова, подобного этому, прекрасно собирается:

void bar () {
return;
}

void foo() {
asm volatile (
"ldi r30, lo8(%0)" "\n""ldi r31, hi8(%0)" "\n""icall" "\n":
: "p" (bar)
);
}

Произведенный ассемблер выглядит так:

ldi r30, lo8(gs(_Z3barv))
ldi r31, hi8(gs(_Z3barv))
icall

И avr-as не жалуется на мусор.

1

Решение

Обратите внимание, что call ожидает постоянного значения, известного во время сборки. "p" ограничение не включает эту семантику; это также позволило бы указатель от переменной (например, char* x), который call не выдерживаю. (Кажется, я помню, что иногда gcc достаточно умен, чтобы оптимизировать таким образом, чтобы «p» работал здесь — но это в основном недокументированное и недетерминированное поведение, поэтому лучше не рассчитывать на него.)

Если функция, которую вы вызываете, на самом деле является постоянной времени компиляции, вы можете использовать "i" (bar), Если это не так, то у вас нет другого выбора, кроме как использовать icall как вы уже поняли.

Кстати, раздел AVR https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints документирует еще некоторые, специфичные для AVR ограничения.

1

Другие решения

Я пробовал различные способы передачи имени функции C во встроенный код ASM без успеха. Однако я нашел обходной путь, который кажется обеспечить желаемый результат.


Ответ на вопрос:

Как объяснено на https://www.nongnu.org/avr-libc/user-manual/inline_asm.html Вы можете назначить имя ASM функции C в объявлении прототипа:

void bar (void) asm ("ASM_BAR");    // any name possible here
void bar (void)
{
return;
}

Затем вы можете легко вызвать функцию из своего кода ASM:

asm volatile("call ASM_BAR");

Используйте с библиотечными функциями:

Этот подход не работает с библиотечными функциями, потому что они имеют свои собственные объявления прототипов. Чтобы вызвать функцию как system_tick() из time.h библиотека более эффективно из ISR, вы можете объявить вспомогательную функцию. К сожалению, GCC не применяет встроенную настройку к вызовам из кода ASM.

inline void asm_system_tick(void) asm ("ASM_SYSTEM_TICK") __attribute__((always_inline));
void asm_system_tick(void)
{
system_tick();
}

В следующем примере GCC генерирует только инструкции push / pop для окружающего кода, но не для вызова функции! Обратите внимание, что system_tick() специально разработан для ISR_NAKED и выполняет все необходимые операции стека самостоятельно.

volatile uint8_t tick = 0;
ISR(TIMER2_OVF_vect)
{
tick++;
if (tick > 127)
{
tick = 0;
asm volatile ("call ASM_SYSTEM_TICK");
}
}

Поскольку встроенный атрибут не работает, каждый вызов функции занимает 8 дополнительных циклов процессора. По сравнению с 5632 циклами ЦП, необходимыми для операций push / pull с обычным вызовом функции (44 цикла ЦП для каждого запуска ISR), это все еще очень впечатляющее улучшение.

0