CSC231 Homework 8 Solution 2012
--D. Thiebaut 12:15, 13 November 2012 (EST)
Problem #1, Version 1
This version contains the complete code. Version 2 below separates the dumpRegs functions and main program into two files.
;;; ---------------------------------------------------------
;;; hw8aSol.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This program supports several functions that allow the user
;;; to dump the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen. Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; +-----------------+
;;; | eax = 1234 5678 |
;;; | ebx = 55FF 55FF |
;;; | ecx = FEDC BA98 |
;;; | edx = 0000 0000 |
;;; | esi = 1111 2222 |
;;; | edi = 2222 3333 |
;;; +-----------------+
;;; +-----------------+
;;; | eax = 1234 5678 |
;;; | ebx = 55FF 55FF |
;;; | ecx = FEDC BA98 |
;;; | edx = 0000 0000 |
;;; | esi = 1111 2222 |
;;; | edi = 2222 3333 |
;;; +-----------------+
;;;
;;; To assemble, link and run:
;;; nasm -f elf hw8aSol.asm
;;; ld -melf_i386 hw8aSol.o -o hw8aSol
;;; ./hw8aSol
;;; ---------------------------------------------------------
section .data
hex db "0123456789ABCDEF"
regs db "axbxcxdxsidi"
line db "+-----------------+", 10
string db "| exx = .... .... |", 10
lineLen equ $-string
reg equ string+3
word1 equ string+8
section .text
global _start
_start:
;;; Initialize the registers
mov eax, 0x12345678
mov ebx, 0x55FF55FF
mov ecx, 0xFEDCBA98
mov edx, 0x00000000
mov esi, 0x11112222
mov edi, 0x22223333
;;; dump them twice to verify that no registers gets modified...
call dumpRegs
call dumpRegs
;;; exit back to OS
mov ebx, 0
mov eax, 1
int 0x80
;;; ---------------------------------------------------------
;;; dumpRegs: dumps the contents of the 6 main registers (eax
;;; ebx, ecx, edx, esi and edi) in a box on the screen.
;;; the screen. Does not modify any register
;;; ---------------------------------------------------------
dumpRegs: pushad
;;; put all the registers to print in the stack. The loop
;;; will pop each one, one at a time, once per loop.
push edi
push esi
push edx
push ecx
push ebx
push eax
;;; print top bar
call printBar
;;; prepare to loop 6 times (6 registers )
mov ecx, 6
mov esi, 0
.for pop ebx ;get value of register to convert from stack
push ecx ;save loop counter
lea eax, [regs + esi*2] ;get address of string representing register
mov ax, word [eax] ;ax gets "ax" or "bx" or "cx" or ... "di"
mov word[reg], ax ;modify string with name of register
mov edx, word1 ;edx points to buffer where to store hex digits
;ebx contains register to convert
call storeDWord ;store hex equivalent of ebx in string
mov ecx, string ;print the whole string
mov edx, lineLen
call printInt80
inc esi ;index into register names incremented
pop ecx ;get loop counter back
loop .for
;;; print bottom bar
call printBar
popad
ret
;;; ---------------------------------------------------------
;;; storeDWord: gets
;;; ebx: register to convert
;;; edx: address where to put information
;;; ---------------------------------------------------------
storeDWord: rol ebx, 16 ;bring most sig word in least sig word
call storeWord
inc edx ;make edx skip space in string
rol ebx, 16 ;get lower byte back in least sig pos
call storeWord
ret
;;; ---------------------------------------------------------
;;; storeWord: gets
;;; bx: word to convert
;;; edx: address where to put information. edx incremented by 4
;;; ---------------------------------------------------------
storeWord: rol bx, 8 ;put most sig byte of bx in lower position
call storeByte ;and convert it. Store it in where edx
;points to.
rol bx, 8 ;same with lower nybble
call storeByte
ret
;;; ---------------------------------------------------------
;;; storeByte: gets
;;; bl: byte to convert
;;; edx: address where to store information. edx incremented by 2 automatically
;;; ---------------------------------------------------------
storeByte: push ebx
push eax
rol bl, 4 ;get upper nybble in lower position (LSB)
mov al, bl ;play with al now
and eax, 0x0000000F ;clear all but the least significant nybble
add eax, hex ;get ascii in hex array equivalentn to nybble
mov al, [eax] ;hex digit now in bl
mov byte [edx], al ;store ascii in string
inc edx
rol bl, 4 ;get lower nybble back
mov al, bl ;play with al
and eax, 0x0000000F
add eax, hex
mov al, [eax]
mov byte [edx], al
inc edx
pop eax
pop ebx
ret
;;; ---------------------------------------------------------
;;; printInt80: prints on the screen the string whose address
;;; is in ecx and length in edx.
;;; does not modify registers
;;; ---------------------------------------------------------
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
;;; ---------------------------------------------------------
;;; printBar: prints the horizontal bar
;;; does not modify registers
;;; ---------------------------------------------------------
printBar: push ecx
push edx
mov ecx, line
mov edx, lineLen
call printInt80
pop edx
pop ecx
ret
Problem #1, Version 2
Main Program
;;; ---------------------------------------------------------
;;; hw8aSol2.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This program uses the library dumpRegs.asm to dump
;;; the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen. Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; +-----------------+
;;; | eax = 1234 5678 |
;;; | ebx = 55FF 55FF |
;;; | ecx = FEDC BA98 |
;;; | edx = 0000 0000 |
;;; | esi = 1111 2222 |
;;; | edi = 2222 3333 |
;;; +-----------------+
;;; +-----------------+
;;; | eax = 1234 5678 |
;;; | ebx = 55FF 55FF |
;;; | ecx = FEDC BA98 |
;;; | edx = 0000 0000 |
;;; | esi = 1111 2222 |
;;; | edi = 2222 3333 |
;;; +-----------------+
;;;
;;; To assemble, link and run:
;;; nasm -f elf hw8aSol.asm
;;; ld -melf_i386 hw8aSol.o -o hw8aSol
;;; ./hw8aSol
;;; ---------------------------------------------------------
%include "dumpRegs.asm"
section .text
global _start
_start:
;;; Initialize the registers
mov eax, 0x12345678
mov ebx, 0x55FF55FF
mov ecx, 0xFEDCBA98
mov edx, 0x00000000
mov esi, 0x11112222
mov edi, 0x22223333
;;; dump them twice to verify that no registers gets modified...
call dumpRegs
call dumpRegs
;;; exit back to OS
mov ebx, 0
mov eax, 1
int 0x80
Library
;;; ---------------------------------------------------------
;;; dumpRegs.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This libary supports several functions that allow the user
;;; to dump the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen. Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; +-----------------+
;;; | eax = 1234 5678 |
;;; | ebx = 55FF 55FF |
;;; | ecx = FEDC BA98 |
;;; | edx = 0000 0000 |
;;; | esi = 1111 2222 |
;;; | edi = 2222 3333 |
;;; +-----------------+
;;; Include in program as follows:
;;;
;;;
;;; %include "dumpRegs.asm"
;;; ---------------------------------------------------------
section .data
hex db "0123456789ABCDEF"
regs db "axbxcxdxsidi"
line db "+-----------------+", 10
string db "| exx = .... .... |", 10
lineLen equ $-string
reg equ string+3
word1 equ string+8
section .text
;;; ---------------------------------------------------------
;;; dumpRegs: dumps the contents of the 6 main registers (eax
;;; ebx, ecx, edx, esi and edi) in a box on the screen.
;;; the screen. Does not modify any register
;;; ---------------------------------------------------------
dumpRegs: pushad
;;; put all the registers to print in the stack. The loop
;;; will pop each one, one at a time, once per loop.
push edi
push esi
push edx
push ecx
push ebx
push eax
;;; print top bar
call printBar
;;; prepare to loop 6 times (6 registers )
mov ecx, 6
mov esi, 0
.for pop ebx ;get value of register to convert from stack
push ecx ;save loop counter
lea eax, [regs + esi*2] ;get address of string representing register
mov ax, word [eax] ;ax gets "ax" or "bx" or "cx" or ... "di"
mov word[reg], ax ;modify string with name of register
mov edx, word1 ;edx points to buffer where to store hex digits
;ebx contains register to convert
call storeDWord ;store hex equivalent of ebx in string
mov ecx, string ;print the whole string
mov edx, lineLen
call printInt80
inc esi ;index into register names incremented
pop ecx ;get loop counter back
loop .for
;;; print bottom bar
call printBar
popad
ret
;;; ---------------------------------------------------------
;;; storeDWord: gets
;;; ebx: register to convert
;;; edx: address where to put information
;;; ---------------------------------------------------------
storeDWord: rol ebx, 16 ;bring most sig word in least sig word
call storeWord
inc edx ;make edx skip space in string
rol ebx, 16 ;get lower byte back in least sig pos
call storeWord
ret
;;; ---------------------------------------------------------
;;; storeWord: gets
;;; bx: word to convert
;;; edx: address where to put information. edx incremented by 4
;;; ---------------------------------------------------------
storeWord: rol bx, 8 ;put most sig byte of bx in lower position
call storeByte ;and convert it. Store it in where edx
;points to.
rol bx, 8 ;same with lower nybble
call storeByte
ret
;;; ---------------------------------------------------------
;;; storeByte: gets
;;; bl: byte to convert
;;; edx: address where to store information. edx incremented by 2 automatically
;;; ---------------------------------------------------------
storeByte: push ebx
push eax
rol bl, 4 ;get upper nybble in lower position (LSB)
mov al, bl ;play with al now
and eax, 0x0000000F ;clear all but the least significant nybble
add eax, hex ;get ascii in hex array equivalentn to nybble
mov al, [eax] ;hex digit now in bl
mov byte [edx], al ;store ascii in string
inc edx
rol bl, 4 ;get lower nybble back
mov al, bl ;play with al
and eax, 0x0000000F
add eax, hex
mov al, [eax]
mov byte [edx], al
inc edx
pop eax
pop ebx
ret
;;; ---------------------------------------------------------
;;; printInt80: prints on the screen the string whose address
;;; is in ecx and length in edx.
;;; does not modify registers
;;; ---------------------------------------------------------
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
;;; ---------------------------------------------------------
;;; printBar: prints the horizontal bar
;;; does not modify registers
;;; ---------------------------------------------------------
printBar: push ecx
push edx
mov ecx, line
mov edx, lineLen
call printInt80
pop edx
pop ecx
ret
Problem #2
;;; File: hw8b.asm
;;; Name: Emma Gould (edited by D. Thiebaut)
;;; Account: 231a-ap
;;; Due: 11/7/12
;;; Description: This program computes and displays the first 10 rows of Pascal's triangle.
;;; 01 00 00 00 00 00 00 00 00 00
;;; 01 01 00 00 00 00 00 00 00 00
;;; 01 02 01 00 00 00 00 00 00 00
;;; 01 03 03 01 00 00 00 00 00 00
;;; 01 04 06 04 01 00 00 00 00 00
;;; 01 05 0A 0A 05 01 00 00 00 00
;;; 01 06 0F 14 0F 06 01 00 00 00
;;; 01 07 15 23 23 15 07 01 00 00
;;; 01 08 1C 38 46 38 1C 08 01 00
;;; 01 09 24 54 7E 7E 54 24 09 01
;;;
;;; To assemble, link, and run: nasm -f elf -F stabs hw8b.asm ; ld -melf_i386 -o hw8b hw8b.o ; ./hw8b
;; -------------------------------
;; Data Section
;; -------------------------------
section .data
Pascal db 0,0,0,0,0,0,0,0,0,0 ; Pascal array of 10 bytes
hexChars db "0123456789ABCDEF" ; list of hex characters
hexCharLen equ 1 ; length of a single character
notation db "0x" ; hex character notation
notationLen equ $-notation ; length of hex character notation
space db " " ; to space the characters of the array
spaceLen equ $-space ; length of space
newLine db 10 ; hex characters for new line
newLineLen equ $-newLine ; length of newLine
;; -------------------------------
;; Code Section
;; -------------------------------
section .text
global _start
;; -------------------------------
;; main program
;; -------------------------------
_start:
mov ebx, Pascal ; pass address of array in ebx
call init ; store 0 in Pascal array
; and 1 in first cell
mov ecx, 10
for: mov ebx, Pascal ; pass address of array in ebx
call printArray ; print Pascal array
mov ebx, Pascal ; pass address of array
call nextLine ; compute next line of triangle
loop for
;;; exit
mov eax, 1
mov ebx, 0
int 0x80
;; -------------------------------
;; function init takes the address
;; in ebx and puts one in the first byte
;; at that address and zero in the other nine
;; bytes that follow
;; -------------------------------
init:
mov byte[ebx], 1 ; move 1 into the first cell
mov edi, 1 ; edi <- index = 1
mov ecx, 9 ; ecx <- n = 9
for1: mov byte[ebx+edi], 0 ; Fib[n] <- 0
inc edi ; index <- index + 1
loop for1 ; n <- n - 1
ret
;; -------------------------------
;; function printArray takes the address
;; in ebx and prints it a byte at a time
;; in hexadecimal (by passing it to printByte)
;; between the string "0x" and three spaces
;; with a new line at the very beginning and end
;; -------------------------------
printArray:
push ecx ; save ecx from main program
call printNewLine
mov ecx, 10 ; n = 10
for3:
push ecx ; save n
push ebx ; save address of Pascal array
mov ecx, notation ; ecx <- address of "0x"
mov edx, notationLen ; edx <- length of "0x"
mov eax, 4 ; print "0x"
mov ebx, 1
int 0x80
pop ebx ; ebx <- address of Pascal array (from stack)
pop ecx ; ecx <- n (from stack)
mov edi, 10 ; edi <- 10
sub edi, ecx ; edi <- 10 - n
mov eax, 0 ; eax <- 0 (initialize)
mov al, byte[ebx+edi] ; al <- Pascal[10 - n]
push ecx ; save n
push ebx ; save address of Pascal array
call printByte ; print the byte in al in hexadecimal
mov ecx, space ; ecx <- address of tab
mov edx, spaceLen ; edx <- length of tab
mov eax, 4 ; print " "
mov ebx, 1
int 0x80
pop ebx ; ebx <- return address of Pascal array (from stack)
pop ecx ; ecx <- n (returned from stack)
loop for3 ; n <- n - 1
call printNewLine
pop ecx ; ecx <- restore value from main program
ret
;; -------------------------------
;; function printNewLine takes no
;; parameters and simply prints a new line
;; -------------------------------
printNewLine:
push ebx
push ecx
mov eax, 4
mov ebx, 1
mov ecx, newLine
mov edx, newLineLen
int 0x80
pop ecx
pop ebx
ret
;; -------------------------------
;; function printByte takes the value
;; stored in eax and print the two nybbles
;; (most significant first) in al
;; -------------------------------
printByte:
rol al, 4 ; move most significant nybble to least
push eax ; save eax in stack
and eax, 0x0000000F ; get rid of upper nybble
mov ecx, hexChars ; ecx <- address of hexChars
add ecx, eax ; ecx <- address of hexChars + value of nybble
mov edx, hexCharLen ; edx <- length of a single character
mov eax, 4 ; print the character
mov ebx, 1
int 0x80
pop eax ; eax <- full hex value (from stack)
rol al, 4 ; move lower nybble back to least significant
and eax, 0x0000000F ; get rid of upper nybble
mov ecx, hexChars ; ecx <- address of hexChars
add ecx, eax ; ecx <- address of hexChars + value of nybble
mov edx, hexCharLen ; edx <- length of a single character
mov eax, 4 ; print the character
mov ebx, 1
int 0x80
ret
;; -------------------------------
;; function nextLine uses the address stored in ebx
;; to compute the next row of pascal's triangle
;; and stores it in the Pascal array
;; -------------------------------
nextLine: push ecx
mov ecx, 9 ; ecx <- m = 9 (length of array - 1)
mov edi, 9 ; edi <- n = 9 (length of array - 1)
for4: mov al, byte[ebx+edi] ; al <- Pascal[n] (starting at the rightmost
; number and working left)
add al, byte[ebx+edi-1] ; al <- Pascal[n-1]
mov byte[ebx+edi], al ; Fib[n] <- al
dec edi ; n = n - 1
loop for4 ; m = m - 1
pop ecx
ret