diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2011-07-04 00:36:11 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2011-07-04 00:36:11 +0400 |
commit | 270050462a570dfa1a21fec39007dc1cb81acb91 (patch) | |
tree | bd96289c0c25e1b37c9fc41578596bb618db0e80 | |
parent | 805f85143e1a85fcc40a5b039f44f07cff0f981a (diff) | |
download | gcd-270050462a570dfa1a21fec39007dc1cb81acb91.tar.gz |
GNU assembler for x86 (32 bits) Linux
-rw-r--r-- | assembler/gcd-x86-linux.s | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/assembler/gcd-x86-linux.s b/assembler/gcd-x86-linux.s new file mode 100644 index 0000000..aa46fd3 --- /dev/null +++ b/assembler/gcd-x86-linux.s @@ -0,0 +1,138 @@ +# This program is for Linux on Intel x86 arch (32 bits). +# Written for GNU Assembler (as) with AT&T syntax + +# To make an executable binary: +# gcc -nostdlib gcd-x86-linux.s -o gcd-x86-linux +# or +# as gcd-x86-linux.s -o gcd-x86-linux.o && \ +# ld gcd-x86-linux.o -o gcd-x86-linux + +# On 64 bits system: +# gcc -m32 -nostdlib gcd-x86-linux.s -o gcd-x86-linux +# or +# as --32 gcd-x86-linux.s -o gcd-x86-linux.o && \ +# ld -melf_i386 gcd-x86-linux.o -o gcd-x86-linux +# +# To run: +# ./gcd-x86-linux 11 22 33 121 792 +# (output should be 11) + + +.data + +# Buffer for output: +buffer: + .space 32 # enough for 32 bits integer +buf_end: + .byte 10 # new line + + +.text +.globl _start + + +# GCD of two numbers. +# input: eax, ebx - two numbers +# output: eax - GCD +# uses: eax, ebx, edx +gcd2: + and %ebx, %ebx # is %ebx == 0 ? + jz gcd2_exit # %ebx == 0, go to exit and return %eax (GCD) + xor %edx, %edx # set %edx = 0 */ + div %ebx # divide: %edx:%eax / %ebx, actually: %eax / %ebx + mov %ebx, %eax # drop quotient in %eax and keep previous %ebx in %eax + mov %edx, %ebx # put remainder in %ebx + jmp gcd2 +gcd2_exit: + ret + + + +# Print an unsigned integer in eax. +# input: eax - unsigned integer to print +# uses: eax, ebx, ecx, edx, edi, buffer +print: + mov $10, %ecx # set %ecx = 10 (radix) + mov $buf_end, %edi + +next_digit: + xor %edx, %edx # set %edx = 0 + div %ecx # divide: %edx:%eax / %ecx, actually: %eax / %ecx + # %edx is a remainder (0-9), it fits into %dl + add $48, %dl # get ASCII code: 0 => 48 = '0', 1 => 49 = '1' + dec %edi # put remainders going from the end of the buffer + mov %dl, (%edi) + # now eax is a quotient + and %eax, %eax # is quotient == 0 ? + jnz next_digit # quotient is not 0, go on + + # printing the number: + mov $4, %eax # syscall `write' + mov $1, %ebx # write to stdout + mov %edi, %ecx # first character to write + mov $buf_end, %edx + sub %edi, %edx # edx is a number of characters to write (buf_end - edi) + inc %edx # + new line + int $0x80 # do syscall (print the number) + + ret + + +# Convert string into unsigned integer +# input: esi - pointer to string +# output: ebx - unsigned integer +# uses: eax, ebx, ecx, edi, direction flag +str2uint: + xor %ecx, %ecx # it will be the string length + dec %ecx # ecx = -1 != 0 for repne + xor %eax, %eax # search for 0 (%eax = %al = 0) + mov %esi, %edi + cld # Search forward (std - backward) + repne scasb # search for 0 (in %al), incrementing edi, decrementing ecx + not %ecx # invert ecx to have the string length + dec %ecx # minus ending zero + + xor %ebx, %ebx +str2uint_loop: + lodsb # going forward from esi + # HINT: assert '0' <= al <= '9' + lea (%ebx, %ebx, 4), %ebx # ebx = 4*ebx + ebx = 5*ebx ;-) + lea -48(%eax, %ebx, 2), %ebx # ebx = 2*ebx + %eax - 48 + # ebx is multiplied by 10 each iteration, + # eax-48 will be multiplied at the next iteration ;-) + loop str2uint_loop + ret + + + +# Entry point for the program +_start: + + # Access command line, see: + # http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html + # Example: ./gcd-x86-linux 11 22 33 + pop %ecx # Get the number of command-line options (4) + pop %esi # Get the pointer to the program name (./gcd-x86-linux), + dec %ecx # minus program name + jz exit # no arguments are given - exiting + + xor %eax, %eax +gcd_loop: + pop %esi # get next command line argument + # Well, we used all registers, now we DO NEED stack :-) + push %ecx # save argument counter + push %eax # save current GCD + call str2uint # convert string at esi to integer at ebx + pop %eax # restore current GCD + call gcd2 # gcd of eax and ebx (returned by str2uint) + # now eax is a GCD + pop %ecx # restore argument counter + loop gcd_loop + + call print # print eax with GCD + +exit: + mov $1, %eax # exit syscall + xor %ebx, %ebx # exit code = 0 + int $0x80 + |