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