CSC231 Top-Down Design Example
--D. Thiebaut 10:53, 4 November 2012 (EST)
Evolution of a program through the top-down design approach. The problem is given this data structure:
strings db 5, "Hello" db 6, "Sharon" db 7, "Pamela!"
write a program that prints all strings (preceded by the number of chars they contain) in a box of stars.
Version 1
;;; towDown.asm
;;; only the main program is expanded here.
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
section .text
global _start
_start:
mov eax, strings+0 ; eax <- address count+string
call printBoxName
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
mov al, byte[eax] ;al contains 5
call printStars
ret
;;; ----------------------------------------------------------------------
;;; printStars
printStars:
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
ret
Version 2
;;; towDown.asm
;;; in this version we expand printName
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
section .text
global _start
_start:
mov eax, strings+0 ; eax <- address count+string
call printBoxName
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
mov al, byte[eax] ;al contains 5
call printStars
ret
;;; ----------------------------------------------------------------------
;;; printStars
printStars:
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
mov eax, 4
mov ebx, 1
int 0x80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
Version 3
;;; towDown.asm
;;; in this version we modify printName and add printInt80
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
section .text
global _start
_start:
mov eax, strings+0 ; eax <- address count+string
call printBoxName
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
mov al, byte[eax] ;al contains 5
call printStars
ret
;;; ----------------------------------------------------------------------
;;; printStars
printStars:
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
call printInt80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printInt80
;;; gets the address and # of chars to print in ecx and edx.
;;; maintains eax and ebx.
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
Version 4
;;; towDown.asm
;;; in this version we expand printStars and print a new-line after the name and the line of stars
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
oneStar db '* '
nl db 0x0a
section .text
global _start
_start:
mov eax, strings+0 ; eax <- address count+string
call printBoxName
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
mov al, byte[eax] ;al contains 5
call printStars
ret
;;; ----------------------------------------------------------------------
;;; printStars
;;; gets the number of stars to print in al
;;; maintains all the other registers
printStars:
push eax
push ecx
push edx
mov ecx, oneStar
mov edx, 1
for: call printInt80
dec al
jnz for
mov ecx, nl
call printInt80
pop edx
pop ecx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
call printInt80
mov ecx, nl
mov edx, 1
call printInt80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printInt80
;;; gets the address and # of chars to print in ecx and edx.
;;; maintains eax and ebx.
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
Version 5
;;; towDown.asm
;;; in this version we modify the functions to print extra stars to form a box
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
oneSpace db ' '
oneStar db '*'
nl db 0x0a
section .text
global _start
_start:
mov eax, strings+0 ; eax <- address count+string
call printBoxName
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
mov al, byte[eax] ;al contains 5
call printStars
ret
;;; ----------------------------------------------------------------------
;;; printStars
;;; gets the number of stars to print in al
;;; maintains all the other registers
printStars:
push eax
push ecx
push edx
add al, 2+2 ; add 2 stars in front and back
mov ecx, oneStar
mov edx, 1 ; print 1 start
for: call printInt80
dec al
jnz for
mov ecx, nl
call printInt80
pop edx
pop ecx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, nl ; go to the next line
mov edx, 1
call printInt80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printInt80
;;; gets the address and # of chars to print in ecx and edx.
;;; maintains eax and ebx.
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
Version 6
;;; towDown.asm
;;; in this version we create a loop to print all the boxed names.
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
oneSpace db ' '
oneStar db '*'
nl db 0x0a
section .text
global _start
_start:
mov ecx, 3
mov eax, strings+0 ; eax <- address count+string
.for: call printBoxName
mov bl, byte[eax] ; bl gets # bytes
and ebx, 0x000000ff ; extend bl in ebx
inc ebx ; add 1 for byte containing #
add eax, ebx ; make eax point to next string
loop .for
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
push eax
mov al, byte[eax] ;al contains 5
call printStars
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printStars
;;; gets the number of stars to print in al
;;; maintains all the other registers
printStars:
push eax
push ecx
push edx
add al, 2+2 ; add 2 stars in front and back
mov ecx, oneStar
mov edx, 1 ; print 1 start
.for: call printInt80
dec al
jnz .for
mov ecx, nl
call printInt80
pop edx
pop ecx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, nl ; go to the next line
mov edx, 1
call printInt80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printInt80
;;; gets the address and # of chars to print in ecx and edx.
;;; maintains eax and ebx.
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret
Version 7
;;; towDown.asm
;;; in this version we clean up the code.
section .data
strings db 5, "Hello"
db 6, "Sharon"
db 7, "Pamela!"
oneSpace db ' '
oneStar db '*'
nl db 0x0a
section .text
global _start
_start:
mov ecx, 3
mov eax, strings+0 ; eax <- address count+string
.for: call printBoxName
mov bl, byte[eax] ; bl gets # bytes
and ebx, 0x000000ff ; extend bl in ebx
inc ebx ; add 1 for byte containing #
add eax, ebx ; make eax point to next string
loop .for
;;; exit
mov ebx, 0
mov eax, 1
int 0x80
;;; ----------------------------------------------------------------------
;;; printBoxName
printBoxName: push ecx
push edx
push eax ;eax contains address of 5
mov al,byte[eax] ;al contains 5
call printStars
pop eax ;address of 5
push eax ;put the address of 5 back in stack
call printName
pop eax ;get back address of 5
push eax
mov al, byte[eax] ;al contains 5
call printStars
mov ecx, nl ;print extra nl char
mov edx, 1
call printInt80
pop eax
pop edx
pop ecx
ret
;;; ----------------------------------------------------------------------
;;; printStars
;;; gets the number of stars to print in al
;;; maintains all the other registers
printStars:
push eax
push ecx
push edx
add al, 2+2 ; add 2 stars in front and back
mov ecx, oneStar
mov edx, 1 ; print 1 start
.for: call printInt80
dec al
jnz .for
mov ecx, nl
call printInt80
pop edx
pop ecx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printName
;;; gets the address of the byte containing the number of chars to print
;;; in eax. address of string is at eax+1
;;; Does not modify any registers.
printName:
push eax ; save registers
push ebx
push ecx
push edx
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov dl, byte[eax] ;get # chars in dl
and edx,0x000000ff ;clear upper part of edx (not dl)
inc eax ;eax points to string
mov ecx, eax ;ecx points to string
call printInt80
mov ecx, oneSpace ; print ' '
mov edx, 1
call printInt80
mov ecx, oneStar ; print '*'
mov edx, 1
call printInt80
mov ecx, nl ; go to the next line
mov edx, 1
call printInt80
pop edx ;restore the registers
pop ecx
pop ebx
pop eax
ret
;;; ----------------------------------------------------------------------
;;; printInt80
;;; gets the address and # of chars to print in ecx and edx.
;;; maintains eax and ebx.
printInt80: push eax
push ebx
mov eax, 4
mov ebx, 1
int 0x80
pop ebx
pop eax
ret