viernes, 7 de agosto de 2015

[FASM] Ensamblador en línea

Hoy les traigo una manera muy simple de como utilizar ensamblador en sus programas, solo vamos a necesitar dos items, una libreria externa y ganas de programar.

Empezamos descargando FASM.dll de este enlace: ¡Descargar!

Esta libreria nos ofrece 3 procedimientos.

Proc fasm_Assemble(Referencia:Cadena,,,,:Entero):Entero, "FASM.dll"
Proc fasm_GetVersion:Entero, "FASM.dll" ' Sin parametros, Void...
Proc fasm_AssembleFile(Referencia:Cadena,,,,:Entero):Entero, "FASM.dll"

fasm_Assemble: Este procedimiento (o función) nos permite "compilar" nuestro código ensamblador con sintaxis FASM a Opcodes (o offsets) que pueden ser manipulados a nuestra voluntad.

fasm_GetVersion: Este procedimiento retorna la versión de la libreria, se debe separar entre HiWord y LoWord.

fasm_AssembleFile: Nos permite procesar un archivo de código fuente con formato ASM, muy util si quieren hacer procedimientos dinamicos.

Por si no se puede apreciar, fasm_Assemble y fasm_AssembleFile tienen exactamente la misma cantidad de parametros y su uso es muy semejante.

2 de 3 de estos procedimientos devuelven punteros a estructuras, estas son las siguientes:

' Unión #1
Unión FASM_DATA1,_
output_length,_ ' Cantidad de opcodes.
error_code:Entero ' Código del error.

' Unión #2
Unión FASM_DATA2,_
output_data,_ ' Puntero a los offsets.
error_line:Entero ' Puntero a FASM_LINE_HEADER con la información del error.

Unión FASM_DATA3,_
file_offset,_
macro_calling_line:Entero

Estruc FASM_STATE,_ ' Estructura que obtiene los offsets / Opcodes.
condition:Entero,_
a:FASM_DATA1,_ ' Unión #1
b:FASM_DATA2   ' Unión #2

Estruc FASM_LINE_HEADER,_
file_path,_
line_number:Entero,_
c:FASM_DATA3,_
macro_line:Entero

fasm_Assemble acepta 5 parametros, los unicos que nos importan son los 3 primeros.

Parametro #1: Código que se procesará.
Parametro #2: Puntero al buffer que recibirá los datos de las estructuras.
Paraemtro #3: Tamaño del buffer.
Parametro #4: Debe ser 100.
Parametro #5: Puntero a CallBack, debe ser cero.
Retorno: 0 Si fue exitoso, otro valor si hubo un error.

Un ejemplo de el uso de este procedimiento es el siguiente:

Proc ProcesarASM(Referencia Código:Cadena):Byte[]
      Var Offsets[]:Byte ' Declaramos el buffer.
      Var Info:FASM_STATE ' Estructura que contendra los datos recibidos del buffer.
      Var Error:FASM_LINE_HEADER ' Estructura que obtiene los errores encontrados.
      Var Verificar:Entero ' Variable que utilizamos para obtener el código de error (si hubo).
      ReDim Offsets,10000 ' ReDimencionamos el buffer (tamaño recomendado).
      Verificar = fasm_Assemble(Código,Offsets[0]@,10000,100,0)
      Si Verificar = 0 Entonces ' Si no hubo ningún problema.
      AdmErr ' Verificamos si se produce un error.
            CopyMemory(Info@,Offsets[0]@,Long(Info)) ' Copiamos el contenido de "Offsets" en Info para _
            ' rellenar la estructura.
            CopyMemory(Offsets[0]@,Info.b.output_data,Long(Info.b.output_data)) ' Rellenamos el buffer _
            ' con los datos que estan en la dirección de "Info.b.output_data" (offsets).
      Controlar ' Si se produjo algún error.
            Salir ' Salimos del procedimiento sin devolver nada.
      FinAdmErr
            ReDim Preservar Offsets,Info.a.output_length ' Redimencionamos la matriz con la cantidad de offsets presentes.
            Resultado = Offsets ' Devolvemos los offsets.
      SiNo ' Si hubo un problema.
            CopyMemory(Info@,Offsets[0]@,Long(Info)) ' Copiamos el contenido de "Offsets" en Info para _
            ' rellenar la estructura.
            CopyMemory(Error@,Info.b.error_line,Long(Error)) ' Rellenamos la estructura Error con el contenido obtenido de la dirección "Info.b.error_line".
            Resultado = [0,ERROR.line_number,ERROR.c.file_offset]
      FinSi
FinProc

Creo que el código de ejemplo esta muy claro.

El procediento fasm_AssembleFile es muy parecido a fasm_Assemble, lo unico que cambia es que el primer parametro, en vez de ser código, es la dirección de un archivo ASM en nuestro sistema, en caso de no encontrarse "info.a.error_code" devuelve "FASM_SOURCE_NOT_FOUND" (-4).

Saludos!