11
votes

Appel de fonction direct C utilisant l'assemblage en ligne de GCC

Si vous souhaitez appeler une fonction C / C ++ à partir de l'assemblage en ligne, vous pouvez faire quelque chose comme ceci:

call callee


6 commentaires

Êtes-vous sûr que l'appel indirect détruit le pipeline? Avez-vous aspiré? Ma compréhension était que dans les vieux jours de X86 (avant I686), des appels indirects étaient très mauvais (je me souviens d'être un bon 10-100 fois plus lent sur ma K6), mais de nos jours, les processeurs sont plus intelligents et peuvent les traiter tout simplement bien. . Alors, certains tests avant de passer aux conclusions!


@R ..: Vous avez raison: si je comparais ceci sur un vrai processeur, cela ne fait aucune différence. Je gère mon code à Qemu, cependant, et il semble faire une différence là-bas (environ 20% de plus de cycles / appel).


Ensuite, je voudrais juste rester avec la façon dont vous le faites, avec l'appel indirect. Cela permettra à GCC de générer le code correct pour les bibliothèques / exécutables Pic / Pie sans avoir à insérer des hacks spéciaux pour gérer ces choses.


@R ..: oui ce serait probablement la meilleure idée. Bien que je n'ai pas à vous inquiéter de pic / pie (c'est le code du noyau), je suis donc toujours intéressé à trouver une bonne solution à ce problème.


Eh bien, si c'est le code du noyau, il suffit de coder l'appel et de mettre __ attribut __ ((utilisé)) sur la fonction afin que cela ne soit pas optimisé. Vous n'avez pas à vous soucier de la portabilité si vous avez une architecture unique OS et CPU. Au fait, utilisez-vous vraiment C ++ dans le code du noyau ??


@R ..: Oui C'est probablement la meilleure option bien que je n'aime pas avoir à coder de manière difficile le nom mutilé ... et oui, j'utilise vraiment C ++ :-) Ce n'est qu'un noyau de passe-temps, cependant.


4 Réponses :


0
votes

L'astuce est la concaténation littérale à chaîne. Avant que GCC ne commence à essayer d'obtenir une signification réelle de votre code, il concaténera des littéraux stricts adjacents, alors même si les cordes d'assemblage ne sont pas identiques que les autres chaînes que vous utilisez dans votre programme, elles devraient être concaténées si vous le faites:

#define ASM_CALL(X) asm("\t call  " #X "\n")

int main(void) {
   ASM_CALL(my_function);
   return 0;
}


2 commentaires

Non, cela ne fonctionne pas du tout. Premièrement, le «$» est totalement erroné pour appeler, second qu'il ne veut pas «my_function» dans la chaîne ASM, mais le nom Mangelé que C ++ génère .


Je n'ai pas vu que c'était aussi pour C ++. Dans ce cas, il est probable que cela ne fonctionnera pas si le nom de la fonction est surchargé sans beaucoup de cerceaux. Je viens de copier le "$" d'un autre poste depuis que je ne me suis pas souvenu de la main de la main X86 ASM. Fixer ça ...



11
votes

J'ai eu le Réponse du mailing de GCC Liste: xxx

maintenant, je dois juste savoir ce que % p0 signifie en réalité parce qu'il semble être une fonctionnalité non documentée ...

EDIT : Après avoir examiné le code source GCC, il n'est pas clairement clair que le code p devant un moyen de contrainte. Mais, entre autres choses, il empêche la GCC de mettre un $ devant des valeurs constantes. Ce dont j'ai besoin dans ce cas.


Pour que cela soit sûr, vous devez indiquer au compilateur à propos de tous les registres que l'appel de la fonction pourrait modifier, par exemple. : "EXA", "ECX", "EDX", "XMM0", "XMM1", ..., "st (0)" "," st (1) ", ... .

voir Calling Printf dans l'ASM en ligne étendu pour un exemple complet x86-64 de en toute sécurité appelle de fonction à partir d'Inline ASM.


5 commentaires

Voir aussi Stackoverflow.com/questions / 37639993 / ... pour Les dangers de l'utilisation de appelle de Inline ASM . Il est essentiellement impossible de faire de manière fiable pour X86-64 System V (Linux), car vous ne pouvez pas dire au compilateur que vous souhaitez clocer la zone rouge. C'est généralement une mauvaise idée. Voir Stackoverflow.com/Questions/ 7984209 / ... .


@Petercordes Cela semble être la question la plus susceptible de «Comment faire de l'appel de la fonction d'assemblée en ligne», je vous recommande de centraliser la réponse des pièges ici.


@Cirosantilli 疆疆 中心 996icu 六四 六四: Peut-être une modification de cette réponse pour inclure un avertissement de grosse graisse et des liens vers plus de détails serait approprié. Et d'inclure un "mémoire" clobber sauf si la fonction que vous appelez est connue de ne pas avoir d'effets secondaires visibles à cette fonction.


@Petercordes qui aiderait. Ma réponse préférée jusqu'à présent est la tentative de béton de Michael: Stackoverflow.com/Questtions/37502841/...


Et BTW, mise à jour: % p est documenté maintenant, pour imprimer des noms de symboles sans décoration. Ou d'imprimer foo @ plt si nécessaire / approprié. gcc.gnu.org/onlinedocs/gcc/... < / a>



0
votes

Si vous générez du code 32 bits (option E.G. -M32 GCC), l'ASM suivant en ligne émet un appel direct:

asm ("call %0" :: "m" (callee));


0 commentaires

2
votes

Peut-être que je manque quelque chose ici, mais xxx

devrait fonctionner correctement. Vous avez besoin d'externe "c" afin que le nom ne soit pas décoré en fonction des règles de mangling nommant C ++.


0 commentaires