//----------------------------------------------------------------- // square.s (Adapted from our 'add.s' demo) // // This program computes the square of a nonnegative integer // which the user enters as a command-line argument, then it // writes the resulting value on the console display screen. // It offers one way to answer Question V on Midterm Exam I. // // assemble with: $ square.s -o square.o // and link with: $ ld square.o -o square // execute using: $ ./square // // programmer: ALLAN CRUSE // written on: 25 FEB 2008 //----------------------------------------------------------------- .equ sys_exit, 1 # system-call ID-number .equ sys_write, 4 # system-call ID-number .equ STDOUT, 1 # device-file ID-number .section .data ten: .int 10 # the decimal-system radix sq: .int 0 # holds square of argument msg: .ascii "The square is " # title for program output buf: .ascii " \n" # buffer for result-string len: .int . - msg # length of program-output .section .text _start: # get address of the command-line argument mov 8(%esp), %esi # ESI = pointer to string # make sure to avoid using a NULL pointer cmp $0, %esi # check: is pointer NULL? je showit # yes, keep zero for value # convert the digit-string at (ESI) to unsigned integer in EAX call atoi # convert ascii to int # now multiply the integer in EAX by itself mul %eax # compute the square of EAX mov %eax, sq # store the resulting value # convert the integer stored in 'sq' to a string of digits showit: mov sq, %eax # load EAX with final total mov $buf, %edi # point EDI to output buffer call itoa # convert integer to string # display the result of this computation mov $sys_write, %eax # system-call ID-number mov $STDOUT, %ebx # device-file ID-number mov $msg, %ecx # address of message mov len, %edx # length of message int $0x80 # invoke kernel service # terminate this program and return control to the shell mov $sys_exit, %eax # system-call ID-number mov $0, %ebx # use zero as exit-code int $0x80 # invoke kernel service itoa: # This procedure converts the unsigned integer found in EAX into # its representation as a decimal digit-string at address (EDI). pushal # preserve CPU registers mov $0, %ecx # initialize digit-count nxdiv: mov $0, %edx # extend dividend to 64-bits divl ten # divide EDX:EAX by ten push %edx # push remainder onto stack inc %ecx # and count this remainder cmp $0, %eax # was the quotient nonzero? jne nxdiv # yes, generate another digit nxdgt: pop %edx # pop next remainder to EDX add $'0', %dl # convert number to numeral mov %dl, (%edi) # store numeral into buffer inc %edi # and advance buffer-index loop nxdgt # again if digits remain popal # restore saved registers ret # return to the caller atoi: # This function converts a string of decimal numerals found at the # address in ESI into an unsigned integer which it returns in EAX. push %ebx # preserve working registers push %edx push %esi mov $0, %eax # initialize the accumulator nxchr: mov $0, %ebx # clear all the bits in EBX mov (%esi), %bl # load next character in BL inc %esi # and advance source index cmp $'0', %bl # does character preceed '0'? jb inval # yes, it's not a numeral cmp $'9', %bl # does character follow '9'? ja inval # yes, it's not a numeral sub $'0', %bl # else convert numeral to int mull ten # multiply accumulator by ten add %ebx, %eax # and then add the new integer jmp nxchr # go back for another numeral inval: pop %esi # recover saved registers pop %edx pop %ebx ret # and return to the caller .global _start # make entry-point visible .end # nothing more to assemble