programa ejecutar con compilar como c winapi gcc assembly mingw

ejecutar - gcc linux



¿Agregando guiones bajos principales a los símbolos de ensamblaje con GCC en Win32? (4)

¿Puedes declararlo dos veces?

.global bar .global _bar

No he escrito ensamblado por un tiempo, pero ¿el identificador .global simplemente actúa como una especie de etiqueta?

Tengo un fragmento de código C que llama a una función definida en el ensamblaje. A modo de ejemplo, supongamos que foo.c contiene:

int bar(int x); /* returns 2x */ int main(int argc, char *argv[]) { return bar(7); }

Y bar.s contiene la implementación de bar () en el conjunto x86:

.global bar bar: movl 4(%esp), %eax addl %eax, %eax ret

En Linux, puedo compilar y vincular fácilmente estas fuentes con GCC de la siguiente manera:

% gcc -o test foo.c bar.s % ./test; echo $? 14

En Windows con MinGW, esto falla con un error de "referencia indefinida a` bar ''". Resulta que la causa de esto es que en Windows todos los identificadores de funciones con convención de llamadas C tienen como prefijo un subrayado, pero dado que "barra" está definida en ensamblaje, no obtiene este prefijo y falla el enlace. (Entonces, el mensaje de error se está quejando realmente por perder el símbolo _bar, no la barra.)

Para resumir:

% gcc -c foo.c bar.s % nm foo.o bar.o foo.o: 00000000 b .bss 00000000 d .data 00000000 t .text U ___main U _bar 00000000 T _main bar.o: 00000000 b .bss 00000000 d .data 00000000 t .text 00000000 T bar

La pregunta ahora es: ¿cómo puedo resolver esto bien? Si estuviera escribiendo solo para Windows, podría agregar el guión bajo al identificador en bar.s, pero luego el código se rompe en Linux. He analizado las -fleading-underscore gcc''s -fleading-underscore y -fno-leading-underscore , pero ninguna parece hacer nada (al menos en Windows).

La única alternativa que veo ahora es pasar el archivo de ensamblaje a través del preprocesador de C y redefinir manualmente todos los símbolos declarados si se define WIN32, pero tampoco es muy bonito.

¿Alguien tiene una solución limpia para esto? Tal vez una opción de compilador que supervisé? ¿Tal vez el ensamblador de GNU admite una manera específica de que este símbolo particular se refiera a una función que usa la convención de llamadas C y debería ser mutilado como tal? ¿Alguna otra idea?


Los compiladores para el objetivo ELF no agregan caracteres de subrayado iniciales de manera predeterminada. Puede agregar -fleading-underscore al compilar en formato ELF (bajo Linux). Use un condicional en el archivo MAKE.

Referencia: http://opencores.org/openrisc,gnu_toolchain (hacer una búsqueda en la página de "dejar sin cambios los nombres globales")


Puede usar el preprocesador C para preprocesar su ensamblaje y usar una macro para agregar los guiones bajos que faltan en Windows. En primer lugar, debe cambiar el nombre de su archivo de ensamblaje de bar.s a bar.S (''S'' mayúscula). Esto le dice a gcc que use cpp para preprocesar el archivo.

Para agregar los guiones bajos que faltan, puede definir una macro "cdecl" como esta:

#if defined(__WIN32__) # define cdecl(s) _##s #else # define cdecl(s) s #endif

Entonces úsalo así:

.global cdecl(bar) cdecl(bar): movl 4(%esp), %eax addl %eax, %eax ret

Tenga en cuenta que Mac OSX también requiere subrayados iniciales, por lo que puede actualizar la primera línea de la macro de esta manera:

#if defined(__WIN32__) || defined(__APPLE__)


Una opción, aunque peligrosa, es convencer a GCC para que omita el guión bajo requerido por ABI.

  • -fleading-underscore

    Esta opción y su contraparte, -fno-leading-underscore , cambian forzosamente la forma en que se representan los símbolos C en el archivo de objeto. Un uso es ayudar a vincular con el código de ensamblaje heredado.

    Advertencia: el -fleading-underscore hace que GCC genere código que no es binario compatible con el código generado sin ese interruptor. Úselo para ajustarse a una interfaz binaria de aplicación no predeterminada. No todos los objetivos brindan soporte completo para este cambio.

Otra opción más segura es indicar explícitamente a GCC el nombre que se debe usar.

5.39 Control de nombres usados ​​en el código ensamblador

Puede especificar el nombre que se utilizará en el código ensamblador para una función o variable C escribiendo la palabra clave asm (o __asm__ ) después del declarador de la siguiente manera:

int foo asm ("myfoo") = 2;

Esto especifica que el nombre que se utilizará para la variable foo en el código del ensamblador debe ser `` myfoo '' rather than the usual /``_foo ''.

En los sistemas en los que normalmente se antepone un guion bajo al nombre de una función o variable C, esta característica le permite definir nombres para el enlazador que no comienzan con un guión bajo.

No tiene sentido utilizar esta característica con una variable local no estática ya que tales variables no tienen nombres de ensamblador. Si está tratando de poner la variable en un registro particular, vea Registros explícitos . Actualmente, GCC acepta dicho código con una advertencia, pero probablemente se modifique para emitir un error, en lugar de una advertencia, en el futuro.

No puede usar asm de esta manera en una definición de función; pero puede obtener el mismo efecto escribiendo una declaración para la función antes de su definición y poniendo asm allí, así:

extern func () asm ("FUNC"); func (x, y) int x, y; /* ... */

Depende de usted asegurarse de que los nombres de ensamblador que elija no entren en conflicto con ningún otro símbolo de ensamblador. Además, no debes usar un nombre de registro; eso produciría un código ensamblador completamente inválido. GCC aún no tiene la capacidad de almacenar variables estáticas en los registros. Quizás eso se agregará.

En tu caso,

extern int bar(int x) asm("bar");

debería decirle a GCC que " bar usa nombre asm` `bar` '', aunque es una función de llamada".