From 22c09056b2a3b870a468f3d0b896f2f913a059e7 Mon Sep 17 00:00:00 2001
From: Igor Pashev <pashev.igor@gmail.com>
Date: Tue, 8 Nov 2022 21:59:38 +0200
Subject: Update assembler

---
 assembler/gcd-x86-linux.s    | 138 ---------------------------------
 assembler/gcd-x86-solaris.s  | 142 ----------------------------------
 assembler/gcd-x86_64-linux.s | 126 ------------------------------
 gcd-amd64.S                  | 161 ++++++++++++++++++++++++++++++++++++++
 gcd-x86.S                    | 178 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 339 insertions(+), 406 deletions(-)
 delete mode 100644 assembler/gcd-x86-linux.s
 delete mode 100644 assembler/gcd-x86-solaris.s
 delete mode 100644 assembler/gcd-x86_64-linux.s
 create mode 100644 gcd-amd64.S
 create mode 100644 gcd-x86.S

diff --git a/assembler/gcd-x86-linux.s b/assembler/gcd-x86-linux.s
deleted file mode 100644
index aa46fd3..0000000
--- a/assembler/gcd-x86-linux.s
+++ /dev/null
@@ -1,138 +0,0 @@
-# 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
-
diff --git a/assembler/gcd-x86-solaris.s b/assembler/gcd-x86-solaris.s
deleted file mode 100644
index 50a93f2..0000000
--- a/assembler/gcd-x86-solaris.s
+++ /dev/null
@@ -1,142 +0,0 @@
-# This program is for Solaris 11 on Intel x86 arch (32 bits).
-# Written for GNU Assembler (as) with AT&T syntax
-
-# To make an executable binary:
-# gcc -nostdlib gcd-x86-solaris.s -o gcd-x86-solaris
-# or
-# as gcd-x86-solaris.s -o gcd-x86-solaris.o && \
-#    ld gcd-x86-solaris.o -o gcd-x86-solaris
-
-# On 64 bits system:
-# gcc -m32 -nostdlib gcd-x86-solaris.s -o gcd-x86-solaris
-# or
-# as --32 gcd-x86-solaris.s -o gcd-x86-solaris.o && \
-#    ld -melf_i386 gcd-x86-solaris.o -o gcd-x86-solaris
-#
-# To run:
-# ./gcd-x86-solaris 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 $buf_end, %edx
-    sub %edi, %edx # edx is a number of characters to write (buf_end - edi)
-    inc %edx       # + new line
-    push %edx
-    push %edi # first character to write
-    push $1   # write to stdout
-    push $0   # dummy
-    int $0x91 # do syscall (print the number)
-    add $16, %esp # clean stack 16 = 4 pushs * 4 bytes (32 bits!)
-
-    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-solaris 11 22 33
-    pop %ecx # Get the number of command-line options (4)
-    pop %esi # Get the pointer to the program name (./gcd-x86-solaris),
-    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
-    push $0       # exit code = 0
-    push $0       # dummy
-    int $0x91
-
diff --git a/assembler/gcd-x86_64-linux.s b/assembler/gcd-x86_64-linux.s
deleted file mode 100644
index ad92477..0000000
--- a/assembler/gcd-x86_64-linux.s
+++ /dev/null
@@ -1,126 +0,0 @@
-# This program is for Linux on Intel x86_64 arch (64 bits).
-# Written for GNU Assembler (as) with AT&T syntax
-
-# To make an executable binary:
-# gcc -nostdlib gcd-x86_64-linux.s -o gcd-x86_64-linux
-# or
-# as gcd-x86_64-linux.s -o gcd-x86_64-linux.o && \
-#    ld gcd-x86_64-linux.o -o gcd-x86_64-linux
-
-
-.data
-
-# Buffer for output:
-buffer:
-    .space 64 # enough for 64 bits integer
-buf_end:
-    .byte  10 # new line
-
-
-.text
-.globl _start
-
-
-#  GCD of two numbers.
-#    input:  rax, rbx - two numbers
-#    output: rax - GCD
-#    uses:   rax, rbx, rdx
-gcd2:
-    and %rbx, %rbx # is %rbx == 0 ?
-    jz  gcd2_exit  # %rbx == 0, go to exit and return %rax (GCD)
-    xor %rdx, %rdx # set %rdx = 0 */
-    div %rbx       # divide: %rdx:%rax / %rbx, actually: %rax / %rbx
-    mov %rbx, %rax # drop quotient in %rax and keep prrvious %rbx in %rax
-    mov %rdx, %rbx # put remainder in %rbx
-    jmp gcd2
-gcd2_exit:
-    ret
-
-
-
-#  Print an unsigned integer in rax.
-#    input: rax - unsigned integer to print
-#    uses:  rax, rbx, rcx, rdx, rdi, buffer
-print:
-    mov $10,  %rcx # set %rcx = 10 (radix)
-    mov $buf_end, %rsi
-
-next_digit:
-    xor %rdx, %rdx # set %rdx = 0
-    div %rcx       # divide: %rdx:%rax / %rcx, actually: %rax / %rcx
-    # %rdx is a remainder (0-9), it fits into %dl
-    add  $48, %dl  # get ASCII code: 0 => 48 = '0', 1 => 49 = '1'
-    dec %rsi       # put remainders going from the end of the buffer
-    mov %dl, (%rsi)
-    # now rax is a quotient
-    and %rax, %rax # is quotient == 0 ?
-    jnz next_digit # quotient is not 0, go on
-
-    # printing the number:
-    mov $1,   %rax # syscall `write'
-    mov $1,   %rdi # write to stdout
-    mov $buf_end, %rdx
-    sub %rsi, %rdx # rdx is a number of characters to write (buf_end - rsi)
-    inc %rdx       # + new line
-    syscall        # do syscall (print the number at rsi)
-
-    ret
-
-
-#  Convert string into unsigned integer
-#    input:  rsi - pointer to string
-#    output: rbx - unsigned integer
-#    uses:   rax, rbx, rcx, rdi, direction flag
-str2uint:
-    xor %rcx, %rcx # it will be the string length
-    dec %rcx       # rcx = -1 != 0 for repne
-    xor %rax, %rax # search for 0 (%rax = %al = 0)
-    mov %rsi, %rdi
-    cld            # Search forward (std - backward)
-    repne scasb    # search for 0 (in %al), incrementing rdi, decrementing rcx
-    not %rcx       # invert rcx to have the string length
-    dec %rcx       # minus ending zero
-
-    xor %rbx, %rbx
-str2uint_loop:
-    lodsb # going forward from rsi
-    # HINT: assert '0' <= al <= '9'
-    lea    (%rbx, %rbx, 4), %rbx # rbx = 4*rbx + rbx = 5*rbx ;-)
-    lea -48(%rax, %rbx, 2), %rbx # rbx = 2*rbx + %rax - 48
-                                 # rbx is multiplied by 10 each iteration,
-                                 # rax-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_64-linux 11 22 33
-    pop %rcx # Get the number of command-line options (4)
-    pop %rsi # Get the pointer to the program name (./gcd-x86_64-linux),
-    dec %rcx # minus program name
-    jz exit  # no arguments are given - exiting
-
-    xor %rax, %rax
-gcd_loop:
-    pop %rsi  # get next command line argument
-    mov %rcx, %r8 # save argument counter
-    mov %rax, %r9 # save current GCD
-    call str2uint # convert string at rsi to integer at rbx
-    mov %r9, %rax # restore current GCD
-    call gcd2 # gcd of rax and rbx (returned by str2uint)
-    # now rax is a GCD
-    mov %r8, %rcx # restore argument counter
-    loop gcd_loop
-
-    call print # print rax with GCD
-
-exit:
-    mov $60,  %rax  # exit syscall
-    xor %rdi, %rdi  # exit code = 0
-    syscall
-
diff --git a/gcd-amd64.S b/gcd-amd64.S
new file mode 100644
index 0000000..16be38f
--- /dev/null
+++ b/gcd-amd64.S
@@ -0,0 +1,161 @@
+# This program is for amd64 arch (64 bits) running Linux, Solaris or FreeBSD.
+# Written for GNU Assembler (as) with AT&T syntax
+#
+# Synopsis:
+#
+# $ gcc -nostdlib [-D OS=LINUX] gcd-amd64.S -o gcd-amd64-linux
+# or
+# $ cpp [-D OS=LINUX] gcd-amd64.S | as -o gcd-amd64-linux.o \
+#       && ld gcd-amd64-linux.o -o gcd-amd64-linux
+#
+#
+# $ gcc -nostdlib -D OS=SOLARIS gcd-amd64.S -o gcd-amd64-solaris
+# or
+# $ cpp -D OS=SOLARIS gcd-amd64.S | gas -64 -o gcd-amd64-solaris.o \
+#       && gld -m elf_x86_64_sol2 gcd-amd64-solaris.o -o gcd-amd64-solaris
+#
+# $ clang -nostdlib -D OS=FREEBSD gcd-amd64.S -o gcd-amd64-freebsd
+#
+
+#define LINUX 1
+#define SOLARIS 2
+#define FREEBSD 3
+
+#ifndef OS
+#define OS LINUX
+#endif
+
+
+.data
+
+# Buffer for output:
+buffer:
+    .space 64 # enough for a 64-bit integer
+buf_end:
+    .byte  10 # new line
+
+
+.text
+.globl _start
+
+
+#  GCD of two numbers.
+#    input:  rax, rbx - two numbers
+#    output: rax - GCD
+#    uses:   rax, rbx, rdx
+gcd2:
+    and %rbx, %rbx # is %rbx == 0 ?
+    jz  gcd2_exit  # %rbx == 0, go to exit and return %rax (GCD)
+    xor %rdx, %rdx # set %rdx = 0
+    div %rbx       # divide: %rdx:%rax / %rbx, actually: %rax / %rbx
+    mov %rbx, %rax # drop quotient in %rax and keep prrvious %rbx in %rax
+    mov %rdx, %rbx # put remainder in %rbx
+    jmp gcd2
+gcd2_exit:
+    ret
+
+
+
+#  Print an unsigned integer in rax.
+#    input: rax - unsigned integer to print
+#    uses:  rax, rbx, rcx, rdx, rdi, buffer
+print:
+    mov $10,  %rcx # set %rcx = 10 (radix)
+    mov $buf_end, %rsi
+
+next_digit:
+    xor %rdx, %rdx # set %rdx = 0
+    div %rcx       # divide: %rdx:%rax / %rcx, actually: %rax / %rcx
+    # %rdx is a remainder (0-9), it fits into %dl
+    add  $48, %dl  # get ASCII code: 0 => 48 = '0', 1 => 49 = '1'
+    dec %rsi       # put remainders going from the end of the buffer
+    mov %dl, (%rsi)
+    # now rax is a quotient
+    and %rax, %rax # is quotient == 0 ?
+    jnz next_digit # quotient is not 0, go on
+
+    # printing the number:
+#if OS == LINUX
+    mov $1, %rax # syscall `write'
+#elif OS == SOLARIS
+    mov $4, %rax # syscall `write'
+#elif OS == FREEBSD
+    mov $4, %rax # syscall `write'
+#else
+#error bad OS.
+#endif
+    mov $1,   %rdi # write to stdout
+    mov $buf_end, %rdx
+    sub %rsi, %rdx # rdx is a number of characters to write (buf_end - rsi)
+    inc %rdx       # + new line
+    syscall        # do syscall (print the number at rsi)
+    ret
+
+
+#  Convert string into unsigned integer
+#    input:  rsi - pointer to string
+#    output: rbx - unsigned integer
+#    uses:   rax, rbx, rcx, rdi, direction flag
+str2uint:
+    xor %rcx, %rcx # it will be the string length
+    dec %rcx       # rcx = -1 != 0 for repne
+    xor %rax, %rax # search for 0 (%rax = %al = 0)
+    mov %rsi, %rdi
+    cld            # Search forward (std - backward)
+    repne scasb    # search for 0 (in %al), incrementing rdi, decrementing rcx
+    not %rcx       # invert rcx to have the string length
+    dec %rcx       # minus ending zero
+
+    xor %rbx, %rbx
+str2uint_loop:
+    lodsb # going forward from rsi
+    # HINT: assert '0' <= al <= '9'
+    lea    (%rbx, %rbx, 4), %rbx # rbx = 4*rbx + rbx = 5*rbx ;-)
+    lea -48(%rax, %rbx, 2), %rbx # rbx = 2*rbx + %rax - 48
+                                 # rbx is multiplied by 10 each iteration,
+                                 # rax-48 will be multiplied at the next iteration ;-)
+    loop str2uint_loop
+    ret
+
+
+
+# Entry point for the program
+_start:
+
+    # Access command line.
+    # Example: ./gcd-amd64-linux 11 22 33
+#if OS == FREEBSD
+    mov %rdi, %rsp
+#endif
+    pop %rcx # Get the number of command-line options (4)
+    pop %rsi # Get the pointer to the program name (./gcd-amd64-linux),
+    dec %rcx # minus program name
+    jz exit  # no arguments are given - exiting
+
+    xor %rax, %rax
+gcd_loop:
+    pop %rsi  # get next command line argument
+    mov %rcx, %r8 # save argument counter
+    mov %rax, %r9 # save current GCD
+    call str2uint # convert string at rsi to integer at rbx
+    mov %r9, %rax # restore current GCD
+    call gcd2 # gcd of rax and rbx (returned by str2uint)
+    # now rax is a GCD
+    mov %r8, %rcx # restore argument counter
+    loop gcd_loop
+
+    call print # print rax with GCD
+
+exit:
+#if OS == LINUX
+    mov $60, %rax # exit syscall
+#elif OS == SOLARIS
+    mov $1, %rax  # exit syscall
+#elif OS == FREEBSD
+    mov $1, %rax  # exit syscall
+#else
+#error bad OS.
+#endif
+    xor %rdi, %rdi  # exit code = 0
+    syscall
+
diff --git a/gcd-x86.S b/gcd-x86.S
new file mode 100644
index 0000000..c8d6c79
--- /dev/null
+++ b/gcd-x86.S
@@ -0,0 +1,178 @@
+# This program is for Intel x86 arch (32 bits) running Linux, Solaris or FreeBSD.
+# Written for GNU Assembler (as) with AT&T syntax
+#
+# Synopsis:
+#
+# $ gcc -nostdlib -m32 [-D OS=LINUX] gcd-x86.S -o gcd-x86-linux
+# or
+# $ cpp [-D OS=LINUX] gcd-x86.S | as -32 -o gcd-x86-linux.o \
+#       && ld -m elf_i386 gcd-x86-linux.o -o gcd-x86-linux
+#
+#
+# $ gcc -nostdlib -m32 -D OS=SOLARIS gcd-x86.S -o gcd-x86-solaris
+# or
+# $ cpp -D OS=SOLARIS gcd-x86.S | gas -32 -o gcd-x86-solaris.o \
+#       && gld -m elf_i386_sol2 gcd-x86-solaris.o -o gcd-x86-solaris
+#
+#
+# $ clang -nostdlib -m32 -D OS=FREEBSD gcd-x86.S -o gcd-x86-freebsd
+#
+
+#define LINUX 1
+#define SOLARIS 2
+#define FREEBSD 3
+
+#ifndef OS
+#define OS LINUX
+#endif
+
+.data
+
+# Buffer for output:
+buffer:
+    .space 32 # enough for a 32-bit 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 $buf_end, %edx
+    sub %edi, %edx # edx is a number of characters to write (buf_end - edi)
+    inc %edx       # + new line
+#if OS == LINUX
+    mov $4,   %eax # syscall `write'
+    mov $1,   %ebx # write to stdout
+    mov %edi, %ecx # first character to write
+    int $0x80      # do syscall (print the number)
+#elif OS == SOLARIS
+    mov $4,   %eax # syscall `write'
+    push %edx
+    push %edi # first character to write
+    push $1   # write to stdout
+    push $0   # dummy
+    int $0x91 # do syscall (print the number)
+    add $16, %esp # clean stack 16 = 4 pushs * 4 bytes (32 bits!)
+#elif OS == FREEBSD
+    mov $4,   %eax # syscall `write'
+    push %edx
+    push %edi # first character to write
+    push $1   # write to stdout
+    push $0   # dummy
+    int $0x80 # do syscall (print the number)
+    add $16, %esp # clean stack 16 = 4 pushs * 4 bytes (32 bits!)
+#else
+#error bad OS.
+#endif
+    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.
+    # 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:
+#if OS == LINUX
+    mov $1,   %eax  # exit syscall
+    xor %ebx, %ebx  # exit code = 0
+    int $0x80
+#elif OS == SOLARIS
+    mov $1, %eax  # exit syscall
+    push $0       # exit code = 0
+    push $0       # dummy
+    int $0x91
+#elif OS == FREEBSD
+    mov $1, %eax  # exit syscall
+    push $0       # exit code = 0
+    push $0       # dummy
+    int $0x80
+#else
+#error bad OS.
+#endif
+
-- 
cgit v1.2.3