domingo, 8 de julio de 2012

Ensamblador 8086 Creando módulos

Conforme desarrollamos ejemplos más elaborados, el tamaño de nuestros archivos aumenta y muchas veces copiamos el mismo código en varios programas (por ejemplo, el código que despliega una imagen bmp). En este post, veremos una forma de cómo reusar funciones que están en un módulo (archivo) independiente.

Tomemos como ejemplo el programa de este post. El programa convierte dos cadenas a enteros usando la función atoi (ascii to integer), los suma y convierte el resultado a cadena usando itoa (integer to ascii) para poder desplegarlo. Las funciones itoa/atoi son funciones que podemos reusar en varios programas, por lo que es buena idea ponerlas en un archivo independiente.

Comencemos por colocar estas funciones en un archivo llamado libcad.asm. El segundo paso es crear un archivo que contenga los prototipos de las funciones que queremos usar en otros archivos. Llamemos a este archivo libcad.inc. El contenido del archivo libcad.inc es el siguiente:

.CODE
EXTERNDEF atoi:NEAR
EXTERNDEF itoa:NEAR
@CurSeg ENDS

Noten que debemos especificar el segmento en donde se encuentra lo que queremos exportar. En este caso nuestras funciones se encuentran en el segmento .CODE; además, es recomendable cerrar el segmento ya que incluiremos este archivo en otros archivos. La palabra clave EXTERNDEF declara lo que queremos exportar, en este caso es seguida por el nombre de la función y el tipo de la función (NEAR, porque estamos usando .MODEL SMALL en nuestros programas).

El archivo libcad.inc se debe incluir tanto en el archivo que define las funciones como en los archivos que las usan. El archivo libcad.asm queda de la siguiente forma:

.model SMALL
.STACK 128
INCLUDE libcad.inc
.CODE
; ========= Convertir cadena a numero =====================
; Parametros
; si: offset inicial de la cadena con respecto a DS
; Retorna
; bx: valor
atoi proc NEAR
  xor bx,bx   ;BX = 0

  atoi_1:
  lodsb       ;carga byte apuntado por SI en AL
              ;e incrementa si
  cmp al,'0'  ;es numero ascii? [0-9]
  jb noascii  ;no, salir
  cmp al,'9'
  ja noascii  ;no, salir

  sub al,30h  ;ascii '0'=30h, ascii '1'=31h...etc.
  cbw         ;byte a word
  push ax
  mov ax,bx   ;BX tendra el valor final
  mov cx,10
  mul cx      ;AX=AX*10
  mov bx,ax
  pop ax
  add bx,ax
  jmp atoi_1  ;seguir mientras SI apunte a un numero ascii
  noascii:
  ret         ;BX tiene el valor final
atoi endp

; =============== Convertir numero a cadena ===============
; Parametros
; ax: valor
; bx: donde guardar la cadena final
; Retorna
; cadena
itoa proc NEAR
  xor cx,cx  ;CX = 0

  itoa_1:
  cmp ax,0   ; El ciclo itoa_1 extrae los digitos del
  je itoa_2  ; menos al mas significativo de AX y los
             ; guarda en el stack. Al finalizar el 
  xor dx,dx  ; ciclo el digito mas significativo esta
  push bx    ; arriba del stack.
  mov bx,10  ; CX contiene el numero de digitos
  div bx
  pop bx
  push dx
  inc cx
  jmp itoa_1

  itoa_2:
  cmp cx,0    ; Esta seccion maneja el caso cuando
  ja itoa_3   ; el numero a convertir (AX) es 0.
  mov ax,'0'  ; En este caso, el ciclo anterior
  mov [bx],ax ; no guarda valores en el stack y
  inc bx      ; CX tiene el valor 0
  jmp itoa_4

  itoa_3:
  pop ax      ; Extraemos los numero del stack
  add ax,30h  ; lo pasamos a su valor ascii
  mov [bx],ax ; lo guardamos en la cadena final
  inc bx
  loop itoa_3

  itoa_4:
  mov ax,'$'  ; terminar cadena con '$' para 
  mov [bx],ax ; imprimirla con la INT21h/AH=9
  ret
itoa endp

end

Y el archivo de ejemplo que usa las funciones es el siguiente (ejem01.asm):

.model SMALL
.STACK 128
INCLUDE libcad.inc
.DATA
  cadena1 db '123$'
  cadena2 db '444$'
  cadena3 db 6 DUP(?)
  op1 dw ?
  op2 dw ?

.CODE
  .STARTUP
  mov ax,@data
  mov ds,ax

main proc
  ; SI parametro
  mov si, offset cadena1
  call atoi
  mov op1,bx
   
  ; SI parametro
  mov si, offset cadena2
  call atoi
  mov op2,bx
   
  ; sumar
  mov ax, op1
  add ax, op2
  mov bx, offset cadena3
  call itoa
   
  mov dx, offset cadena3
  call desplegar
   
  ; INT 21h / AH=4Ch retorna el control al sistema operativo
  ;                  termina el programa
  salir:
  mov ax,4c00h
  int 21h
  ret
main endp

; ============ Proc: Desplegar mensaje ====================
; Parametros
; dx: offset de cadena terminada por $ con respecto a DS
desplegar proc
   ; INT 21h / AH=9 - despliega cadena apuntada por DS:DX. 
   ; la cadena debe estar terminada por '$'.
   mov ah,09h
   ;mov dx, offset cad
   int 21h
   ret
desplegar endp

end

Para ensamblar y ligar estos archivos basta con invocar

ml EJEM01.ASM LIBCAD.ASM

No hay comentarios:

Publicar un comentario