summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2011-07-04 00:36:11 +0400
committerIgor Pashev <pashev.igor@gmail.com>2011-07-04 00:36:11 +0400
commit270050462a570dfa1a21fec39007dc1cb81acb91 (patch)
treebd96289c0c25e1b37c9fc41578596bb618db0e80
parent805f85143e1a85fcc40a5b039f44f07cff0f981a (diff)
downloadgcd-270050462a570dfa1a21fec39007dc1cb81acb91.tar.gz
GNU assembler for x86 (32 bits) Linux
-rw-r--r--assembler/gcd-x86-linux.s138
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
+