Как передать адрес функции в инструкции ассемблера с операндами выражения C

#c #assembly #arm #inline-assembly #cortex-m

Вопрос:

С помощью gcc/clang для коры головного мозга ARM M можно ли передать адрес функции в качестве константы в инструкциях ассемблера с операндами выражения C ? Точнее, я хотел бы загрузить R12 с адресом функции (сохраненным в памяти): ldr R12, =func в функции C, например, такой пример

 // __attribute__((naked)) 
int loader(int fn)
{
__asm ("ldr R12, =%0"::??? (fn):"r12");
// ... then  SVC #0, and the R0 is the return value 
}
 

Вопрос в том, что именно я должен указать для входного операнда?

ПРАВКА: Спасибо за комментарии! На самом деле мне нужно повторно реализовать KEIL __svc_indirect(0) , который загружает R12 с адресом функции и передает до четырех аргументов в R0..R3 (см. __svc_косвенный

Комментарии:

1. Есть ли какая-то причина, по которой вы просто не запрашиваете адрес функции в реестре в первую очередь? Например (void*)fn , указать свой int указатель или просто запросить int в регистре, например "r"(fn) . Вы можете использовать register int fn asm("r12") , чтобы ограничение «r» выбрало r12. Как вы хотите, чтобы ваш код компилировался? Как будто вы хотите, чтобы это встроилось в какой-то вызывающий объект, так int fn что это может быть константа времени связи, которую компилятор может встроить в инструкцию с помощью имени символа? Но голые функции не могут встроиться.

2. Обратите внимание, что naked функции не могут безопасно использовать расширенный Asm, только базовый (без ограничений/операндов). И их нужно вернуть вручную (например, закончить bx lr ) gcc.gnu.org/onlinedocs/gcc/…

3. не стервозная функция, возвращающая int значение, должна что-то внести в r0 реестр…

4. @peter-cordes, мне нужно повторно реализовать __svc_косвенный(0) КЕЙЛА, который загружает R12 с адресом функции и передает до четырех аргументов в R0..R3

5. Хорошо, тогда вы должны использовать "r" ограничение, чтобы GCC сделал ldr это за вас (с register ... asm("r12") переменной). И не создавайте naked функцию; это в основном эквивалентно использованию отдельного .s файла, за исключением искажения имени.

Ответ №1:

Используйте i ограничение и вручную добавьте = символ:

 __asm ("ldr r12, =%0" :: "i"(fn) : "r12");
 

Обратите внимание, что инструкция встроенной сборки по-прежнему неверна по другим причинам, некоторые из которых были указаны в комментариях к вашему вопросу. Также рассмотрите возможность использования переменной с ограничением по регистру для такого рода вещей:

 register int fn asm("r12");
__asm ("" :: "r"(fn));