Hace algun tiempo consegui 2 libros sobre “systems programming” :
- Software de sistemas: Introduccion a la programacion de sistemas, por Leland L. Beck, Editorial Addison Wesley, ISBN: 0-201-64402-9
- Systems Programmin, por John J. Donovan. Editorial MCGRAW HILL ISBN- 0-07-085175-1
Esta area una de mis pasiones sin duda, aunque nunca me habia dado cuenta, ya que estan grande que no sabia como etiquetarla. En fin al grano.
Hay muy pocar informacion sobre como programar un ensamblador, hasta ahora estos 2 libros nos dan una idea y teoria sobre como podemos empezar, aunque uno se enfoca en un ensamblador para arquitectura mainframe ( ibm 360) y el otro en un cpu imaginario, la verdad es que son ejemplos un poco viejitos y no dan algunos “trucos” que podemos hacer, para esto estudiamos un poco en ensamblador NASM:
En el codigo del nasm existen varios scripts en perl y algunos archivos .dat que son procesados por los anteriores para crear algunos archivos de salida en lenguaje C ( la mayoria son declaracion de vectores y estructuras)
El esquema que tienen realmente es ingenioso!!!
Primero que nada necesitamos una “base de datos” donde podamos tener relacionada la informacion sobre los codigos de operacion (opcodes) de TODAS las instrucciones del procesador.
—————————————-
~/src/nasm-0.98.38$ more insns.dat
; For a detailed description of the code string (third field), please
; see the comment at the top of assemble.c. For a detailed description
; of the flags (fourth field), please see insns.h.
;
AAA void \1\x37 8086
AAD void \2\xD5\x0A 8086
AAD imm \1\xD5\24 8086,SB
AAM void \2\xD4\x0A 8086
AAM imm \1\xD4\24 8086,SB
……
……
======================================
En el archivo insns.dat del nasm ( version 0.98.38) tenemos la “informacion” sobre cada instruccion, cuantos parametros ocupa, cual es el “size” de los parametros
En el archivo insns.h encontramos una estructura muy importante:
struct itemplate {
int opcode; /* the token, passed from “parser.c” */
int operands; /* number of operands */
long opd[3]; /* bit flags for operand types */
const char *code; /* the code it assembles to */
unsigned long flags; /* some flags */
};
El programa insns.pl procesa el insns.dat y genera varios archivos llenando varios vectores de estructuras las cuales seran utilizadas por la funcion de generacion de codigo del propio NASM.
~/src/nasm-0.98.38$ ls *.pl
insns.pl
~/src/nasm-0.98.38$ more insnsd.c
/* This file auto-generated from insns.dat by insns.pl - don’t edit it */
#include “nasm.h”
#include “insns.h”
Por cada instruccion se genero un valor entero por medio de un enum (archivo insnsi.h)
static struct itemplate instrux[] = {
{I_AAA, 0, {0,0,0}, “\1\x37″, IF_8086}, //AAA tiene cero parametros,su valor es 0×37
“\1 valor hex= 0×37
{I_AAD, 0, {0,0,0}, “\2\xD5\x0A”, IF_8086},
{I_AAD, 1, {IMMEDIATE,0,0}, “\1\xD5\24″, IF_8086|IF_SB},
{I_AAM, 0, {0,0,0}, “\2\xD4\x0A”, IF_8086},
{I_AAM, 1, {IMMEDIATE,0,0}, “\1\xD4\24″, IF_8086|IF_SB},
{I_AAS, 0, {0,0,0}, “\1\x3F”, IF_8086},
{I_ADC, 2, {MEMORY,REG8,0}, “\300\1\x10\101″, IF_8086|IF_SM},
{I_ADC, 2, {REG8,REG8,0}, “\1\x10\101″, IF_8086},
Ademas se genera un archivo donde tenemos una estructura por cada instruccion de modo que especificamos cuantas “formas” tiene una instruccion.
/* This file auto-generated from insns.dat by insns.pl - don’t edit it */
#include “nasm.h”
#include “insns.h”
AAA tiene solo una forma
static struct itemplate instrux_AAA[] = {
{I_AAA, 0, {0,0,0}, “\1\x37″, IF_8086},
ITEMPLATE_END
};
AAD tiene 2 formas
static struct itemplate instrux_AAD[] = {
{I_AAD, 0, {0,0,0}, “\2\xD5\x0A”, IF_8086},
{I_AAD, 1, {IMMEDIATE,0,0}, “\1\xD5\24″, IF_8086|IF_SB},
ITEMPLATE_END
};
AAM tiene 2 formas
static struct itemplate instrux_AAM[] = {
{I_AAM, 0, {0,0,0}, “\2\xD4\x0A”, IF_8086},
{I_AAM, 1, {IMMEDIATE,0,0}, “\1\xD4\24″, IF_8086|IF_SB},
ITEMPLATE_END
};
El elemento ITEMPLATE_END es esta definido para ser una marca de fin, de modo que posteriormente la funcion que genera el codigo pueda, en base al codigo de operacion, el tipo de parametros y la posicion de cada uno seleccionar una de las entradas en el vector instrux_AAA ( en el ejemplo para AAA).
De la forma anterior unicamente se necesita programar la logica para “leer” lo que indica la entructura instrux. Por lo que se puede ver, el proposito de cada campo en la estructura es la siguiente:
struct itemplate {
int opcode; /* cada instruccion tiene definido un posible token que el parser reconocera
int operands; /* indica el numero de operadores */
long opd[3]; /* bit flags for operand types */
const char *code; /* el numero hexadecimal una vez ensamblado*/
unsigned long flags; /* banderas, posiblemente para indicar en que modo del procesador es valido*/
};
Asi, estas estructuras forman parte basica de NASM, ya en ellas se puede descargar la logica/complejidad para especificar que numeros hexadecimales( y por tanto binarios) corresponden a cada instruccion en ensamblador asi como cuantas formas posibles tiene cada una.
Pf, veremos si podemos especificar algo como esto para el jmmix assembler 