He hecho esto muchas veces y sigo haciéndolo. En este caso, donde su objetivo principal es leer y no escribir ensamblador, creo que esto se aplica.
Escriba su propio desensamblador. No con el propósito de hacer el próximo mejor desensamblador, este es estrictamente para usted. El objetivo es aprender el conjunto de instrucciones. Ya sea que esté aprendiendo ensamblador en una nueva plataforma, recordando ensamblador para una plataforma que una vez conocí. Comience con solo unas pocas líneas de código, agregando registros, por ejemplo, y haciendo ping pong entre el desmontaje de la salida binaria y la adición de instrucciones cada vez más complicadas en el lado de entrada:
1) aprender el conjunto de instrucciones para el procesador específico
2) aprenda los matices de cómo escribir código en ensamblado para dicho procesador de modo que pueda mover cada bit de código de operación en cada instrucción
3) aprende el conjunto de instrucciones mejor que la mayoría de los ingenieros que utilizan ese conjunto de instrucciones para ganarse la vida
En su caso, hay un par de problemas, normalmente recomiendo el conjunto de instrucciones ARM para empezar, hay más productos basados en ARM enviados hoy que cualquier otro (computadoras x86 incluidas). Pero la probabilidad de que esté usando ARM ahora y no conozca el ensamblador suficiente para que escriba el código de inicio u otras rutinas sabiendo que ARM puede ayudar o no a lo que está tratando de hacer. La segunda y más importante razón para ARM primero es porque las longitudes de las instrucciones son de tamaño fijo y están alineadas. Desmontar instrucciones de longitud variable como x86 puede ser una pesadilla como primer proyecto, y el objetivo aquí es aprender el conjunto de instrucciones, no para crear un proyecto de investigación. Third ARM es un conjunto de instrucciones bien hecho, los registros se crean de la misma manera y no tienen matices especiales individuales.
Por lo tanto, tendrá que averiguar con qué procesador desea comenzar. Sugiero el msp430 o ARM primero, luego ARM primero o segundo y luego el caos de x86. Independientemente de la plataforma, cualquier plataforma que valga la pena usar tiene hojas de datos o manuales de referencia de programadores gratuitos del proveedor que incluyen el conjunto de instrucciones y la codificación de los códigos de operación (los bits y bytes del lenguaje de máquina). Con el fin de aprender lo que hace el compilador y cómo escribir código con el que el compilador no tiene que luchar, es bueno conocer algunos conjuntos de instrucciones y ver cómo se implementa el mismo código de alto nivel en cada conjunto de instrucciones con cada compilador con cada optimización. ajuste. No desea optimizar su código solo para descubrir que lo ha mejorado para un compilador / plataforma, pero mucho peor para todos los demás.
Ah, para desensamblar conjuntos de instrucciones de longitud variable, en lugar de simplemente comenzar desde el principio y desensamblar cada palabra de cuatro bytes linealmente a través de la memoria como lo haría con el ARM o cada dos bytes como el msp430 (el msp430 tiene instrucciones de longitud variable pero aún puede pasar pasando linealmente a través de la memoria si comienza en los puntos de entrada de la tabla de vectores de interrupción). Para la longitud variable, desea encontrar un punto de entrada basado en una tabla de vectores o conocimiento sobre cómo arranca el procesador y sigue el código en el orden de ejecución. Debe decodificar cada instrucción por completo para saber cuántos bytes se utilizan, luego, si la instrucción no es una rama incondicional, asuma que el siguiente byte después de esa instrucción es otra instrucción. También debe almacenar todas las direcciones de sucursales posibles y asumir que esas son las direcciones de byte de inicio para obtener más instrucciones. La única vez que tuve éxito hice varias pasadas a través del binario. Comenzando en el punto de entrada, marqué ese byte como el comienzo de una instrucción y luego decodifiqué linealmente a través de la memoria hasta llegar a una rama incondicional. Todos los destinos de rama se etiquetaron como direcciones de inicio de una instrucción. Hice varias pasadas a través del binario hasta que no encontré nuevos objetivos de rama. Si en algún momento encuentra una instrucción de 3 bytes, pero por alguna razón ha etiquetado el segundo byte como el comienzo de una instrucción, tiene un problema. Si el código fue generado por un compilador de alto nivel, esto no debería suceder a menos que el compilador esté haciendo algo malo, si el código tiene un ensamblador escrito a mano (como por ejemplo un viejo juego de arcade) es muy posible que haya ramas condicionales que nunca pueden suceder como r0 = 0 seguido de un salto si no es cero. Puede que tenga que editar manualmente los que están fuera del binario para continuar. Para sus objetivos inmediatos, que supongo que estarán en x86, no creo que tenga un problema.
Recomiendo las herramientas gcc, mingw32 es una forma fácil de usar las herramientas gcc en Windows si x86 es su objetivo. Si no, mingw32 plus msys es una excelente plataforma para generar un compilador cruzado a partir de fuentes binutils y gcc (generalmente bastante fácil). mingw32 tiene algunas ventajas sobre cygwin, como programas significativamente más rápidos y evita el infierno de cygwin dll. gcc y binutils te permitirán escribir en C o ensamblador y desensamblar tu código y hay más páginas web de las que puedes leer que te muestran cómo hacer una o todas las tres. Si va a hacer esto con un conjunto de instrucciones de longitud variable, le recomiendo que utilice un conjunto de herramientas que incluya un desensamblador. Un desensamblador de terceros para x86, por ejemplo, será un desafío de usar, ya que nunca se sabe realmente si se ha desmontado correctamente. Algo de esto también depende del sistema operativo, el objetivo es compilar los módulos en un formato binario que contenga instrucciones de marcado de información a partir de datos para que el desensamblador pueda hacer un trabajo más preciso. Su otra opción para este objetivo principal es tener una herramienta que pueda compilar directamente en ensamblador para su inspección y luego esperar que cuando compile en un formato binario cree las mismas instrucciones.
La respuesta corta (está bien, un poco más corta) a su pregunta. Escriba un desensamblador para aprender un conjunto de instrucciones. Comenzaría con algo RISCY y fácil de aprender como ARM. Una vez que conoce un conjunto de instrucciones, los demás se vuelven mucho más fáciles de aprender, a menudo en unas pocas horas, con el tercer conjunto de instrucciones puede comenzar a escribir código casi de inmediato utilizando la hoja de datos / manual de referencia para la sintaxis. Todos los procesadores que vale la pena usar tienen una hoja de datos o un manual de referencia que describe las instrucciones hasta los bits y bytes de los códigos de operación. Aprenda un procesador RISC como ARM y un CISC como x86 lo suficiente como para tener una idea de las diferencias, cosas como tener que pasar por registros para todo o poder realizar operaciones directamente en la memoria con menos o ningún registro. Tres instrucciones de operando versus dos, etc. A medida que ajusta su código de alto nivel, compile para más de un procesador y compare la salida. Lo más importante que aprenderá es que no importa lo bien que esté escrito el código de alto nivel, la calidad del compilador y las opciones de optimización que se hagan marcan una gran diferencia en las instrucciones reales. Recomiendo llvm y gcc (con binutils), ni producirgran código, pero son multiplataforma y multiplataforma y ambos tienen optimizadores. Y ambos son gratuitos y puede crear fácilmente compiladores cruzados a partir de fuentes para varios procesadores de destino.