summaryrefslogtreecommitdiff
path: root/assignments/3/max_min.asm
blob: 4487fccfe5b1e0bbbc38892aef8b1513955ddd1f (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
.section .data
largest_msg: .asciz "Max: "
smallest_msg: .asciz "The smallest number is: "
newline: .asciz "\n"
temp_input: .space 32  # Buffer for input string
largest: .quad 0
smallest: .quad 0
initialized: .byte 0  # Flag to check if smallest/largest are initialized

.section .text
.globl _start

_start:
    # Initialize the largest and smallest values
    movq $0, largest
    movq $0, smallest
    movb $0, initialized  # Mark as uninitialized

read_input:
    # Read a line of input from stdin
    movq $0, %rax        # syscall: read
    movq $0, %rdi        # file descriptor: stdin
    lea temp_input(%rip), %rsi # buffer to store input
    movq $32, %rdx       # size of input buffer
    syscall

    # Check if input is empty (EOF)
    cmpq $0, %rax
    je print_results

    # Null-terminate the input string
    lea temp_input(%rip), %rdi   # Load base address of temp_input
    addq %rax, %rdi              # Add offset to the base address
    movb $0, (%rdi)              # Null-terminate the string

    # Convert the input string to an integer
    lea temp_input(%rip), %rsi
    call string_to_int
    movq %rax, %rdi      # Store integer in %rdi

    # Check for termination (sentinel value -1)
    cmpq $-1, %rdi
    je print_results

    # Check if largest/smallest are initialized
    cmpb $0, initialized(%rip)
    jne compare_values

    # Initialize largest and smallest with the first input value
    movq %rdi, largest(%rip)
    movq %rdi, smallest(%rip)
    movb $1, initialized(%rip)  # Mark as initialized
    jmp read_input

compare_values:
    # Update the largest value
    movq largest(%rip), %rax
    cmpq %rdi, %rax
    jge check_smallest
    movq %rdi, largest(%rip)

check_smallest:
    # Update the smallest value
    movq smallest(%rip), %rax
    cmpq %rdi, %rax
    jle read_input
    movq %rdi, smallest(%rip)
    jmp read_input

print_results:
    # Print the largest value
    movq $1, %rax        # syscall: write
    movq $1, %rdi        # file descriptor: stdout
    lea largest_msg(%rip), %rsi
    movq $5, %rdx       # length of message
    syscall

    movq largest(%rip), %rax   # Load the largest value
    call print_integer

    # Print newline
    movq $1, %rax
    movq $1, %rdi
    lea newline(%rip), %rsi
    movq $1, %rdx
    syscall

    # Print the smallest value
    movq $1, %rax
    movq $1, %rdi
    lea smallest_msg(%rip), %rsi
    movq $25, %rdx
    syscall

    movq smallest(%rip), %rax  # Load the smallest value
    call print_integer

    # Print newline
    movq $1, %rax
    movq $1, %rdi
    lea newline(%rip), %rsi
    movq $1, %rdx
    syscall

    # Exit program
    movq $60, %rax        # syscall: exit
    xorq %rdi, %rdi
    syscall

string_to_int:
    # Convert null-terminated string at %rsi to integer in %rax
    xorq %rax, %rax       # Clear %rax (result)
    xorq %rbx, %rbx       # Clear %rbx (temporary register)

convert_loop:
    movb (%rsi), %bl      # Load next character
    cmpb $0, %bl          # Check for null terminator
    je convert_done
    subb $48, %bl         # Convert ASCII to integer
    imulq $10, %rax       # Multiply result by 10
    addq %rbx, %rax       # Add the current digit
    incq %rsi             # Move to the next character
    jmp convert_loop

convert_done:
    ret

print_integer:
    # Convert integer in %rax to string and print it
    pushq %rbp
    movq %rsp, %rbp
    subq $16, %rsp

    movq $10, %rbx       # Base 10 divisor
    xorq %rcx, %rcx      # Counter for digits
    movq %rax, %rdx      # Copy number to %rdx

    # Convert digits to string in reverse order
convert_digit:
    xorq %r8, %r8        # Clear temporary
    divq %rbx            # Divide %rdx by 10, remainder in %rax
    addb $48, %al        # Convert remainder to ASCII
    movb %al, -1(%rbp,%rcx)  # Store digit
    incq %rcx            # Increment digit count
    testq %rdx, %rdx     # Check if quotient is 0
    jne convert_digit

    # Print the digits
    movq $1, %rax        # syscall: write
    movq $1, %rdi        # file descriptor: stdout
    lea -1(%rbp,%rcx), %rsi # Start of digits
    movq %rcx, %rdx      # Length of string
    syscall

    movq %rbp, %rsp
    popq %rbp
    ret