Difference between revisions of "CSC231 Homework 2 2017"

From dftwiki3
Jump to: navigation, search
(231Lib.asm)
 
(6 intermediate revisions by the same user not shown)
Line 24: Line 24:
 
  cp hw2_skel.asm hw2.asm
 
  cp hw2_skel.asm hw2.asm
 
   
 
   
You should now have a new file called hw2.asm in your directory, and a library file called 231Lib.asm as well.  The library file will help us get input from the keyboard, and print strings.   
+
You should now have a new file called hw2.asm in your directory, and another file called 231Lib.asm.  231Lib.asm is a library we will use to print and input decimal numbers.  The library file will help us get input from the keyboard, and print strings.  <font code="magenta">You do not need to understand the code in 231Lib.asm in order to use it!</font>
  
 
The hw2.asm file is just a skeleton and you will need to add code to it to solve this problem.  For right now, just assemble and link it to the new library, and run it:
 
The hw2.asm file is just a skeleton and you will need to add code to it to solve this problem.  For right now, just assemble and link it to the new library, and run it:
   
+
 
 +
nasm -f elf  hw2.asm  
 
  nasm -f elf  231Lib.asm
 
  nasm -f elf  231Lib.asm
ld -o hw2 hw2.o 231Lib.o
 
 
  ld -melf_i386 -o hw2 hw2.o 231Lib.o
 
  ld -melf_i386 -o hw2 hw2.o 231Lib.o
  
Line 37: Line 37:
 
Here's an example of what happens if I run the program and feed it 3 numbers: 1, 2, and 3 (user input underlined):
 
Here's an example of what happens if I run the program and feed it 3 numbers: 1, 2, and 3 (user input underlined):
 
   
 
   
  ./hw2
+
  <u>./hw2</u>
 
  > <u>1</u>
 
  > <u>1</u>
 
  > <u>2</u>
 
  > <u>2</u>
 
  > <u>3</u>
 
  > <u>3</u>
 
  ans = 0
 
  ans = 0
 +
 +
<br />
 +
==Your Assignment==
 +
<br />
 +
Modify hw2.asm and make it compute ans = 2*(a-b) + 3*c.
 +
 +
'''Note 1''': you will need to use the '''sub''' instruction, which works similarly to '''add''':
 +
 +
      sub      dest, source        ; dest <-- dest - source
 +
 +
'''Note 2''': Do not use the mul instruction.  It is too complicated for us to use now.  Instead, if you want to multiply something by two, just add that quantity twice.  In other words, if you want to compute 2*x, then simply compute x + x.  Similarly, when you need to compute 3*z, simply compute z + z + z.
 +
 +
You should add code '''only between the two box comments''' shown below:
 +
<br />
 +
::<source lang="asm">
 +
;; -----------------------------------
 +
;; computation: ans = 2*(a-b) + 3*c
 +
;; -----------------------------------
 +
 +
; your code will go here...
 +
  
 +
;; -----------------------------------
 +
;; display "ans ="
 +
;; -----------------------------------
 +
</source>
 +
<br />
  
 +
==Examples==
 +
<br />
 +
I ran my solution program a few times with different numbers.  Your program should behave exactly the same!
 +
<br />
 +
231b@aurora ~/hw/hw2 $ ./hw2
 +
> 3
 +
> 1
 +
> 10
 +
ans = 34
 +
 +
231b@aurora ~/hw/hw2 $ ./hw2
 +
> 10
 +
> 10
 +
> 0
 +
ans = 0
 +
 +
231b@aurora ~/hw/hw2 $ ./hw2
 +
> 1
 +
> 2
 +
> 3
 +
ans = 7
 
   
 
   
 
+
231b@aurora ~/hw/hw2 $ ./hw2
 +
> 10
 +
> 0
 +
> 10
 +
ans = 50
 +
 +
==Submission==
 +
<br />
 +
Submit your program on Moodle, in the Problem 2 section.
 +
<br />
 +
<br />
 
<br />
 
<br />
 
<br />
 
<br />
 
<br />
 
<br />
 
<br />
 
<br />
 +
 +
=Assembly File=
 
<br />
 
<br />
 +
Below are the two files used in Problem 2, for reference.
 
<br />
 
<br />
 +
==hw2.asm==
 
<br />
 
<br />
 +
::<source lang="asm">
 +
;;; hw2.asm
 +
;;; put your name here
 +
;;; describe what the program does
 +
;;; explain how to assemble and run it.
 +
 +
 +
        extern  _printDec
 +
        extern  _printString
 +
        extern  _println
 +
        extern  _getInput
 +
 +
section .data
 +
prompt db "> "
 +
promptLen equ $-prompt
 +
ansStr          db      "ans = "
 +
ansStrLen equ $-ansStr
 +
 +
a dd 0
 +
b dd 0
 +
c dd 0
 +
ans dd 0
 +
 +
section .text
 +
global _start
 +
_start:
 +
;; display prompt
 +
mov ecx, prompt
 +
mov edx, promptLen
 +
call _printString
 +
;; get a
 +
call _getInput
 +
mov dword[a], eax
 +
 +
;; display prompt
 +
mov ecx, prompt
 +
mov edx, promptLen
 +
call _printString
 +
;; get b
 +
call _getInput
 +
mov dword[b], eax
 +
 +
;; display prompt
 +
mov ecx, prompt
 +
mov edx, promptLen
 +
call _printString
 +
;; get c
 +
call _getInput
 +
mov dword[c], eax
 +
 +
;; -----------------------------------
 +
;; computation: ans = 2*(a-b) + 3*c
 +
;; -----------------------------------
 +
 +
; your code will go here...
 +
 +
 +
;; -----------------------------------
 +
;; display "ans ="
 +
;; -----------------------------------
 +
mov ecx, ansStr
 +
mov edx, ansStrLen
 +
call _printString
 +
 +
;; -----------------------------------
 +
;; display ans variable
 +
;; -----------------------------------
 +
mov eax, dword[ans]
 +
call _printDec
 +
call _println
 +
call _println
 +
 +
;;; exit
 +
mov ebx, 0
 +
mov eax, 1
 +
int    0x80
 +
 +
</source>
 
<br />
 
<br />
 +
==231Lib.asm==
 
<br />
 
<br />
 +
::<source lang="asm">
 +
cs231a@aurora ~/HWs/HW1/pb2 $ cat  ~/handout_231b/231Lib.asm
 +
;;; 231Lib.asm
 +
;;; A simple I/O library for CSC231.
 +
;;; will be expanded as needed.
 +
;;;
 +
;;; D. Thiebaut
 +
;;; Adapted from Swarnali Ahmed's 2002 program: mytools.inc
 +
;;; http://cs.smith.edu/dftwiki
 +
;;;
 +
;;; Contains several functions for performing simple I/O of
 +
;;; data.
 +
;;; _printDec: function that prints an integer on the screen
 +
;;; _printString: function that prints a string on the screen
 +
;;; _println: moves the cursor to the next line on the screen
 +
;;; _getInput: gets a possibly signed integer from the keyboard
 +
;;;
 +
;;; Version 2.  Sept 22, 2014.
 +
;;;      - updated _getInput to get only 1 char at at time.
 +
;;;      - now works with pipes     
 +
;;; Version 1.  Sept 21, 2014.
 +
;;;
 +
%assign SYS_EXIT        1
 +
%assign SYS_WRITE      4
 +
%assign STDOUT          1
 +
 +
global _atoi
 +
global  _printDec
 +
global  _printInt
 +
global  _printString
 +
global  _printCString
 +
global  _println
 +
global  _getInput
 +
global  _printRegs
 +
global  _printHex
 +
 +
       
 +
 +
        section        .text
 +
       
 +
   
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
;;; ; _atoi:    gets a numerical input in a 0-terminated string
 +
;;; ;         pointed to by eax.
 +
;;; ;          returns the resulting number in eax (32 bits).
 +
;;; ;          recognizes - as the first character of
 +
;;; ;          negative numbers.  Does not skip whitespace
 +
;;; ;          at the beginning.  Stops on first not decimal
 +
;;; ;          character encountered.
 +
;;; ;
 +
;;; ; NO REGISTERS MODIFIED, except eax
 +
;;; ;
 +
;;; ; Example of call:
 +
;;; ;
 +
;;; ;          call  getInput
 +
;;; ;          mov  dword[x], eax ; put integer in x
 +
;;; ;
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
_atoi:
 +
                section .bss
 +
intg2          resd    1
 +
isneg2          resb    1
 +
       
 +
                section .text
 +
                pushad                  ; save all registers
 +
 +
                mov    esi, eax        ; eci --> buffer
 +
                mov    ecx, 0          ; edi = counter of chars
 +
.count: cmp byte[esi], 0 ; '\0'?
 +
je .parse
 +
inc esi
 +
inc ecx
 +
jmp .count
 +
.parse:
 +
                mov    esi, eax        ; esi --> buffer
 +
                mov    ecx, edi        ; loop for all chars received
 +
                mov    dword[intg2], 0
 +
                mov    byte[isneg2], 0
 +
 +
.negativ:     
 +
                cmp    byte[esi], '-'
 +
                jne    .loop
 +
                inc    byte[isneg2]
 +
       
 +
.loop:          mov    ebx, 0
 +
                mov    bl, byte[esi]
 +
 +
                ;; stop on line feed
 +
                cmp    bl, 0 ; '\0'?
 +
                je      .done
 +
 +
                ;; stop on non-digit characters
 +
                cmp    bl, '0'
 +
                jb      .done
 +
                cmp    bl, '9'
 +
                ja      .done
 +
       
 +
                ;; bl is a digit...  multiply .int by 10 first
 +
                mov    edx, 10
 +
                mov    eax, dword[intg2]
 +
                mul    edx            ; edx:eax <-- 10 * .int
 +
               
 +
                ;; add int version of char
 +
                sub    bl, '0'
 +
                add    eax, ebx
 +
                mov    dword[intg2], eax
 +
                inc    esi
 +
                loop    .loop
 +
.done:
 +
                ;; if negative, make eax neg
 +
                cmp    byte[isneg2], 0
 +
                je      .return
 +
                neg    eax
 +
                mov    dword [intg2], eax
 +
       
 +
                ;; restore registers and return result in eax
 +
.return:
 +
 +
                popad
 +
                mov    eax, [intg2]
 +
                ret
 +
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
;;; ; getInput: gets a numerical input from the keyboard.
 +
;;; ;          returns the resulting number in eax (32 bits).
 +
;;; ;          recognizes - as the first character of
 +
;;; ;          negative numbers.  Does not skip whitespace
 +
;;; ;          at the beginning.  Stops on first not decimal
 +
;;; ;          character encountered.
 +
;;; ;
 +
;;; ; NO REGISTERS MODIFIED, except eax
 +
;;; ;
 +
;;; ; Example of call:
 +
;;; ;
 +
;;; ;          call  getInput
 +
;;; ;          mov  dword[x], eax ; put integer in x
 +
;;; ;
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
_getInput:
 +
                section .bss
 +
buffer          resb    120
 +
intg            resd    1
 +
isneg          resb    1
 +
       
 +
                section .text
 +
                pushad                  ; save all registers
 +
 +
                mov    esi, buffer    ; eci --> buffer
 +
                mov    edi, 0          ; edi = counter of chars
 +
.loop1:       
 +
                mov    eax, 03        ; input
 +
                mov    ebx, 0          ; stdin
 +
                mov    ecx, esi        ; where to put the next char
 +
                mov    edx, 1          ; one char at a time
 +
                int    0x80            ; get the input into buffer
 +
 +
                cmp    byte[esi], 0    ; EOF?
 +
                je      .parse
 +
                cmp    byte[esi], 10  ; line feed?
 +
                je      .parse
 +
                inc    esi            ; point to next cell
 +
                inc    edi            ; increment char counter
 +
                jmp    .loop1
 +
 +
.parse:
 +
                mov    esi, buffer    ; esi --> buffer
 +
                mov    ecx, edi        ; loop for all chars received
 +
                mov    dword[intg], 0
 +
                mov    byte[isneg], 0
 +
 +
.negativ:     
 +
                cmp    byte[esi], '-'
 +
                jne    .loop
 +
                inc    byte[isneg]
 +
       
 +
.loop:          mov    ebx, 0
 +
                mov    bl, byte[esi]
 +
 +
                ;; stop on line feed
 +
                cmp    bl, 10          ; line feed?
 +
                je      .done
 +
 +
                ;; stop on non-digit characters
 +
                cmp    bl, '0'
 +
                jb      .done
 +
                cmp    bl, '9'
 +
                ja      .done
 +
       
 +
                ;; bl is a digit...  multiply .int by 10 first
 +
                mov    edx, 10
 +
                mov    eax, dword[intg]
 +
                mul    edx            ; edx:eax <-- 10 * .int
 +
               
 +
                ;; add int version of char
 +
                sub    bl, '0'
 +
                add    eax, ebx
 +
                mov    dword[intg], eax
 +
                inc    esi
 +
                loop    .loop
 +
.done:
 +
                ;; if negative, make eax neg
 +
                cmp    byte[isneg], 0
 +
                je      .return
 +
                neg    eax
 +
                mov    dword [intg], eax
 +
       
 +
                ;; restore registers and return result in eax
 +
.return:
 +
 +
                popad
 +
                mov    eax, [intg]
 +
                ret   
 +
       
 +
       
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
;;; ; _printDec: takes the double word in eax and prints it
 +
;;; ; to STDOUT in decimal.
 +
;;; ;
 +
;;; ; Examples:
 +
;;; ; print a byte variable
 +
;;; ;          mov    eax, 0
 +
;;; ;          mov    al, byte[someVar]
 +
;;; ;          call    _printDec
 +
;;; ;
 +
;;; ; print a word variable
 +
;;; ;          mov    eax
 +
;;; ;          mov    ax, word[otherVar]
 +
;;; ;          call    _printDec
 +
;;; ;
 +
;;; ; print a double-word variable
 +
;;; ;          mov    eax, dword[thirdVar]
 +
;;; ;          call    _printDec
 +
;;; ;
 +
;;; ; print register edx in decimal
 +
;;; ;
 +
;;; ;          mov    eax, edx
 +
;;; ;          call    _printDec
 +
;;; ;
 +
;;; ;REGISTERS MODIFIED: NONE
 +
;;; ;------------------------------------------------------
 +
;;; ;------------------------------------------------------
 +
 +
_printDec:
 +
;;; saves all the registers so that they are not changed by the function
 +
 +
                section        .bss
 +
.decstr        resb            10
 +
.ct1            resd            1  ; to keep track of the size of the string
 +
 +
                section .text
 +
                pushad                          ; save all registers
 +
 +
                mov            dword[.ct1],0  ; assume initially 0
 +
                mov            edi,.decstr    ; edi points to decstring
 +
                add            edi,9          ; moved to the last element of string
 +
                xor            edx,edx        ; clear edx for 64-bit division
 +
.whileNotZero:
 +
                mov            ebx,10          ; get ready to divide by 10
 +
                div            ebx            ; divide by 10
 +
                add            edx,'0'        ; converts to ascii char
 +
                mov            byte[edi],dl    ; put it in sring
 +
                dec            edi            ; mov to next char in string
 +
                inc            dword[.ct1]    ; increment char counter
 +
                xor            edx,edx        ; clear edx
 +
                cmp            eax,0          ; is remainder of division 0?
 +
                jne            .whileNotZero  ; no, keep on looping
 +
 +
                inc            edi            ; conversion, finish, bring edi
 +
                mov            ecx, edi        ; back to beg of string. make ecx
 +
                mov            edx, [.ct1]    ; point to it, and edx gets # chars
 +
                mov            eax, SYS_WRITE  ; and print!
 +
                mov            ebx, STDOUT
 +
                int            0x80
 +
 +
                popad                          ; restore all registers
 +
 +
                ret
 +
       
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _printString:        prints a string whose address is in
 +
;;; ;                      ecx, and whose total number of chars
 +
;;; ;                      is in edx.
 +
;;; ; Examples:
 +
;;; ; Assume a string labeled msg, containing "Hello World!",
 +
;;; ; and a constant MSGLEN equal to 12.  To print this string:
 +
;;; ;
 +
;;; ;          mov        ecx, msg
 +
;;; ;          mov        edx, MSGLEN
 +
;;; ;          call      _printSTring
 +
;;; ;
 +
;;; ; REGISTERS MODIFIED:  NONE
 +
;;; ; ------------------------------------------------------------
 +
 +
;;; ;save eax and ebx so that it is not modified by the function
 +
 +
_printString:
 +
                push            eax
 +
                push            ebx
 +
       
 +
                mov            eax,SYS_WRITE
 +
                mov            ebx,STDOUT
 +
                int            0x80
 +
 +
                pop            ebx
 +
                pop            eax
 +
                ret
 +
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _printCString:      prints a string whose address is in
 +
;;; ;                      ecx, and which is 0-terminated, like
 +
;;; ;   C strings.
 +
;;; ; Examples:
 +
;;; ; Assume a string labeled msg, containing "Hello World!",
 +
;;; ; and a constant MSGLEN equal to 12.  To print this string:
 +
;;; ;
 +
;;; ;          mov        ecx, msg    ;there's a \0 somewher in msg
 +
;;; ;          call      _printCString
 +
;;; ;
 +
;;; ; REGISTERS MODIFIED:  NONE
 +
;;; ; ------------------------------------------------------------
 +
 +
;;; ;save eax and ebx so that it is not modified by the function
 +
_printCString: push ebx
 +
push edx ; save regs
 +
mov ebx, ecx ; make ebx point to string
 +
mov edx, 0 ; count in edx
 +
.for: cmp byte[ebx], 0 ; '\0' found yet?
 +
je .done
 +
inc ebx ; no, point to next char
 +
inc edx ; add 1 to counter
 +
jmp .for
 +
 +
.done: call _printString
 +
pop edx
 +
pop ebx
 +
ret
 +
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _println            put the cursor on the next line.
 +
;;; ;
 +
;;; ; Example:
 +
;;; ;          call      _println
 +
;;; ;
 +
;;; ; REGISTERS MODIFIED:  NONE
 +
;;; ; ------------------------------------------------------------
 +
_println: 
 +
                section .data
 +
.nl            db              10
 +
       
 +
                section .text
 +
                push            ecx
 +
                push            edx
 +
       
 +
                mov            ecx, .nl
 +
                mov            edx, 1
 +
                call            _printString
 +
 +
                pop            edx
 +
                pop            ecx
 +
                ret
 +
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _printHex: prints contents of eax in hexadecimal, uppercase.
 +
;;; ;            using 8 chars.
 +
;;; ; ------------------------------------------------------------
 +
                section .data
 +
table          db      "0123456789ABCDEF"
 +
hexString      db      "xxxxxxxx"
 +
tempEax        dd      0
 +
       
 +
                section .text
 +
_printHex:
 +
                pushad                  ; save all registers
 +
                mov    [tempEax], eax  ; save eax, as we are going to need it
 +
                                        ; several times, for all its digits
 +
                mov    ecx, 8          ; get ready to loop 8 times
 +
 +
        ;; get char equivalent to lower nybble of eax
 +
for:            and    eax, 0xF        ; isolate lower nybble of eax
 +
                add    eax, table      ; and translate it into ascii hex char
 +
                mov    bl, byte[eax]  ; bl <- ascii
 +
 +
        ;; make eax point to place where to put this digit in hexString
 +
                mov    eax, hexString  ; beginning of table
 +
                add    eax, ecx        ; add ecx to it, since ecx counts
 +
                dec    eax            ; but eax 1 too big, decrement it
 +
                mov    byte[eax], bl  ; store ascii char at right index in hexString
 +
 +
        ;; shift eax down by 4 bits by dividing it by 16
 +
                mov    ebx, 16        ; ready to shift down by 4 bits
 +
                mov    eax, [tempEax]  ; get eax back
 +
                div    ebx            ; shift down by 4
 +
                mov    [tempEax], eax  ; save again
 +
 +
                loop    for            ; and repeat, 8 times!
 +
       
 +
        ;; print the pattern in hexString, which contains 8 chars
 +
 +
                mov    ecx, hexString  ;
 +
                mov    edx, 8
 +
                call    _printString
 +
 +
                popad
 +
                ret
 +
         
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _printInt: prints the contents of eax as a 2's complement
 +
;;; ;            number.
 +
;;; ; ------------------------------------------------------------
 +
_printInt:      push    eax ; save the regs we are using
 +
                push    ecx
 +
                push    edx
 +
               
 +
        ;; check if msb is set
 +
                test    eax, 0x80000000
 +
                jz      positive
 +
neg eax
 +
                push    eax
 +
 +
;; the number is negative.  Print a minus sign and
 +
;; the positive equivalent of the number
 +
                mov    ecx, minus
 +
                mov    edx, 1
 +
                call    _printString
 +
                pop    eax
 +
               
 +
        ;; the number is positive, just print it.
 +
positive:      call    _printDec
 +
 +
                pop    edx
 +
                pop    ecx
 +
                pop    eax
 +
                ret
 +
 +
;;; ; ------------------------------------------------------------
 +
;;; ; printMinus, _printSpace: print a minus sign, and a plus sign.
 +
;;; ; ------------------------------------------------------------
 +
_printMinus:    push    ecx
 +
                push    edx
 +
                mov    ecx, minus
 +
                mov    edx, 1
 +
                call    _printString
 +
                pop    edx
 +
                pop    ecx
 +
                ret
 +
 +
_printSpace:    push    ecx
 +
                push    edx
 +
                mov    ecx, space
 +
                mov    edx, 1
 +
                call    _printString
 +
                pop    edx
 +
                pop    ecx
 +
                ret
 +
 +
;;; ; ------------------------------------------------------------
 +
;;; ; _printRegs: prints all the registers.
 +
;;; ; ------------------------------------------------------------
 +
                section .data
 +
minus          db      '-'
 +
space          db      ' '       
 +
eaxStr          db      'eax '
 +
ebxStr          db      'ebx '
 +
ecxStr          db      'ecx '
 +
edxStr          db      'edx '
 +
esiStr          db      'esi '
 +
ediStr          db      'edi '
 +
eaxTemp        dd      0
 +
ebxTemp        dd      0
 +
ecxTemp        dd      0
 +
edxTemp        dd      0
 +
esiTemp        dd      0
 +
ediTemp        dd      0
 +
                             
 +
                section .text
 +
_printRegs:    mov    [eaxTemp], eax
 +
                mov    [ebxTemp], ebx
 +
                mov    [ecxTemp], ecx
 +
                mov    [edxTemp], edx
 +
                mov    [ediTemp], edi
 +
                mov    [esiTemp], esi
 +
 +
pushad
 +
 +
        ;; print eax
 +
                mov    ecx, eaxStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
        ;; print ebx
 +
                mov    ecx, ebxStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                mov eax, [ebxTemp]
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
        ;; print ecx
 +
                mov    ecx, ecxStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                mov eax, [ecxTemp]
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
        ;; print edx
 +
                mov    ecx, edxStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                mov eax, [edxTemp]
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
        ;; print edi
 +
                mov    ecx, ediStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                mov eax, [ediTemp]
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
        ;; print esi
 +
                mov    ecx, esiStr
 +
                mov    edx, 4
 +
                call    _printString
 +
                mov eax, [esiTemp]
 +
                call    _printHex
 +
                call    _printSpace
 +
                call    _printDec
 +
                call    _printSpace
 +
                call    _printInt
 +
                call    _println
 +
 +
popad
 +
 +
                ret
 +
cs231a@aurora ~/HWs/HW1/pb2 $
 +
  
 +
</source>
  
 
<br />
 
<br />
 
[[Category:CSC231]][[Category:Homework]]
 
[[Category:CSC231]][[Category:Homework]]

Latest revision as of 13:38, 25 September 2017

--D. Thiebaut (talk) 16:14, 9 February 2017 (EST)




This assignment is due on 2/20/17 at 11:55 p.m.




Problem #1

Answer the quizzes in the Moodle Homework 2 section.

Problem #2


In your 231b-xx account on aurora, run the following commands:

getcopy 231Lib.asm
getcopy hw2_skel.asm
cp hw2_skel.asm hw2.asm

You should now have a new file called hw2.asm in your directory, and another file called 231Lib.asm. 231Lib.asm is a library we will use to print and input decimal numbers. The library file will help us get input from the keyboard, and print strings. You do not need to understand the code in 231Lib.asm in order to use it!

The hw2.asm file is just a skeleton and you will need to add code to it to solve this problem. For right now, just assemble and link it to the new library, and run it:

nasm -f elf  hw2.asm  
nasm -f elf  231Lib.asm
ld -melf_i386 -o hw2 hw2.o 231Lib.o


The program will prompt you for 3 integer numbers, which it will put into three 32-bit integers called a, b, and c in the data segment. It then takes the integer stored in a fourth variable called ans (for answer), and prints it. Since ans is initialized with 0, that's the number that gets printed.

Here's an example of what happens if I run the program and feed it 3 numbers: 1, 2, and 3 (user input underlined):

./hw2
> 1
> 2
> 3
ans = 0


Your Assignment


Modify hw2.asm and make it compute ans = 2*(a-b) + 3*c.

Note 1: you will need to use the sub instruction, which works similarly to add:

      sub       dest, source         ; dest <-- dest - source

Note 2: Do not use the mul instruction. It is too complicated for us to use now. Instead, if you want to multiply something by two, just add that quantity twice. In other words, if you want to compute 2*x, then simply compute x + x. Similarly, when you need to compute 3*z, simply compute z + z + z.

You should add code only between the two box comments shown below:

	;; -----------------------------------
	;; computation: ans = 2*(a-b) + 3*c
	;; -----------------------------------
	
	; your code will go here...
	

	;; -----------------------------------
	;; display "ans ="
	;; -----------------------------------


Examples


I ran my solution program a few times with different numbers. Your program should behave exactly the same!

231b@aurora ~/hw/hw2 $ ./hw2
> 3
> 1
> 10
ans = 34

231b@aurora ~/hw/hw2 $ ./hw2
> 10
> 10
> 0
ans = 0

231b@aurora ~/hw/hw2 $ ./hw2
> 1
> 2
> 3
ans = 7

231b@aurora ~/hw/hw2 $ ./hw2
> 10
> 0
> 10
ans = 50

Submission


Submit your program on Moodle, in the Problem 2 section.





Assembly File


Below are the two files used in Problem 2, for reference.

hw2.asm


;;; hw2.asm
;;; put your name here
;;; describe what the program does
;;; explain how to assemble and run it.


	        extern  _printDec
	        extern  _printString
	        extern  _println
	        extern  _getInput
	
	section	.data
prompt		db	"> "
promptLen	equ	$-prompt	
ansStr          db      "ans = "
ansStrLen	equ	$-ansStr	

a		dd	0
b		dd	0
c		dd	0
ans		dd	0
	
		section	.text
		global	_start
_start:
	;; display prompt
		mov	ecx, prompt
		mov	edx, promptLen
		call	_printString
	;; get a
		call	_getInput
		mov	dword[a], eax

	;; display prompt
		mov	ecx, prompt
		mov	edx, promptLen
		call	_printString
	;; get b
		call	_getInput
		mov	dword[b], eax
	
	;; display prompt
		mov	ecx, prompt
		mov	edx, promptLen
		call	_printString
	;; get c
		call	_getInput
		mov	dword[c], eax
	
	;; -----------------------------------
	;; computation: ans = 2*(a-b) + 3*c
	;; -----------------------------------
	
	; your code will go here...
	

	;; -----------------------------------
	;; display "ans ="
	;; -----------------------------------
		mov	ecx, ansStr
		mov	edx, ansStrLen
		call	_printString

	;; -----------------------------------
	;; display ans variable
	;; -----------------------------------
		mov	eax, dword[ans]
		call	_printDec
		call	_println
		call	_println
	
;;; exit
		mov	ebx, 0
		mov	eax, 1
		int     0x80


231Lib.asm


cs231a@aurora ~/HWs/HW1/pb2 $ cat  ~/handout_231b/231Lib.asm
;;; 231Lib.asm
;;; A simple I/O library for CSC231.
;;; will be expanded as needed.
;;;
;;; D. Thiebaut
;;; Adapted from Swarnali Ahmed's 2002 program: mytools.inc
;;; http://cs.smith.edu/dftwiki
;;;
;;; Contains several functions for performing simple I/O of
;;; data.
;;; _printDec: function that prints an integer on the screen
;;; _printString: function that prints a string on the screen
;;; _println: moves the cursor to the next line on the screen
;;; _getInput: gets a possibly signed integer from the keyboard
;;;
;;; Version 2.  Sept 22, 2014. 
;;;      - updated _getInput to get only 1 char at at time.
;;;      - now works with pipes       
;;; Version 1.  Sept 21, 2014.
;;; 
%assign SYS_EXIT        1
%assign SYS_WRITE       4
%assign STDOUT          1

global	_atoi	
global  _printDec
global  _printInt	
global  _printString
global  _printCString	
global  _println
global  _getInput
global  _printRegs
global  _printHex

        

        section         .text
        
     
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
;;; ; _atoi:    gets a numerical input in a 0-terminated string
;;; ;	        pointed to by eax.
;;; ;           returns the resulting number in eax (32 bits).
;;; ;           recognizes - as the first character of
;;; ;           negative numbers.  Does not skip whitespace
;;; ;           at the beginning.  Stops on first not decimal
;;; ;           character encountered.
;;; ;
;;; ; NO REGISTERS MODIFIED, except eax
;;; ;
;;; ; Example of call:
;;; ;
;;; ;          call  getInput
;;; ;          mov   dword[x], eax ; put integer in x
;;; ;
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
_atoi:	
                section .bss
intg2           resd    1
isneg2          resb    1
        
                section .text
                pushad                  ; save all registers

                mov     esi, eax        ; eci --> buffer
                mov     ecx, 0          ; edi = counter of chars
.count:		cmp	byte[esi], 0	; '\0'?
		je	.parse
		inc	esi
		inc	ecx
		jmp	.count
.parse:
                mov     esi, eax        ; esi --> buffer
                mov     ecx, edi        ; loop for all chars received
                mov     dword[intg2], 0
                mov     byte[isneg2], 0

.negativ:      
                cmp     byte[esi], '-'
                jne     .loop
                inc     byte[isneg2]
        
.loop:          mov     ebx, 0
                mov     bl, byte[esi]

                ;; stop on line feed
                cmp     bl, 0		; '\0'?
                je      .done

                ;; stop on non-digit characters
                cmp     bl, '0'
                jb      .done
                cmp     bl, '9'
                ja      .done
        
                ;; bl is a digit...  multiply .int by 10 first
                mov     edx, 10
                mov     eax, dword[intg2]
                mul     edx             ; edx:eax <-- 10 * .int
                
                ;; add int version of char
                sub     bl, '0'
                add     eax, ebx
                mov     dword[intg2], eax
                inc     esi
                loop    .loop
.done:
                ;; if negative, make eax neg
                cmp     byte[isneg2], 0
                je      .return
                neg     eax
                mov     dword [intg2], eax
        
                ;; restore registers and return result in eax
.return:

                popad
                mov     eax, [intg2]
                ret

;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
;;; ; getInput: gets a numerical input from the keyboard.
;;; ;           returns the resulting number in eax (32 bits).
;;; ;           recognizes - as the first character of
;;; ;           negative numbers.  Does not skip whitespace
;;; ;           at the beginning.  Stops on first not decimal
;;; ;           character encountered.
;;; ;
;;; ; NO REGISTERS MODIFIED, except eax
;;; ;
;;; ; Example of call:
;;; ;
;;; ;          call  getInput
;;; ;          mov   dword[x], eax ; put integer in x
;;; ;
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
_getInput:
                section .bss
buffer          resb    120
intg            resd    1
isneg           resb    1
        
                section .text
                pushad                  ; save all registers

                mov     esi, buffer     ; eci --> buffer
                mov     edi, 0          ; edi = counter of chars
.loop1:        
                mov     eax, 03         ; input
                mov     ebx, 0          ; stdin
                mov     ecx, esi        ; where to put the next char
                mov     edx, 1          ; one char at a time
                int     0x80            ; get the input into buffer

                cmp     byte[esi], 0    ; EOF?
                je      .parse
                cmp     byte[esi], 10   ; line feed?
                je      .parse
                inc     esi             ; point to next cell 
                inc     edi             ; increment char counter
                jmp     .loop1

.parse:
                mov     esi, buffer     ; esi --> buffer
                mov     ecx, edi        ; loop for all chars received
                mov     dword[intg], 0
                mov     byte[isneg], 0

.negativ:      
                cmp     byte[esi], '-'
                jne     .loop
                inc     byte[isneg]
        
.loop:          mov     ebx, 0
                mov     bl, byte[esi]

                ;; stop on line feed
                cmp     bl, 10          ; line feed?
                je      .done

                ;; stop on non-digit characters
                cmp     bl, '0'
                jb      .done
                cmp     bl, '9'
                ja      .done
        
                ;; bl is a digit...  multiply .int by 10 first
                mov     edx, 10
                mov     eax, dword[intg]
                mul     edx             ; edx:eax <-- 10 * .int
                
                ;; add int version of char
                sub     bl, '0'
                add     eax, ebx
                mov     dword[intg], eax
                inc     esi
                loop    .loop
.done:
                ;; if negative, make eax neg
                cmp     byte[isneg], 0
                je      .return
                neg     eax
                mov     dword [intg], eax
        
                ;; restore registers and return result in eax
.return:

                popad
                mov     eax, [intg]
                ret     	
        
        
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
;;; ; _printDec: takes the double word in eax and prints it
;;; ; to STDOUT in decimal.
;;; ;
;;; ; Examples:
;;; ; print a byte variable
;;; ;          mov     eax, 0
;;; ;          mov     al, byte[someVar]
;;; ;          call    _printDec
;;; ;
;;; ; print a word variable
;;; ;          mov     eax
;;; ;          mov     ax, word[otherVar]
;;; ;          call    _printDec
;;; ;
;;; ; print a double-word variable
;;; ;          mov     eax, dword[thirdVar]
;;; ;          call    _printDec
;;; ;
;;; ; print register edx in decimal
;;; ;
;;; ;          mov     eax, edx
;;; ;          call    _printDec
;;; ;
;;; ;REGISTERS MODIFIED: NONE
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------

_printDec:
;;; saves all the registers so that they are not changed by the function

                section         .bss
.decstr         resb            10
.ct1            resd            1  ; to keep track of the size of the string

                section .text
                pushad                          ; save all registers

                mov             dword[.ct1],0   ; assume initially 0
                mov             edi,.decstr     ; edi points to decstring
                add             edi,9           ; moved to the last element of string
                xor             edx,edx         ; clear edx for 64-bit division
.whileNotZero:
                mov             ebx,10          ; get ready to divide by 10
                div             ebx             ; divide by 10
                add             edx,'0'         ; converts to ascii char
                mov             byte[edi],dl    ; put it in sring
                dec             edi             ; mov to next char in string
                inc             dword[.ct1]     ; increment char counter
                xor             edx,edx         ; clear edx
                cmp             eax,0           ; is remainder of division 0?
                jne             .whileNotZero   ; no, keep on looping

                inc             edi             ; conversion, finish, bring edi
                mov             ecx, edi        ; back to beg of string. make ecx
                mov             edx, [.ct1]     ; point to it, and edx gets # chars
                mov             eax, SYS_WRITE  ; and print!
                mov             ebx, STDOUT
                int             0x80

                popad                           ; restore all registers

                ret
        
;;; ; ------------------------------------------------------------
;;; ; _printString:        prints a string whose address is in
;;; ;                      ecx, and whose total number of chars
;;; ;                      is in edx.
;;; ; Examples:
;;; ; Assume a string labeled msg, containing "Hello World!",
;;; ; and a constant MSGLEN equal to 12.  To print this string:
;;; ;
;;; ;           mov        ecx, msg
;;; ;           mov        edx, MSGLEN
;;; ;           call       _printSTring
;;; ;
;;; ; REGISTERS MODIFIED:  NONE
;;; ; ------------------------------------------------------------

;;; ;save eax and ebx so that it is not modified by the function

_printString:
                push            eax
                push            ebx
        
                mov             eax,SYS_WRITE
                mov             ebx,STDOUT
                int             0x80

                pop             ebx
                pop             eax
                ret

;;; ; ------------------------------------------------------------
;;; ; _printCString:       prints a string whose address is in
;;; ;                      ecx, and which is 0-terminated, like
;;; ;			   C strings.
;;; ; Examples:
;;; ; Assume a string labeled msg, containing "Hello World!",
;;; ; and a constant MSGLEN equal to 12.  To print this string:
;;; ;
;;; ;           mov        ecx, msg     ;there's a \0 somewher in msg
;;; ;           call       _printCString
;;; ;
;;; ; REGISTERS MODIFIED:  NONE
;;; ; ------------------------------------------------------------

;;; ;save eax and ebx so that it is not modified by the function
_printCString:	push		ebx
		push		edx	 	; save regs 
		mov		ebx, ecx 	; make ebx point to string
		mov		edx, 0		; count in edx
.for:		cmp		byte[ebx], 0 	; '\0' found yet?
		je		.done
		inc		ebx 		; no, point to next char 
		inc		edx		; add 1 to counter
		jmp		.for

.done:		call		_printString
		pop		edx
		pop		ebx
		ret
		
;;; ; ------------------------------------------------------------
;;; ; _println             put the cursor on the next line.
;;; ;
;;; ; Example:
;;; ;           call      _println
;;; ;
;;; ; REGISTERS MODIFIED:  NONE
;;; ; ------------------------------------------------------------
_println:  
                section .data
.nl             db              10
        
                section .text
                push            ecx
                push            edx
        
                mov             ecx, .nl
                mov             edx, 1
                call            _printString

                pop             edx
                pop             ecx
                ret

;;; ; ------------------------------------------------------------
;;; ; _printHex: prints contents of eax in hexadecimal, uppercase.
;;; ;            using 8 chars.
;;; ; ------------------------------------------------------------
                section .data
table           db      "0123456789ABCDEF"
hexString       db      "xxxxxxxx"
tempEax         dd      0
        
                section .text
_printHex:
                pushad                  ; save all registers
                mov     [tempEax], eax  ; save eax, as we are going to need it
                                        ; several times, for all its digits 
                mov     ecx, 8          ; get ready to loop 8 times

        ;; get char equivalent to lower nybble of eax
for:            and     eax, 0xF        ; isolate lower nybble of eax
                add     eax, table      ; and translate it into ascii hex char
                mov     bl, byte[eax]   ; bl <- ascii

        ;; make eax point to place where to put this digit in hexString
                mov     eax, hexString  ; beginning of table
                add     eax, ecx        ; add ecx to it, since ecx counts
                dec     eax             ; but eax 1 too big, decrement it
                mov     byte[eax], bl   ; store ascii char at right index in hexString

        ;; shift eax down by 4 bits by dividing it by 16
                mov     ebx, 16         ; ready to shift down by 4 bits
                mov     eax, [tempEax]  ; get eax back
                div     ebx             ; shift down by 4
                mov     [tempEax], eax  ; save again

                loop    for             ; and repeat, 8 times!
        
        ;; print the pattern in hexString, which contains 8 chars

                mov     ecx, hexString  ; 
                mov     edx, 8
                call    _printString

                popad
                ret
          
;;; ; ------------------------------------------------------------
;;; ; _printInt: prints the contents of eax as a 2's complement
;;; ;            number.
;;; ; ------------------------------------------------------------
_printInt:      push    eax			; save the regs we are using
                push    ecx
                push    edx
                
        ;; check if msb is set
                test    eax, 0x80000000
                jz      positive
		neg	eax
                push    eax

		;; the number is negative.  Print a minus sign and
		;; the positive equivalent of the number
                mov     ecx, minus
                mov     edx, 1
                call    _printString
                pop     eax
                
        ;; the number is positive, just print it.
positive:       call    _printDec

                pop     edx
                pop     ecx
                pop     eax
                ret

;;; ; ------------------------------------------------------------
;;; ; printMinus, _printSpace: print a minus sign, and a plus sign.
;;; ; ------------------------------------------------------------
_printMinus:    push    ecx
                push    edx
                mov     ecx, minus
                mov     edx, 1
                call    _printString
                pop     edx
                pop     ecx
                ret

_printSpace:    push    ecx
                push    edx
                mov     ecx, space
                mov     edx, 1
                call    _printString
                pop     edx
                pop     ecx
                ret

;;; ; ------------------------------------------------------------
;;; ; _printRegs: prints all the registers.
;;; ; ------------------------------------------------------------
                section .data
minus           db      '-'
space           db      ' '        
eaxStr          db      'eax '
ebxStr          db      'ebx '
ecxStr          db      'ecx '
edxStr          db      'edx '
esiStr          db      'esi '
ediStr          db      'edi '
eaxTemp         dd      0
ebxTemp         dd      0
ecxTemp         dd      0
edxTemp         dd      0
esiTemp         dd      0
ediTemp         dd      0
                              
                section .text
_printRegs:     mov     [eaxTemp], eax
                mov     [ebxTemp], ebx
                mov     [ecxTemp], ecx
                mov     [edxTemp], edx
                mov     [ediTemp], edi
                mov     [esiTemp], esi

				pushad
				
        ;; print eax
                mov     ecx, eaxStr
                mov     edx, 4
                call    _printString
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

        ;; print ebx
                mov     ecx, ebxStr
                mov     edx, 4
                call    _printString
                mov		eax, [ebxTemp]
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

        ;; print ecx
                mov     ecx, ecxStr
                mov     edx, 4
                call    _printString
                mov		eax, [ecxTemp]
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

        ;; print edx
                mov     ecx, edxStr
                mov     edx, 4
                call    _printString
                mov		eax, [edxTemp]
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

        ;; print edi
                mov     ecx, ediStr
                mov     edx, 4
                call    _printString
                mov		eax, [ediTemp]
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

        ;; print esi
                mov     ecx, esiStr
                mov     edx, 4
                call    _printString
                mov		eax, [esiTemp]
                call    _printHex
                call    _printSpace
                call    _printDec
                call    _printSpace
                call    _printInt
                call    _println

		popad 
				
                ret
cs231a@aurora ~/HWs/HW1/pb2 $