forked from sonictk/asm_tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hello_random_array.asm
215 lines (160 loc) · 5.86 KB
/
hello_random_array.asm
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
; This program allocates and fills an array with random numbers and then computes
; the minimum value of the array. If the array size <= 20, it prints the values
; in the array.
; TODO: Crashing when specifying 10000 on the command line
; TODO: Not printing the indices correctly
default rel
bits 64
segment .bss
argv resq 1
argc resq 1
segment .data
format_string db 'array value: %ld for index', 0xd, 0xa, 0
format_min db 'min: %ld', 0xd, 0xa, 0 ; CRLF and then null-terminate
segment .text
global main
; msvcrt.lib and ucrt.lib
extern malloc
extern printf
extern rand
extern _wtoi
; Kernel32.lib
extern _CRT_INIT
extern ExitProcess
extern GetCommandLineW
; Shell32.lib
extern CommandLineToArgvW
create_array: ; Equivalent to void *create_array(int size)
push rbp
mov rbp, rsp
sub rsp, 32
sal rcx, 2 ; Multiply size by 4 to get num of bytes to allocate
call malloc
leave
ret
fill_array: ; implements fill(array, size)
.array equ 0 ; Define offsets to access local stack frame variables
.size equ 8 ; These are local labels (only valid within the scope of ``fill_array``)
.i equ 16
push rbp ; Set up a stack frame
mov rbp, rsp
sub rsp, 32
mov [rsp + .array], rcx ; Save the array on the stack
mov [rsp + .size], rdx ; Save the size on the stack
xor ecx, ecx ; Clear the index register
.more:
mov [rsp + .i], rcx ; Save index register
call rand
mov rcx, [rsp + .i] ; Recall index
mov rdx, [rsp + .array] ; Load array address
mov [rdx + rcx * 4], eax ; store random value from rand's return
inc rcx
cmp rcx, [rsp + .size]
jl .more ; Keep looping until we go through the array
leave
ret
print_array: ; Implements print(array, size)
.array equ 32
.size equ 40
.i equ 48
push rbp ; Set up a stack frame
mov rbp, rsp
sub rsp, 64 ; Reserve extra 32 bytes for printf
mov [rsp + .array], rcx ; Save the array
mov [rsp + .size], rdx ; Save size
xor r8d, r8d ; Zero index register (lower 32 bits)
mov [rsp + .i], r8 ; Move the index into R8
.more:
lea rcx, [format_string] ; First param
mov rdx, [rsp + .array] ; Array address
mov r8, [rsp + .i] ; Index register 3rd param
mov edx, [rdx + r8 * 4] ; get array[i], 2nd param
; NOTE: Because we're making a function call here, need to make sure that all
; stack variables are _above_ the shadow space (i.e. offset starts after 32 bytes)
call printf
mov rcx, [rsp + .i] ; get index
inc rcx
mov [rsp + .i], rcx ; save incremented index
cmp rcx, [rsp + .size]
jl .more
leave
ret
min: ; Implements min(array, size)
push rbp ; Set up a stack frame
mov rbp, rsp
sub rsp, 32
mov eax, [rcx] ; get array[0]
mov r8d, 1 ; Set index to 1
.more:
mov r9d, [rcx + r8 * 4] ; Get array[r8]
cmp r9d, eax ; if array[r8] < eax
cmovl eax, r9d ; if yes, move array[r8] to eax
inc r8
cmp r8, rdx ; Compare counter vs array size
jl .more ; Continue until iterate over entire array
leave
ret
main:
.array equ 32
.size equ 40
push rbp
mov rbp, rsp
sub rsp, 64
call _CRT_INIT ; Needed since our entry point is not _DllMainCRTStartup. See https://msdn.microsoft.com/en-us/library/708by912.aspx
mov r8d, 7 ; Set default array size
mov [rsp + .size], r8
; Check for cmdline argument providing size
; On Windows, mainCRTStartup doesn't receive any args from the
; caller. Command line that is eventually passed to main/WinMain is being
; retrieved via GetCommandLine() within the runtime library (RTL)'s
; implementation of xxxCRTStartup.
call GetCommandLineW
; At this point, rax should have pointer to string from GetCommandLineW
; Prepare arguments for CommandLineToArgvW
lea rdx, [argc]
mov rcx, rax
call CommandLineToArgvW
; if an error occurred in CommandLineToArgvW, assume no size entered
cmp rax, 0
je .nosize
mov qword [argv], rax
cmp qword [argc], 2 ; Must only specify one argument, the 1st argument
; will be the path to the exe and the 2nd will be the actual
; argument
jne .nosize
mov rcx, [argv]
mov r9, 2
mov rcx, [rcx + 8]
call _wtoi ; Convert string to int, now rax should have size from cmdline
; If invalid size was specified on command line, use default size
cmp rax, 0
je .nosize
; ...else use the size specified
mov [rsp + .size], rax
jmp .gotsize
.nosize:
mov rcx, [rsp + .size]
.gotsize:
call create_array
mov [rsp +.array], rax ; Get array address from return value of create_array()
; fill array with random numbers
mov rcx, rax
mov rdx, [rsp + .size]
call fill_array
; If size <= 20 print the array
mov rdx, [rsp + .size]
cmp rcx, 20
jg .too_big
mov rcx, [rsp + .array]
call print_array
.too_big:
; print the minimum
mov rcx, [rsp + .array]
mov rdx, [rsp + .size]
call min
lea rcx, [format_min]
mov rdx, rax
call printf
xor eax, eax ; return 0
;leave ; TODO: Somehow this causes a crash if CommandLineToArgvW is even specified in externals? Why???
call ExitProcess