2010-10-10 18 views
33

En mi constante experimentación con el ensamblado en línea de GCC, me encontré con un nuevo problema relacionado con las etiquetas y el código en línea.Etiquetas en ensamblaje en línea de GCC

Considérese el siguiente salto simple:

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

Esto no hace nada excepto salto a la etiqueta out. Como es, este código compila bien. Pero si lo coloca dentro de una función y luego compila con indicadores de optimización, el compilador se queja: "Error: el símbolo 'out' ya está definido".

Lo que parece estar sucediendo es que el compilador repite este código de ensamblaje cada vez que indica la función. Esto hace que la etiqueta out se duplique, lo que genera varias etiquetas out.

Entonces, ¿cómo puedo solucionar esto? ¿Realmente no es posible usar etiquetas en el ensamblaje en línea? Este tutorial on GCC inline assembly menciona que:

Thus, you can make put your assembly into CPP macros, and inline C functions, so anyone can use it in as any C function/macro. Inline functions resemble macros very much, but are sometimes cleaner to use. Beware that in all those cases, code will be duplicated, so only local labels (of 1: style) should be defined in that asm code.

He intentado encontrar más información acerca de estas "etiquetas" locales, pero parece que no puede encontrar todo lo relacionado con el montaje inline. Parece que el tutorial dice que una etiqueta local es un número seguido de dos puntos (como 1:), así que traté de usar una etiqueta como esa. Curiosamente, el código compilado, pero en tiempo de ejecución simplemente desencadenó una falla de segmentación. Hmm ...

¿Alguna sugerencia, consejos, respuestas ...?

Respuesta

44

A declaración de una etiqueta local es de hecho un número seguido de dos puntos. Pero una referencia a una etiqueta local necesita un sufijo de f o b, según si desea mirar hacia adelante o hacia atrás, es decir, 1f se refiere a la siguiente etiqueta 1: en la dirección de avance.

Declarando que la etiqueta como 1: es correcta; pero para referenciarlo, necesita decir jmp 1f (porque está saltando hacia adelante en este caso).

+1

@MichaelGraczyk Las etiquetas locales no son una característica específica de x86. GAS los admite independientemente del formato de archivo de CPU o objeto, y lo mismo ocurre con casi todos los demás ensambladores de Unixy (como en, nunca he visto uno que no lo haya hecho, incluso en 1995). – zwol

+1

De hecho, y 'jmp 1' se consideraría un salto a la ubicación 1, por lo tanto, la segfault. – greggo

24

Bueno, esta pregunta no se está volviendo más joven, pero hay otras dos soluciones interesantes.

1) Este ejemplo usa% =. % = en una plantilla de ensamblador se reemplaza por un número que es "único para cada ins en toda la compilación. Esto es útil para hacer etiquetas locales a las que se hace referencia más de una vez en una entrada determinada". Tenga en cuenta que para usar% =, usted (al parecer) debe tener al menos una entrada (aunque probablemente no tenga que usarla realmente).

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

Este salidas:

test %eax 
jnz to_here14 
jz to_there14 
to_here14: 
to_there14: 

Alternativamente, se puede utilizar el Goto asm (Añadido en v4.5 creo). Esto realmente le permite saltar a las etiquetas c en lugar de a las etiquetas asm:

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

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

// c label: 
gofurther: 
printf("Jumped\n"); 
+4

Me encanta Stackoverflow para cosas como esta. – demonkoryu

Cuestiones relacionadas