¿Cómo afecta un sistema operativo la forma en que se ejecuta el código ensamblador?

StackOverflow https://stackoverflow.com/questions/1175375

  •  19-09-2019
  •  | 
  •  

Pregunta

Espero aprender lenguaje ensamblador para x86.Estoy en una Mac y supongo que la mayoría de los tutoriales/libros x86 usan código destinado a Windows.

¿Cómo afecta el sistema operativo en el que se ejecuta el código lo que hace el código o determina si el código funciona?¿Puedo seguir un tutorial basado en Windows y modificar algunos comandos para que funcione en Mac con relativa facilidad?En términos más generales, ¿hay algo complicado que un programador ensamblador de Mac, específicamente, deba saber?¡Gracias!

¿Fue útil?

Solución

(Por supuesto, todo lo siguiente se aplica solo a lenguaje ensamblador x86 y x86-64, para procesadores y sistemas operativos IA-32 y AMD64).

Las otras respuestas actualmente visibles son todas correctas, pero, en mi opinión, no entienden el punto.La sintaxis de AT&T versus Intel no es un problema;cualquier herramienta decente funcionará con ambas sintaxis o tendrá una contraparte o reemplazo que lo haga.Y se montan igual de todos modos.(Consejo:realmente desea utilizar la sintaxis de Intel.Toda la documentación oficial del procesador lo hace.La sintaxis de AT&T es solo un gran dolor de cabeza.) Sí, encontrar los indicadores correctos para pasar al ensamblador y al vinculador puede ser complicado, pero sabrás cuándo los tienes y solo tendrás que hacerlo una vez por sistema operativo (si ¡recuerda anotarlo en alguna parte!).

Las propias instrucciones de montaje, por supuesto, son completamente independientes del sistema operativo.La CPU no le importa qué sistema operativo está ejecutando.A menos que esté haciendo piratería de nivel extremadamente bajo (es decir, desarrollo de sistema operativo), los aspectos prácticos de cómo interactúan el sistema operativo y la CPU son casi totalmente irrelevantes.

El mundo exterior

El problema con el lenguaje ensamblador surge cuando interactúas con el mundo exterior:el kernel del sistema operativo y otro código del espacio de usuario.El espacio de usuario es el más complicado:tienes que obtener el ABI correcto o tu programa de ensamblaje será prácticamente inútil.Esta parte generalmente no es portátil entre sistemas operativos a menos que use trampolines/thunks (básicamente, otra capa de abstracción que debe reescribirse para cada sistema operativo que desee admitir).

La parte más importante de la ABI es cualquiera que sea la convención de llamada para funciones de estilo C.Son los que se admiten con mayor frecuencia y con los que probablemente interactuarás si estás escribiendo en ensamblador.Agner Fog mantiene varios buenos recursos en su sitio;el descripción detallada de las convenciones de llamadas es particularmente útil.En su respuesta, Norman Ramsey menciona PIC y bibliotecas dinámicas;En mi experiencia, normalmente no tienes que preocuparte por ellos si no quieres.Los enlaces estáticos funcionan bien para usos típicos del lenguaje ensamblador (como reescribir funciones centrales de un bucle interno u otro punto de acceso).

La convención de llamada funciona en dos direcciones:puede llamar a C desde la asamblea o a la asamblea desde C.Esto último suele ser un poco más fácil pero no hay una gran diferencia.Llamar a C desde un ensamblado le permite usar cosas como las funciones de salida de la biblioteca estándar de C, mientras que llamar a un ensamblado desde C es normalmente la forma de acceder a una implementación en ensamblador de una única función crítica para el rendimiento.

Llamadas al sistema

La otra cosa que hará su programa es realizar llamadas al sistema.Puedes escribir un programa ensamblador completo y útil que nunca llame a funciones C externas, pero si quieres escribir un programa en lenguaje ensamblador puro que no subcontrate las cosas divertidas al código de otra persona, vas a necesidad llamadas al sistema.Y, desafortunadamente, las llamadas al sistema son total y completamente diferentes en cada sistema operativo.Las llamadas al sistema estilo Unix que necesitará incluyen (¡pero seguramente no se limitan a ellas!) open, creat, read, write, y lo más importante exit, junto con mmap si te gusta asignar memoria dinámicamente.

Si bien cada sistema operativo es diferente, la mayoría de los sistemas operativos modernos siguen un patrón general:carga el número de la llamada al sistema que desea en un registro, normalmente EAX en código de 32 bits, luego cargue los parámetros (la forma de hacerlo varía enormemente) y finalmente emita una solicitud de interrupción:es INT 2E para núcleos de Windows NT o INT 80h para Linux 2.x y FreeBSD (y, creo, OSX).Luego, el kernel toma el control, ejecuta la llamada al sistema y devuelve la ejecución a su programa.Dependiendo del sistema operativo, es posible que elimine los registros o se apile como parte de la llamada al sistema;Tendrás que asegurarte de leer la documentación de llamadas al sistema de tu plataforma para estar seguro.

SYSENTER

Los kernels de Linux 2.6 (y, creo, Windows XP y posteriores, aunque nunca lo he probado en Windows) también admiten un método más nuevo y más rápido para realizar una llamada al sistema:el SYSENTER instrucción introducida por Intel en los chips Pentium más nuevos.Los chips AMD tienen SYSCALL, pero pocos sistemas operativos de 32 bits lo usan (aunque creo que es el estándar para 64 bits;No he tenido que realizar llamadas directas al sistema desde un programa de 64 bits, así que no estoy seguro de esto). SYSENTER es significativamente más complicado de configurar y usar (ver, por ejemplo, Linus Torvalds sobre la implementación SYSENTER soporte para Linux 2.6:"Soy un cerdo repugnante y, además, orgulloso de ello.") Puedo dar fe personalmente de su peculiaridad;Una vez escribí una función de ensamblaje que emitía SYSENTER directamente a un kernel Linux 2.6, y yo aún No entiendo los diversos trucos de pila y registro que hicieron que funcionara...¡Pero funcionó!

SYSENTER es algo más rápido que emitir INT 80h, por lo que su uso es deseable cuando esté disponible.Para facilitar la escritura de código rápido y portátil, Linux asigna un VDSO llamado linux-gate en el espacio de direcciones de cada programa;llamar a una función especial en este VDSO emitirá una llamada al sistema mediante el mecanismo más rápido disponible.Desafortunadamente, usarlo generalmente genera más problemas de lo que vale la pena: INT 80h Es mucho más sencillo de hacer en una pequeña rutina de montaje que vale la pena la pequeña penalización de velocidad.A menos que necesites el máximo rendimiento...y si necesita eso, probablemente no quiera llamar a un VDSO de todos modos, y conoce su hardware, por lo que puede hacer algo terriblemente inseguro y emitir SYSENTER tú mismo.

Todo lo demas

Aparte de las exigencias impuestas por la interacción con el kernel y otros programas, existen muy, muy pocas diferencias entre los sistemas operativos.El montaje expone el alma de la máquina:puedes trabajar como quieras y dentro de tu propio código no estás sujeto a ninguna convención de llamadas en particular.Tienes acceso gratuito a las unidades FPU y SSE;puede PREFETCH directamente para transmitir datos desde la memoria al caché L1 y asegurarse de que estén calientes cuando los necesite;puedes mover la pila a voluntad;puedes emitir INT 3 si desea interactuar con un (correctamente configurado;¡buena suerte!) depurador externo.Ninguna de estas cosas depende de su sistema operativo.La única restricción real que tiene es que está ejecutando en el Anillo 3, no en el Anillo 0, por lo que algunos registros de control del procesador no estarán disponibles para usted.(Pero si los necesita, está escribiendo código del sistema operativo, no código de aplicación). Aparte de eso, la máquina está al descubierto para usted:¡Ve y calcula!

Otros consejos

En términos generales, siempre y cuando se utiliza el mismo ensamblador, y la misma arquitectura (por ejemplo, NASM, y x86-64), que debe ser capaz de montar el montaje tanto en Windows y Mac.

Sin embargo, es importante tener en cuenta que los formatos ejecutables y los entornos de ejecución pueden ser diferentes. Como ejemplo, Windows puede emular / manejar ciertas instrucciones privilegiadas de manera diferente a Mac, provocando un comportamiento diferente.

También una gran parte de la diferencia está en cómo el programa se comunica con el mundo exterior.

Por ejemplo, si desea mostrar un mensaje al usuario o leer un archivo o asignar más memoria que tiene que pedir al sistema operativo para hacerlo, haciendo una especie de llamada al sistema. Eso va ser muy diferente entre sistemas operativos.

La sintaxis del lenguaje en sí debería ser básicamente idénticos, siempre y cuando estés usando el mismo ensamblador. Diferentes ensambladores tienen a veces un poco diferente de pedidos en la sintaxis o diferentes macros, pero nada que sea demasiado difícil de acostumbrarse.

La gran división en el lenguaje ensamblador de Intel se encuentra entre la sintaxis de AT&T y la sintaxis de Intel.Querrás un ensamblador para tu Mac que use la misma sintaxis que cualquier tutorial que uses.Como creo que MacOS Darwin, una variante de BSD, usa la sintaxis de AT&T y el ensamblador de Microsoft usa la sintaxis de Intel, deberá tener cuidado.

La otra diferencia a tener en cuenta es la interfaz binaria de aplicaciones (ABI) del sistema, que cubre convenciones de llamadas, diseño de pila, llamadas al sistema, etc.Pueden diferir sustancialmente entre sistemas operativos, especialmente cuando se trata de código independiente de la posición y enlace dinámico.Tengo vagos recuerdos tristes de que PIC era especialmente complicado en PowerPC MacOS, pero tal vez sea más simple en Intel.

Un consejo: aprender x86_64 (también conocido como AMD64): es mucho más divertido escribir código ensamblador a mano y estará más preparado para el futuro.

Cuando se sumerge en la Asamblea durante una de mis turística de programación visitas, el Gotcha que me sustentaba en cada tutorial no estaba siendo capaz de compilar en el formato binario correcto. La mayoría de los tutoriales dan elf (para Linux) y aoutb (para BSD), sin embargo, con este último OS X se queja (opción lógica?):

ld: hello.o bad magic number (not a Mach-O file)

¿No Mach-O no como un formato, y si man nasm se obtiene sólo bin, formatos aout y archivo elf - man ld no es más útil - macho es la opción de hacer el formato de Mach-O para OS X:

nasm -f macho hello.asm

escribí el viaje aquí (incluye un enlace a un buen paquete TextMate de montaje y otra información), pero - a ser breve -. lo anterior es lo que se necesita para empezar

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top