#----------------------------------------------------------------- # gcdcalc.s # # Below we added comments to the 'gcc' compiler's translation of # our 'gcdcalc.c' high-level program into x86 assembly language. # # we executed: $ gcc -S gcdcalc # then edited: $ vi gcdcalc.s # # programmer: ALLAN CRUSE # written on: 29 MAR 2006 #----------------------------------------------------------------- .file "gcdcalc.c" #--------------------------------------------------- # Typical memory-layout of a function's stack-frame # # | ... | # +------------------------+ # | function arguments | # +------------------------+ # | return-address | # +------------------------+ # | former frame-pointer | # +------------------------+ <--- EBP # | local variables | # +------------------------+ <--- ESP # | ... | # | stack expands downward | # | to process interupts | # | ... | # #--------------------------------------------------- .text #----------------------------------------------------------------- .globl gcd .type gcd, @function gcd: # # standard function prologue # pushl %ebp # preserve frame-pointer movl %esp, %ebp # setup stackframe access subl $28, %esp # allocate local storage # # p = ( m < 0 ) ? -m : m; # movl 8(%ebp), %eax # fetch argument m movl %eax, -20(%ebp) # store as temp1 cmpl $0, -20(%ebp) # is temp1 negative? jns .L2 # no, retain temp1 negl -20(%ebp) # else negate temp1 .L2: movl -20(%ebp), %ecx # fetch temp1 movl %ecx, -12(%ebp) # and store as p # # q = ( n < 0 ) ? -n : n; # movl 12(%ebp), %eax # fetch argument n movl %eax, -24(%ebp) # store as temp2 cmpl $0, -24(%ebp) # is temp2 negative? jns .L3 # no, retain temp2 negl -24(%ebp) # else negate temp2 .L3: movl -24(%ebp), %ecx # fetch temp2 movl %ecx, -8(%ebp) # and store as q # # skip to loop-exit test # jmp .L4 # goto 'while' test .L5: # # r = p % q; # movl -12(%ebp), %edx # fetch value from p leal -8(%ebp), %eax # setup pointer to q movl %eax, -28(%ebp) # store pointer as temp3 movl %edx, %eax # copy value p into EAX movl -28(%ebp), %ecx # copy temp3 into ECX cltd # sign-extend dividend idivl (%ecx) # division by value of q movl %edx, -4(%ebp) # store remainder into r # # p = q; # movl -8(%ebp), %eax # fetch from q movl %eax, -12(%ebp) # store into p # # q = r; # movl -4(%ebp), %eax # fetch from r movl %eax, -8(%ebp) # store into q .L4: # # if ( q != 0 ) goto .L5 # cmpl $0, -8(%ebp) # test: does q equal zero? jne .L5 # no, go back through loop # # else return p as function's value # movl -12(%ebp), %eax # setup p as return-value # # standard function epilogue # leave # discard local variables ret # transfer back to caller .size gcd, .-gcd #----------------------------------------------------------------- .section .rodata .LC0: .string "\n\n gcd( %d , %d ) = %d \n\n" .text #----------------------------------------------------------------- .globl main .type main, @function main: # # standard function prologue # pushl %ebp # preserve frame-pointer movl %esp, %ebp # setup stackframe access subl $24, %esp # allocate local storage # # here the stack-pointer address gets rounded downward, # presumably to improve alignment with CPU cache-lines. # andl $-16, %esp # lower to multiple of 16 movl $0, %eax # clear the accumulator addl $15, %eax # add $0xF addl $15, %eax # and add $0xF again shrl $4, %eax # divide by 16 sall $4, %eax # multiply by 16 subl %eax, %esp # lower by multiple of 16 # # if ( argc < 3 ) return 1; # cmpl $2, 8(%ebp) # check: is argc > 2? jg .L9 # yes, then continue movl $1, %eax # else 1 is return-value movl %eax, -20(%ebp) # save as temp jmp .L8 # jump ahead to finish .L9: # # m = atoi( argv[1] ); # movl 12(%ebp), %eax # get pointer to argv array addl $4, %eax # advance pointer to argv[1] movl (%eax), %eax # fetch value from argv[1] subl $12, %esp # push 3 'dummy' arguments pushl %eax # push value from argv[1] call atoi # call 'atoi()' function addl $16, %esp # discard 4 stack-arguments movl %eax, -12(%ebp) # save function-value as m # # n = atoi( argv[2] ); # movl 12(%ebp), %eax # get pointer to argv array addl $8, %eax # advance pointer to argv[2] movl (%eax), %eax # fetch value from argv[2] subl $12, %esp # push 3 'dummy' arguments pushl %eax # push value from argv[2] call atoi # call 'atoi()' function addl $16, %esp # discard 4 stack-arguments movl %eax, -8(%ebp) # save function-value an n # # g = gcd( m, n ); # pushl -8(%ebp) # push n as argument #2 pushl -12(%ebp) # push m as argument #1 call gcd # call 'gcd()' function addl $8, %esp # discard 2 arguments movl %eax, -4(%ebp) # save return-value as g # # printf( format-string, m, n, g ); # pushl -4(%ebp) # push g as argument #4 pushl -8(%ebp) # push n as argument #3 pushl -12(%ebp) # push m as argument #2 pushl $.LC0 # push ptr as argument #1 call printf # call 'printf()' function addl $16, %esp # discard 4 arguments jmp .L11 # skip ahead to epilogue .L8: # # setup EAX with return-value of function 'main()' # movl -20(%ebp), %eax # setup return-value .L11: # # standard function epilogue # leave # discard local variables ret # transfer back to caller .size main, .-main #----------------------------------------------------------------- .ident "GCC: (GNU) 4.0.2 20051125 (Red Hat 4.0.2-8)" .section .note.GNU-stack,"",@progbits