Доступ к статической переменной C++ из встроенного asm gcc
По какой-то причине я хочу смешать немного ассемблера с C++ (не C).
Чтобы код можно было скомпилировать с помощью стандартной среды разработки Arduino, я не хочу использовать исходный код прямой сборки.
Я также не хочу использовать файл-оболочку C.
Моя проблема заключается в следующем:
У меня есть класс с одним экземпляром (реализующим какой-то драйвер), который выглядит так:
class cDriver {
public:
char ISR_param;
// ...
};
cDriver Driver;
Если я хочу получить доступ к ISR_param
этого единственного экземпляра из ISR, я могу сделать что-то вроде:
ISR (TIMER2_COMPA_Vect) {
do_something_with (Driver.ISR_param);
}
Это работает как шарм: адрес Driver.ISR_param
становится константой, компилятор просто генерирует инструкцию lds r24, &Driver.ISR_param
для загрузки правильный байт в качестве параметра для do_something_with
.
Теперь, когда я пытаюсь воспроизвести тот же механизм с помощью встроенного ассемблера, все становится намного сложнее.
Адрес Driver.ISR_param
известен компилятору C++ только как искаженная метка, и я не могу найти способ передать его встроенному ассемблеру для создания эквивалентного lds r24, <&Driver.ISR_param>
.
пытается переименовать переменную
Переименование переменных для сборки примерно так:
char global_var asm("my_var");
и попытка использовать его вот так:
asm ("lds r24, my_var\n");
будет компилироваться, но выдаст ошибку компоновщика (my_var
не определено).
Глядя на таблицу символов объектов, единственная метка для global_var
— это искаженное имя, подобное C++.
Как бы я ни старался использовать этот трюк с переименованием, мне не удалось заставить компилятор сгенерировать метку my_var
.
пытается использовать ограничения asm
Ограничение типа
asm (lds r24, %0\n" : : "I"(&global_var));
просто не скомпилируется. Я просмотрел возможные типы параметров и не смог найти способ сообщить ассемблеру об этом чертовом адресе.
ужасно неудобный обходной путь
Единственный найденный мной способ заставить компилятор генерировать эту ужасную инструкцию lds r24,...
— это выполнить реальный вызов функции.
Итак, вы можете сделать что-то вроде:
__attribute__((always_inline)) give_me_my_friggin_variable(char data)
{
asm volatile ("cmp %0,%0\n"::"r"(data));
}
ISR (TIMER2_COMPA_Vect, ISR_NAKED) {
<some prologue to save SREG and all needed registers>
//...
give_me_my_friggin_variable(Driver.ISR_param);
// продолжить ассемблерный код с правильно инициализированным r24
}
Это создаст:
lds r24, <the proper address> // добавлено компилятором...
cmp r24,r24 // ...из-за ограничения регистра здесь
Ну, это работает, но за счет создания совершенно бесполезной инструкции.
Итак, мой вопрос...
Есть ли более простой способ сообщить ассемблеру адреса статических переменных C++?
@kuroi neko, 👍7
1 ответ
Лучший ответ:
Попробуйте это:
asm volatile("lds r24, %0" : : "i" (&Driver.ISR_param));
Ограничение "i"
означает, что вы указываете целочисленную константу. Может быть
любое целое число, в отличие от ограничения "I"
в верхнем регистре, которое ограничено
6-битные положительные целые числа.
Дополнение:
Ограничения, поддерживаемые gcc, перечислены в документации gcc,
раздел Ограничения для операндов asm
:
- Ограничение
"i"
указано в подразделе "Простые ограничения". и описывается как:
Допускается непосредственный целочисленный операнд (один с постоянным значением). Сюда входят символические константы, значения которых будут известны только в время сборки или позже.
- Ограничение
"I"
находится в подразделе "Ограничения компьютера" и, для архитектуры AVR определяется как
Константа больше -1, меньше 64.
- Работает ли конструкция int array[100] = {0} на Arduino?
- C++ против языка Arduino?
- ошибка: ожидаемое первичное выражение перед токеном ','
- Ввести идентификатор чипа ESP32 в строковую переменную (новичок в Arduino/C++)
- Передача функции-члена класса в качестве аргумента
- Улучшенное циклическое переключение цветов RGB.
- Какие есть другие IDE для Arduino?
- GCC msg "note: in definition of macro 'max'" сообщение об ошибке
Черт... И спасибо :). Этот тип «i» не был указан в онлайн-руководствах, которые я нашел. Для полноты, не могли бы вы добавить ссылку на актуальную документацию? Кстати. Интересно, почему так трудно найти пример такого очевидного использования встроенного ассемблера., @kuroi neko
@kuroineko: ограничение
"i"
действительно отсутствует в [Поваренной книге встроенного ассемблера] avr-libc (http://www.nongnu.org/avr-libc/user-manual/inline_asm.html). Я добавил ссылку на документацию gcc, в которой он указан., @Edgar BonetБольшое спасибо. Думаю, такая кулинария довольно конфиденциальна :)., @kuroi neko
Ограничение
"i"
**не означает "целое число"**."i"
задает непосредственный операнд, который представляет собой объединение"n"
(целочисленный операнд, известный во время компиляции) и символического операнда"s", известный во время компоновки. Например, адреса переменных в статическом хранилище известны во время компоновки, поэтому для них будет работать
"i"`., @emacs drives me nuts