CSC231 Homework 2 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.
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 231Lib.asm ld -o hw2 hw2.o 231Lib.o 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
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
;;; 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 _printDec global _printString global _println global _getInput global _printRegs global _printHex section .text ;;; ;------------------------------------------------------ ;;; ;------------------------------------------------------ ;;; ; getInput: gets a numerical input from the keyboard. ;;; ; returns the resulting number in eax (32 bits). ;;; ; recognize - 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 ;;; ; ------------------------------------------------------------ ;;; ; _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 cmp eax, 0x8000000 jb positive 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 neg 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