1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# 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, %rdi
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 %rdi # put remainders going from the end of the buffer
mov %dl, (%rdi)
# now rax is a quotient
and %rax, %rax # is quotient == 0 ?
jnz next_digit # quotient is not 0, go on
# printing the number:
mov $4, %rax # syscall `write'
mov $1, %rbx # write to stdout
mov %rdi, %rcx # first character to write
mov $buf_end, %rdx
sub %rdi, %rdx # rdx is a number of characters to write (buf_end - rdi)
inc %rdx # + new line
int $0x80 # do syscall (print the number)
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 $1, %rax # exit syscall
xor %rbx, %rbx # exit code = 0
int $0x80
|