assembly x86 nasm gas

assembly - NASM Vs GAS(diferencias prácticas)



x86 (2)

No estoy tratando de provocar una guerra entre Intel y AT & T (punto discutible de todos modos, ahora que ambos admiten la sintaxis de Intel) o preguntar cuál es "mejor" en sí, solo quiero saber las diferencias prácticas en la elección de uno u otro .

Básicamente, cuando recogí algunos ensambles básicos de x86 hace unos años, utilicé NASM sin otra razón que no fuera el libro que estaba leyendo, lo cual me puso firme pero involuntariamente en el campamento de NASM. Desde entonces, he tenido muy pocas causas para usar el ensamblaje, por lo que no he tenido la oportunidad de probar GAS.

Teniendo en cuenta que ambos admiten la sintaxis Intel (que personalmente prefiero) y, al menos teóricamente, deberían producir el mismo binario (sé que probablemente no lo harán, pero el significado no debería cambiar), ¿cuáles son las razones para favorecerse? ¿uno o el otro?

¿Es opciones de línea de comando? Macros? ¿Palabras clave no nemotécnicas? ¿O algo mas?

Gracias :)


NASM en realidad usa su propia variación de sintaxis Intel, diferente de la sintaxis MASM utilizada en la documentación oficial de Intel. Los nombres de código de operación y los pedidos de operandos son los mismos que en Intel, por lo que las instrucciones parecen iguales a primera vista, pero cualquier programa significativo tendrá diferencias. Por ejemplo, con MASM, la instrucción utilizada por MOV ax, foo depende del tipo de foo , mientras que NASM no tiene tipos y esto siempre se ensambla en una instrucción de movimiento inmediato. Cuando el tamaño de un operando no puede determinarse implícitamente, MASM requiere que se use algo como DWORD PTR donde NASM usa DWORD para significar lo mismo. La mayor parte de la sintaxis más allá de la mnemónica de instrucciones y el orden y el formato de operandos básicos es diferente.

En términos de funcionalidad, NASM y GAS son prácticamente lo mismo. Ambos tienen instalaciones macro de ensamblador, aunque NASM es más extenso y más maduro. Muchos archivos de código fuente GAS usan el preprocesador C en lugar del soporte macro propio de GAS.

La mayor diferencia entre los dos ensambladores es su compatibilidad con el código de 16 bits. GAS no tiene soporte para definir segmentos x86. Con GAS, está limitado a la creación de imágenes binarias simples de un solo segmento de 16 bits, básicamente solo sectores de arranque y archivos .COM. NASM tiene soporte completo para segmentos y admite archivos de objetos de formato OMF que puede usar con un enlazador adecuado para crear ejecutables segmentados de 16 bits.

Además del formato de archivo de objeto OMF, NASM es compatible con varios formatos que no tiene GAS. Normalmente, GAS solo admite el formato nativo de la máquina en la que se ejecuta, básicamente ELF, PE-COFF o MACH-O. Si desea admitir un formato diferente, debe compilar una versión de GAS "compilación cruzada" para ese formato.

Otra diferencia notable es que GAS tiene soporte para crear DWARF y la información de desenrollado de Windows de 64 bits (la última requerida por el ABI de Windows x64) mientras que con NASM ha creado crear las secciones y completar los datos usted mismo.


Sintaxis Intel : mov eax, 1 (destino de la instrucción, fuente)

Sintaxis de AT & T : movl $ 1,% eax (fuente de la instrucción, destino)

La sintaxis de Intel es bastante auto explicativa. En el ejemplo anterior, la cantidad de datos que se mueve se deduce del tamaño del registro (32 bits en el caso de eax). El modo de direccionamiento utilizado se deduce de los operandos mismos.

Hay algunos caprichos cuando se trata de la sintaxis de AT & T. En primer lugar, observe el sufijo l al final de la instrucción mov , esto significa long y significa 32 bits de datos. Otros sufijos de instrucción incluyen w para una palabra (16 bits, que no debe confundirse con el tamaño de la palabra de la CPU), q para una palabra cuádruple (64 bits) y b para un solo byte. Aunque no siempre se requiere, normalmente verá un código ensamblador que usa la sintaxis de AT & T que indica explícitamente la cantidad de datos que operan en la instrucción.

Se requiere más claridad cuando se trata del modo de direccionamiento utilizado en el operando de origen y destino. $ significa immediate direccionamiento immediate , como en uso el valor en la instrucción en sí. En el ejemplo anterior, si se escribió sin este $ , se usaría el direccionamiento direct , es decir, la CPU intentaría recuperar el valor en la dirección de memoria 1 (lo que más probablemente resultará en un error de segmentación). El % significa direccionamiento de register , si no incluyó esto en el ejemplo anterior, eax trataría como un symbol es decir, una dirección de memoria etiquetada, lo que muy probablemente resultaría en una undefined reference en el tiempo del enlace. Por lo tanto, es obligatorio que sea explícito sobre el modo de direccionamiento utilizado tanto en el operando de origen como en el de destino.

La forma en que se especifican los operandos de memoria también es diferente:

Intel : [base register + index * size of index + offset]

AT & T : compensación (registro base, índice, tamaño del índice)

La sintaxis de Intel hace que sea un poco más claro qué cálculo se está llevando a cabo para encontrar la dirección de memoria. Con la sintaxis de AT & T, el resultado es el mismo, pero se espera que sepa que se está realizando el cálculo.

debería, teóricamente al menos, producir el mismo binario

Esto es completamente dependiente de tu cadena de herramientas.

¿Cuáles son las razones para favorecer a uno u otro?

Preferencia personal, por supuesto, en mi opinión, se reduce a la sintaxis con la que se sienta más cómodo al abordar la memoria. ¿Prefiere la explicitación forzada de la sintaxis de AT & T? ¿O prefieres que tu ensamblador descubra este bajo nivel de detalle para ti?

¿Es opciones de línea de comando? Macros? ¿Palabras clave no nemotécnicas?

Esto tiene que ver con el ensamblador (GAS, NASM) en sí. Nuevamente, preferencia personal.