Extended-asm syntax nécessite d'écrire %%
pour obtenir un seul %
dans la sortie asm. par exemple. pour x86:
asm("inc %eax") // bad: undeclared clobber
asm("inc %%eax" ::: "eax"); // safe but still useless :P
%r7
est de traiter r7
comme numéro d'opérande. Comme les commentateurs l'ont souligné, il suffit d'omettre les %
, car vous n'en avez pas besoin pour ARM, même avec GNU as
.
Malheureusement, il doesn't seem to be a way to request input operands in specific registers on ARM, la façon dont vous pouvez pour x86. (par exemple "a"
signifie contrainte eax
spécifiquement).
Vous pouvez utiliser register int var asm ("r7")
pour forcer un var à utiliser un registre spécifique, puis utiliser une contrainte "r"
et supposer qu'il sera dans ce registre. Je ne suis pas sûr que ce soit toujours sûr, ou une bonne idée, mais il semble fonctionner même après l'inline. @Jeremy commente que cette technique a été recommandée par l'équipe du GCC.
J'ai obtenu un code efficace généré, ce qui évite de perdre une instruction sur un mouvement reg-reg:
See it on the Godbolt Compiler Explorer:
__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()'s first arg.
Puisque vous voulez toujours la valeur lue de la mémoire, vous pouvez utiliser une contrainte "m"
et inclure un ldr
dans votre asm inline. Ensuite, vous n'avez pas besoin de l'astuce register int var asm("r0")
pour éviter un mov
perdu pour cet opérande. Le mov r7, #1
peut ne pas toujours être nécessaire non plus, c'est pourquoi j'ai aussi utilisé la syntaxe register asm()
pour cela.Si gcc veut une constante 1
dans un registre ailleurs dans une fonction, il peut le faire en r7
alors c'est déjà là pour l'ASM_EXIT.
Chaque fois que la première ou les dernières instructions d'une déclaration en ligne asm GNU C sont mov
instructions, il y a probablement un moyen de les éliminer avec de meilleures contraintes.
Est-ce que 'GET_STATUS' a vraiment un' // 'dessus ou l'avez-vous ajouté pour clarifier la question? Que se passe-t-il si vous le supprimez? Aussi, que diriez-vous d'essayer ASM_EXIT (1)? Enfin, il pourrait être instructif d'essayer de compiler ceci avec '-E'. –
'% r7' - bien, vous n'avez pas 8 opérandes à l'extension ASM, n'est-ce pas? Dans le cas de l'asm simple (où le compilateur n'essaye pas d'analyser le contenu), il arrive que l'assembleur ignore apparemment la fausse syntaxe et assemble ce que vous pensez. – Notlikethat
Pour GCC ARM asm, vous n'avez pas besoin du préfixe% pour enregistrer les noms. – Jeremy