LICENSE: BSD 3-Clause "New" or "Revised" License
[libmalice.git] / libmalice.asm
1 ; libmalice
2
3 ; Code for Linux on IA-32.
4
5 extern lmMain
6
7 section .text ; start of code
8
9
10 global _lmStart ; export the entry point function
11 _lmStart:       ; void lmStart(void)
12 mov [__start_esp], esp
13 call lmMain
14 .end:
15 mov esp, [__start_esp]
16         ; Cleanup can be done here if necessary
17 mov ebx, eax
18 mov eax, 1
19 int 0x80
20
21
22
23
24
25 ; lmExit - Terminate safely from any position in the program
26
27 global lmExit
28 lmExit: ; void lmExit(int exitstatus)
29 mov eax, [esp+4]        ; pass the exit status through as eax
30 jmp _lmStart.end        ; poor man's exception handling
31         ; ret is not necessary
32
33
34
35
36
37 ; lmPrintChar - Print one character to stdout (8-bit in 32-bit, LSB)
38
39 global lmPrintChar
40 lmPrintChar:    ; void lmPrintChar(int chr)
41    ; eax        ; will be: syscall number
42 push ebx        ; will be: stdout fd
43    ; ecx        ; will be: character start address
44    ; edx        ; will be: character counter
45
46 mov  edx, 1     ; print one char
47 lea  ecx, [esp+8]       ; address of the char
48 mov  ebx, 1     ; stdout fd
49 mov  eax, 4     ; write()
50 int 0x80
51
52 pop ebx
53 ret
54
55
56
57
58
59 ; lmPrintString - Print a null-terminated string to stdout
60
61 global lmPrintString
62 lmPrintString:  ; void lmPrintString(char *string)
63    ; eax        ; will be: syscall number
64 push ebx        ; will be: stdout fd
65    ; ecx        ; will be: character start address
66    ; edx        ; will be: character counter
67
68 mov  eax, 0             ; prepare for holding a char
69 mov  ecx, [esp+8]       ; string start address
70 mov  edx, -1            ; init char counter to 0
71
72 .loop:
73         inc  edx                ; char_counter++
74         mov  al, [ecx+edx]      ; check next char
75 cmp al, 0                       ; if != '\0' continue
76 jne .loop
77
78 mov  ebx, 1     ; stdout fd
79 mov  eax, 4     ; write()
80 int 0x80
81
82 pop ebx
83 ret
84
85
86
87
88
89 ; lmPrintInt32s - Print an integer to stdout (signed, 32-bit)
90
91 global lmPrintInt32s
92 lmPrintInt32s:  ; void lmPrintInt(int num)
93    ; eax        ; will be: dividend
94 push ebx        ; will be: divisor
95    ; ecx        ; will be: character start address
96    ; edx        ; will be: character counter
97 mov eax, [esp+8]        ; load num
98 sub esp, 12             ; make space for converted integer
99 lea ecx, [esp+11]       ; string offset counter, start at lastchar+1
100                         ; so writing ends at 10 and char 11 is reserved
101
102 mov ebx, 10             ; always divide by 10
103
104 cmp eax, dword 0        ; if the number is negative, negate
105 jge .loop
106 neg eax                 ; great fun at -2147483648. Overflow ftw!
107
108 .loop:
109         mov edx, 0
110         idiv ebx
111         add edx, 0x30
112         dec ecx         ; write next char
113         mov [ecx], dl
114 test eax, eax
115 jne .loop
116
117 cmp [esp+20], dword 0   ; check for negative number
118 jge .end                ; skip for positive
119 dec ecx
120 mov [ecx], byte '-'     ; add - sign
121
122 .end:
123 lea edx, [esp+11]
124 sub edx, ecx    ; number of chars
125 mov  ebx, 1     ; stdout fd
126 mov  eax, 4     ; write()
127 int 0x80        ; let the number speak
128
129 add esp, 12
130 pop ebx
131 ret
132
133
134
135
136
137 ; lmReadChar - Read a character from stdin (8-bit in 32-bit, LSB)
138
139 global lmReadChar
140 lmReadChar:     ; int lmReadChar(void)
141 push ebx
142
143 sub esp, 4      ; make room for character to be read
144
145 mov edx, 1      ; number of chars
146 mov ecx, esp    ; character buffer
147 mov ebx, 0      ; stdin fd
148 mov eax, 3      ; read()
149 int 0x80
150
151 cmp eax, 0
152 jne .ok         ; No end of input -> return char
153
154 mov eax, 0      ; End of Input -> return 0
155 jmp .end
156
157 .ok:
158 mov eax, 0
159 mov al, [esp]
160
161 .end:
162 add esp, 4
163 pop ebx
164 ret
165
166
167
168
169
170 ; lmReadInt32s - Read an integer from stdin (signed, 32-bit)
171 ;                       Terminated by EOF or LF
172
173 global lmReadInt32s
174 lmReadInt32s:   ; int lmReadInt(void)
175 push ebx
176 push esi        ; negative number info
177 push edi        ; actual number
178
179 sub esp, 4      ; make room for character to be read
180
181 mov esi, 0      ; 0 = positive
182 mov edi, 0      ; start with 0
183
184
185 .next:
186 mov edx, 1      ; number of chars
187 mov ecx, esp    ; character buffer
188 mov ebx, 0      ; stdin fd
189 mov eax, 3      ; read()
190 int 0x80
191
192 cmp eax, 0
193 je .neg         ; End of input
194
195 mov eax, 0
196 mov al, [esp]
197
198 cmp al, '-'
199 jne .process_digit
200 mov esi, 1
201 jmp .next
202
203 .process_digit:
204 cmp al, 0x30
205 jb .neg         ; char < '0'
206 cmp al, 0x39
207 ja .neg         ; char > '9'
208
209 sub eax, 0x30
210 imul edi, 10    ; shift old digits
211 add edi, eax    ; add new digit
212
213 jmp .next
214
215
216 .neg:
217 test esi, esi
218 jz .skip_loop
219 neg edi
220
221
222 .skip_loop:     ; read and skip until newline is encountered
223 cmp byte [esp], 0x0a
224 je .end         ; if newline found -> end reading
225
226 mov edx, 1      ; number of chars
227 mov ecx, esp    ; character buffer
228 mov ebx, 0      ; stdin fd
229 mov eax, 3      ; read()
230 int 0x80
231
232 cmp eax, 0
233 je .end         ; End of input -> end reading
234
235 jmp .skip_loop
236
237
238 .end:
239 mov eax, edi    ; Return value: The number read
240
241 add esp, 4
242 pop edi
243 pop esi
244 pop ebx
245 ret
246
247
248
249
250
251
252
253 section .data
254
255 __start_esp: dd 0