web-dev-qa-db-fra.com

Étiquettes dans l'assemblage en ligne GCC

Dans mon expérimentation en cours avec GCC inline Assembly, j'ai rencontré un nouveau problème concernant les étiquettes et le code intégré.

Considérez le saut simple suivant:

__asm__
(
    "jmp out;"
    "out:;"
    :
    :
);

Cela ne fait rien sauf passer à l'étiquette out. En l'état, ce code se compile très bien. Mais si vous le placez dans une fonction, puis compilez avec des drapeaux d'optimisation, le compilateur se plaint: "Erreur: le symbole 'out' est déjà défini".

Ce qui semble se produire, c'est que le compilateur répète ce code d'assembly chaque fois qu'il insère la fonction. Cela provoque la duplication de l'étiquette out, conduisant à plusieurs étiquettes out.

Alors, comment puis-je contourner cela? N'est-il vraiment pas possible d'utiliser des étiquettes dans un assemblage en ligne? Ce tutoriel sur GCC inline Assembly mentionne que:

Ainsi, vous pouvez placer votre assembly dans des macros CPP et des fonctions C en ligne, afin que tout le monde puisse l'utiliser en tant que fonction/macro C. Les fonctions en ligne ressemblent beaucoup aux macros, mais sont parfois plus propres à utiliser. Attention, dans tous ces cas, le code sera dupliqué, donc seules les étiquettes locales (de 1: style) doivent être définies dans ce code asm.

J'ai essayé de trouver plus d'informations sur ces "labels locaux", mais je n'arrive pas à trouver quoi que ce soit concernant l'assemblage en ligne. Il semble que le didacticiel indique qu'une étiquette locale est un nombre suivi de deux points (comme 1:), j'ai donc essayé d'utiliser une étiquette comme ça. Fait intéressant, le code a été compilé, mais au moment de l'exécution, il a simplement déclenché une erreur de segmentation. Hmm ...

Donc, des suggestions, des conseils, des réponses ...?

39
Channel72

Une déclaration d'une étiquette locale est en effet un nombre suivi d'un deux-points. Mais un référence à une étiquette locale a besoin d'un suffixe f ou b, selon que vous voulez regarder en avant ou en arrière - c'est-à-dire 1f fait référence à la prochaine 1: étiquette dans le sens avant.

Donc, déclarer l'étiquette comme 1: est correct; mais pour y faire référence, vous devez dire jmp 1f (parce que vous sautez en avant dans ce cas).

51
Matthew Slattery

Eh bien, cette question ne rajeunit pas, mais il existe deux autres solutions intéressantes.

1) Cet exemple utilise% =. % = dans un modèle d'assembleur est remplacé par un nombre qui est "unique à chaque insn dans la compilation entière. Ceci est utile pour créer des étiquettes locales auxquelles il est fait référence plusieurs fois dans une insn donnée". Notez que pour utiliser% =, vous (apparemment) devez avoir au moins une entrée (bien que vous n'ayez probablement pas à l'utiliser réellement).

int a = 3;
asm (
    "test %0\n\t"
    "jnz to_here%=\n\t"
    "jz to_there%=\n\t"
    "to_here%=:\n\t"
    "to_there%=:"
    ::"r" (a));

Cela produit:

test %eax
jnz to_here14
jz to_there14
to_here14:
to_there14:

Alternativement, vous pouvez utiliser le goto asm (ajouté dans la v4.5 je pense). Cela vous permet en fait de passer aux étiquettes c au lieu de simplement les étiquettes asm:

asm goto ("jmp %l0\n"
 : /* no output */
 : /* no input */
 : /* no clobber */
 : gofurther);

printf("Didn't jump\n");

// c label:
gofurther:
printf("Jumped\n");
30
David Wohlferd