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