assembly - nivel - ¿Por qué hay una diferencia entre los lenguajes ensambladores como Windows, Linux?
lenguaje maquina ejemplos (9)
Soy relativamente nuevo en todo esto de bajo nivel, lenguaje ensamblador ... y quiero aprender más detalles. ¿Por qué hay una diferencia entre los lenguajes de ensamblador de Linux y Windows?
Como entiendo cuando compilo un código C, el sistema operativo realmente no produce una máquina pura o un código ensamblador, sino que produce un código binario dependiente del sistema operativo. Pero ¿por qué?
Por ejemplo, cuando uso un sistema x86, la CPU solo entiende ASM x86 ¿estoy en lo cierto? Por lo tanto, ¿por qué no escribimos el código de ensamblaje x86 puro y por qué hay diferentes variaciones de ensamblaje basadas en el sistema operativo? Si escribiéramos ASM puro o OS produciría ASM puro, no habría problemas de compatibilidad binarios entre los sistemas operativos o no?
Realmente me pregunto todas las razones detrás de ellos. Cualquier respuesta detallada, artículo, libro sería genial. Gracias.
No hay diferencia en los lenguajes ensambladores (aunque puede haber diferencias entre los ensambladores, y por lo tanto, las anotaciones utilizadas), siempre que nos apeguemos a x86. Tanto Linux como Microsoft Windows se ejecutan en otras arquitecturas, más aún en el caso de Linux.
Sin embargo, un sistema operativo hoy en día no solo carga un programa en la memoria y lo deja ir. Proporciona una gran cantidad de servicios. Como también protege los programas entre sí, impone restricciones. Para hacer algo más que cálculos básicos, generalmente es necesario pasar por el sistema operativo. (Esto era menos cierto en los sistemas operativos anteriores, como MS-DOS y CP / M, que podían cargar programas que se ejecutarían independientemente, pero hoy en día casi todos los sistemas no integrados tienen un sistema operativo moderno).
Tampoco se almacenan los programas como blobs binarios simples. Normalmente es necesario vincularlo con otras bibliotecas, a menudo cuando el programa se carga para su ejecución (así es como funcionan las DLL, por ejemplo) y es necesario vincularlo con el sistema operativo. Puede haber otra información que el sistema operativo requiera y, por lo tanto, debe haber algún tipo de información sobre el blob binario en el archivo ejecutable. Esto varía entre los sistemas operativos.
Por lo tanto, los archivos ejecutables deben estar en un formato para ser cargados en la memoria, y esto varía desde el sistema operativo al sistema operativo. Para hacer algo útil, tienen que hacer llamadas al sistema operativo, que son diferentes entre sistemas. Es por eso que no puede tomar un ejecutable de Windows y las bibliotecas asociadas y ejecutarlo en Linux.
Históricamente, el ensamblaje de Linux tiende a realizarse usando la sintaxis de AT & T, ya que es lo que GNU Assembler admite. Del mismo modo, los ensambladores de Windows tienden a usar la sintaxis de Intel, como con MASM y NASM .
Todos los ensambladores x86 producen la misma salida, es decir, el código de máquina x86. Y puede usar NASM o GNU Assembler en Linux para programar bajo la sintaxis de Intel, y GNU Assembler en Windows para programar bajo la sintaxis de AT & T.
A menos que esté utilizando un entorno de desarrollo de sistema integrado, está compilando con compiladores que están destinados a un tiempo de ejecución particular. Ese tiempo de ejecución define las convenciones para el uso del hardware: aprobación de argumentos, manejo de excepciones, etc. Estas convenciones interactúan con el sistema operativo, o al menos con las bibliotecas de tiempo de ejecución disponibles con las que el programa necesita vincularse.
Además de otras respuestas.
OS dicta su Interfaz Binaria de Aplicación (ABI), que incluye el formato de objetos ejecutables. Estos son formatos ejecutables y enlazables (ELF) para Linux (y muchos otros sistemas similares a Unix) y Portable Executable (PE) en Windows. Vea esta tabla para otros formatos.
Bueno, no ejecutas el ensamblaje directo. El código debe estar en algún tipo de formato ejecutable: windows usa PE, la mayoría de los Unices usan ELF ahora (aunque ha habido otros, como a.out).
Las instrucciones de ensamblaje de la base son las mismas, y las funciones que crea con ellas son las mismas.
El problema viene con el acceso a otros recursos. El procesador es realmente bueno para el cálculo, pero no puede acceder al disco duro, imprimir un personaje en la pantalla o conectarse a un teléfono con Bluetooth. Estos elementos siempre dependen de algún modo del sistema operativo. Se implementan en términos de llamadas de sistema, donde el procesador señala al sistema operativo para realizar una determinada tarea. La tarea número 17 en Linux no es necesariamente la tarea 17 en Windows; es posible que ni siquiera tengan equivalentes.
Como la mayoría de las bibliotecas tienen algunas llamadas de sistema en sus niveles más bajos, esta es la razón por la que el código no se puede volver a compilar en todos los casos.
El sistema operativo determina dos cosas: (1) la convención de llamadas , que define cómo van los parámetros en la pila y, por lo tanto, afecta el código ensamblador, y (2) las bibliotecas de tiempo de ejecución que implementan funciones comunes como asignación de memoria, entrada / salida, superior nivel de matemáticas, etc.
Entonces, mientras x+y
compila el mismo código ensamblador bajo Windows o Linux en un procesador x86, y = sin(x)
será diferente debido a una convención de llamada diferente y a una biblioteca matemática diferente.
Más allá de eso, el lenguaje ensamblador depende del procesador. x86, x86_64, ARM, PowerPC, cada uno tiene su propio lenguaje ensamblador.
No hay diferencia. El código de ensamblaje es el mismo si el procesador es el mismo. El código x86 compilado en Windows es binario compatible con el código x86 en Linux. El compilador no produce código binario dependiente del sistema operativo, pero puede empaquetar el código en un formato diferente (por ejemplo, PE frente a ELF).
La diferencia radica en qué bibliotecas se utilizan. Para usar cosas del sistema operativo (E / S, por ejemplo), debe vincularse con las bibliotecas del sistema operativo. Como era de esperar, las bibliotecas del sistema de Windows no están disponibles en una máquina Linux (a menos que tenga Wine por supuesto) y viceversa.
Existen algunos ensambladores para varias plataformas que, dado un archivo fuente, producirán un archivo binario de salida directamente diseñado para ser cargado en una dirección particular. Tales ensambladores han sido populares para algunos microcontroladores pequeños, o para algunos procesadores históricos como el 6502 y el Z80. Al armar el programa, sería necesario conocer la dirección donde se esperaría que residiera; usar una dirección diferente requeriría volver a ensamblar el programa. Por otro lado, el ensamblaje en un sistema de este tipo era un proceso de un solo paso. Ejecute el ensamblador en el código fuente y obtenga una salida ejecutable. En algunos casos, sería posible tener el código fuente, ensamblador y salida en la memoria a la vez (en mi Commodore 64, utilicé un ensamblador que se publicó en la revista Compute''s Gazette que funcionaba así).
Aunque volver a montar todo en cualquier momento sus cambios de dirección podrían haber sido prácticos para un programa que "asumirá la máquina", en muchos casos es deseable usar un proceso de varios pasos donde los archivos fuente se procesen en archivos de código objeto, que contienen el instrucciones ensambladas pero también contienen varios tipos de información "simbólica" sobre ellas; estos archivos se procesan de varias formas para generar una imagen de memoria que se puede cargar directamente en la memoria, o bien un archivo de objeto reubicable combinado que el cargador de un sistema operativo sabrá cómo ajustar para cualquier dirección a la que pueda cargarse .
Para que un sistema de enlace de objetos sea útil, debe permitir el aplazamiento de ciertos tipos de cálculo de direcciones hasta que un programa se vincule o cargue. Algunos sistemas solo permiten que se realicen cómputos extremadamente simples en el tiempo de enlace / carga, mientras que otros permiten cálculos más complicados. Los esquemas más simples pueden ser más eficientes cuando son viables, pero sus limitaciones pueden forzar soluciones temporales. Como ejemplo, una rutina que usará BX para recorrer una estructura de datos con menos de 256 bytes podría escribirse como algo como:
mov bx,StartAddr
lp: mov al, [bx] ... hacer algunos cálculos inc bx cmp bl, <(StartAddr + Length); <operador de prefijo significa "LSB de" jnz lp
Sería posible usar cmp bx,(StartAddr+Length)
, pero si las herramientas de compilación lo admiten, la comparación del byte bajo sería más rápida. Por otro lado, algunos tipos de herramientas de ensamblaje / enlace de 16 bits pueden requerir que todas las correcciones de direcciones se realicen con direcciones de 16 bits almacenadas en el código.
Debido a que diferentes sistemas permiten diferentes características en sus formatos de código objeto, requieren diferentes características en sus lenguajes de ensamblaje para controlarlos. Los conjuntos de instrucciones pueden ser especificados por el fabricante del chip, pero las características para expresar el cálculo de dirección reubicable generalmente no lo son.
El lenguaje ensamblador está relacionado con la arquitectura de la CPU que no tiene sistema operativo, pero el sistema operativo tiene una serie de funciones del sistema compiladas en binario que su programa ensamblador puede invocar, mediante llamadas de interrupción. Por ejemplo, salida de entrada estándar, operación ecc ....