Ответ 1
Синтаксис Extended-asm требует записи %%
, чтобы получить одиночный %
в asm-выходе. например для x86:
asm("inc %eax") // bad: undeclared clobber
asm("inc %%eax" ::: "eax"); // safe but still useless :P
%r7
обрабатывает r7
как число операндов. Как отмечали комментаторы, просто опустите %
s, потому что они вам не нужны для ARM, даже с GNU as
.
К сожалению, похоже, не способ запросить входные операнды в определенных регистрах на ARM, как вы можете это сделать для x86. (например, ограничение "a"
означает eax
).
Вы можете использовать register int var asm ("r7")
, чтобы заставить var использовать определенный регистр, а затем использовать ограничение "r"
и предположить, что он будет в этом регистре. Я не уверен, что это всегда безопасно или хорошая идея, но, похоже, работает даже после inlining. @Jeremy комментирует, что этот метод был рекомендован командой GCC.
Я получил некоторый эффективный код, который позволяет избежать потери команды reg-reg move:
Посмотрите на сборщик компиляторов Godbolt:
__attribute__((noreturn)) static inline void ASM_EXIT(int status)
{
register int status_r0 asm ("r0") = status;
register int callno_r7 asm ("r7") = 1;
asm volatile("swi #0\n"
:
: "r" (status_r0), "r" (callno_r7)
);
}
#define GET_STATUS() (*(int*)(some_address)) //gets an integer from an address
void foo(void) { ASM_EXIT(12); }
push {r7} @ # gcc is still saving r7 before use, even though it sees the "noreturn" and doesn't generate a return
movs r0, #12 @ stat_r0,
movs r7, #1 @ callno,
swi #0
# yes, it literally ends here, after the inlined noreturn
void bar(int status) { ASM_EXIT(status); }
push {r7} @
movs r7, #1 @ callno,
swi #0 # doesn't touch r0: already there as bar() first arg.
Поскольку вы всегда хотите, чтобы значение читалось из памяти, вы можете использовать ограничение "m"
и включить ldr
в свой встроенный asm. Тогда вам не понадобится трюк register int var asm("r0")
, чтобы избежать потраченного впустую mov
для этого операнда.
Не всегда может понадобиться mov r7, #1
, поэтому я использовал синтаксис register asm()
для него. Если gcc хочет константу 1
в регистре где-то еще в функции, она может сделать это в r7
, так что она уже существует для ASM_EXIT.
В любой момент, когда первая или последняя инструкция оператора GNU C inline asm являются инструкциями mov
, вероятно, есть способ удалить их с лучшими ограничениями.