//---------------------------------------------------------------- // add.s // // This program shows how to use the 'aaa' instruction to // add a series of unpacked Binary Coded Decimal numbers, // entered as command-line arguments: // // Example: $ add 234 8 69 2743 3 17 // // programmer: ALLAN CRUSE // written on: 09 DEC 2003 //---------------------------------------------------------------- .equ MAX, 25 # the maximum number of digits .data total: .zero MAX+1 # running total (in BCD-format) entry: .zero MAX+1 # current value (in BCD-format) buff: .zero MAX+1 # output-buffer, for the result chr: .asciz " " # holds an ascii output-prefix fmt: .asciz "%s %s \n" # format-string (for 'printf') .text main: # setup frame-pointer to access arguments pushl %ebp movl %esp, %ebp # loop through the list of command-line arguments movl 12(%ebp), %ebx # get argv into EBX movl 8(%ebp), %ecx # and argc into ECX nxarg: addl $4, %ebx # next arg-address cmpl $0, (%ebx) # is null-string? je argxx # yes, finished! call add_arg # else add the arg jmp nxarg # & go for another argxx: call show_sum # display the total # restore caller's frame-pointer and exit movl %ebp, %esp popl %ebp ret #----------------------------------------------------------------- add_arg: pushal # preserve registers # arrange argument's digits in BDC format cld # use forward processing leal entry, %edi # point EDI to buffer movl (%ebx), %esi # point ESI to argument xorl %ecx, %ecx # start counting digits nxchr: lodsb # fetch next character orb %al, %al # null terminator? jz nochr # yes, no more digits pushl %eax # else push character incl %ecx # and count the digit cmpl $MAX, %ecx # check: buffer full? jne nxchr # no, fetch next char nochr: popl %eax # pop previous digit stosb # store to our buffer loop nochr # until all are popped # show the argument pushl (%ebx) # pointer to argument pushl $chr # pointer to prefix pushl $fmt # address of format call printf # call to 'printf' addl $12, %esp # discard arguments movb $'+', chr # setup next prefix # add the new BCD entry to our total xorl %edi, %edi # initialize array-index movl $MAX, %ecx # initialize loop-count clc # clear the carry-flag nxadd: movb entry(%edi), %al # get next entry-digit adcb total(%edi), %al # add next total-digit aaa # do ascii adjustment movb %al, total(%edi) # store the new digit incl %edi # increment array-index loop nxadd # process other digits popal # restore saved registers ret # and go back to caller #----------------------------------------------------------------- show_sum: # convert total to ascii output-string leal buff, %edi # setup dest'n pointer leal total, %esi # setup source pointer movl $MAX, %ecx # initialize counter x5: lodsb # fetch next byte orb $'0', %al # convert to ascii pushl %eax # push onto stack loop x5 # do it for all movl $MAX, %ecx # reinitialze count x6: popl %eax # pop the digit stosb # store the digit loop x6 # do it for all # show the total (without leading zeros) leal buff, %esi # point to output movl $MAX-1, %ecx # max number to skip adv: cmpb $'0', (%esi) # is a leading zero? jne ready # no, start printing incl %esi # else skip past it jmp adv # and check next one ready: # print out the significant digits movb $'=', chr # adjust the prefix pushl %esi # push buffer address pushl $chr # push prefix address pushl $fmt # push format-string call printf # call 'printf' addl $12, %esp # discard parameters ret # return to caller .globl main