Etichette in assemblaggio in linea GCC

Nella mia continua sperimentazione con l’assemblaggio in linea di GCC, ho riscontrato un nuovo problema relativo alle etichette e al codice inline.

Considera il seguente semplice salto:

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

Questo non fa nulla se non saltare all’etichetta. Così com’è, questo codice si compila bene. Ma se lo si inserisce in una funzione e poi si compila con i flag di ottimizzazione, il compilatore si lamenta: “Errore: il simbolo ‘out’ è già definito”.

Ciò che sembra accadere è che il compilatore sta ripetendo questo codice assembly ogni volta che incorpora la funzione. Questo fa sì che l’etichetta venga duplicata, portando a più etichette.

Quindi, come posso aggirare questo? Non è davvero ansible utilizzare le etichette nel assembly in linea? Questo tutorial sull’assemblaggio in linea di GCC afferma che:

Pertanto, è ansible inserire il proprio assieme in macro CPP e funzioni C inline, in modo che chiunque possa utilizzarlo come qualsiasi funzione / macro C. Le funzioni in linea assomigliano molto ai macro, ma a volte sono più pulite da usare. Attenzione, in tutti questi casi, il codice verrà duplicato, quindi solo le etichette locali (di 1: stile) dovrebbero essere definite in quel codice asm.

Ho cercato di trovare maggiori informazioni su queste “etichette locali”, ma non riesco a trovare nulla che riguardi l’assemblaggio in linea. Sembra che il tutorial stia dicendo che un’etichetta locale è un numero seguito da due punti (come 1: :), quindi ho provato a usare un’etichetta del genere. È interessante notare che il codice è stato compilato, ma in fase di esecuzione ha semplicemente triggersto un errore di segmentazione. Hmm …

Quindi suggerimenti, suggerimenti, risposte …?

Una dichiarazione di un’etichetta locale è in effetti un numero seguito da due punti. Ma un riferimento a un’etichetta locale ha bisogno di un suffisso di f o b , a seconda se si desidera guardare avanti o indietro – cioè 1f riferisce al prossimo 1: etichetta nella direzione avanti.

Quindi dichiarare l’etichetta come 1: è corretta; ma per fare riferimento, devi dire jmp 1f (perché in questo caso stai saltando in avanti).

Bene, questa domanda non sta diventando più giovane, ma ci sono altre due soluzioni interessanti.

1) Questo esempio utilizza% =. % = in un modello di assemblatore viene sostituito con un numero che è “univoco per ogni insn nell’intera compilazione. Ciò è utile per creare etichette locali a cui si fa riferimento più volte in un dato insn”. Nota che per usare% =, tu (apparentemente) devi avere almeno un input (anche se probabilmente non devi effettivamente usarlo).

 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)); 

Questo produce:

 test %eax jnz to_here14 jz to_there14 to_here14: to_there14: 

In alternativa, puoi usare asm goto (aggiunto in v4.5 credo). Questo in realtà ti consente di passare alle etichette c anziché solo alle etichette asm:

 asm goto ("jmp %l0\n" : /* no output */ : /* no input */ : /* no clobber */ : gofurther); printf("Didn't jump\n"); // c label: gofurther: printf("Jumped\n");