mescc: Run mini-mes.
[mes.git] / module / mes / libc-i386.mes
1 ;;; -*-scheme-*-
2
3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of Mes.
7 ;;;
8 ;;; Mes is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; Mes is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; libc-i386.mes defines C library routines
24
25 ;;; Code:
26
27 (define (i386:function-preamble)
28   '(#x55                                ; push   %ebp
29     #x89 #xe5))                         ; mov    %esp,%ebp
30
31 (define (i386:function-locals)
32   '(#x83 #xec #x20))               ; sub    $0x10,%esp -- 8 local vars
33
34 (define (i386:push-global-address o)
35   (or o push-global-address)
36   `(#x68 ,@(int->bv32 o)))              ; push  $0x<o>
37
38 (define (i386:push-global o)
39   (or o push-global)
40   `(#xa1 ,@(int->bv32 o)                ; mov    0x804a000,%eax
41          #x50))                         ; push  %eax
42
43 (define (i386:push-local n)
44   (or n push-local)
45   `(#xff #x75 ,(- 0 (* 4 n))))          ; pushl  0x<n>(%ebp)
46
47 (define (i386:push-local-address n)
48   (or n push-local-address)
49   `(#x8d #x45 ,(- 0 (* 4 n))            ; lea 0x<n>(%ebp),%eax
50          #x50))                         ; push %eax
51
52 (define (i386:push-local-de-ref n)
53   (or n push-local-de-ref)
54   `(#x8b #x45 ,(- 0 (* 4 n))            ; mov    -0x<n>(%ebp),%eax
55          #x0f #xb6 #x00                 ; movzbl (%eax),%eax
56          ;;#x0f #xbe #xc0                 ; movsbl %al,%eax ***FIXME BYTE****
57          #x50))                         ; push   %eax
58
59 (define (i386:pop-accu)
60   '(#x58))                              ; pop %eax
61
62 (define (i386:push-accu)
63   '(#x50))                              ; push %eax
64
65 (define (i386:pop-base)
66   '(#x5a))                              ; pop %eax
67
68 (define (i386:push-base)
69   '(#x52))                              ; push %eax
70
71 (define (i386:push-arg f g ta t d)
72   (lambda (o)
73     (or o push-arg)
74     (cond ((number? o)
75            `(#x68 ,@(int->bv32 o)))     ; push $<o>
76           ((and (pair? o) (procedure? (car o)))
77            (append-map (lambda (p) (p f g ta t d)) o))
78           ((pair? o) o)
79           ((procedure? o) (o f g ta t d))
80           (_ barf))))
81
82 (define (i386:ret . rest)
83   (lambda (f g ta t d)
84     `(
85       ,@(cond ((null? rest) '())
86               ((number? (car rest))
87                `(#xb8                     ; mov    $<>,%eaxx
88                  ,@(int->bv32 (car rest))))
89               ((pair? (car rest)) (car rest))
90               ((procedure? (car rest))
91                ((car rest) f g ta t d)))
92     #xc9                                ; leave
93     #xc3                                ; ret
94     )))
95
96 (define (i386:accu->base)
97   '(#x89 #xc2))                         ; mov    %eax,%edx
98
99 (define (i386:accu->base-address)
100   '(#x89 #x02))                         ; mov    %eax,%(edx)
101
102 (define (i386:byte-accu->base-address)
103   '(#x88 #x02))                         ; mov    %al,%(edx)
104
105 (define (i386:accu->base-address+n n)
106   (or n accu->base-address+n)
107   `(#x89 #x42 ,n))                      ; mov    %eax,$0x<n>%(edx)
108
109 (define (i386:accu->local n)
110   (or n accu->local)
111   `(#x89 #x45 ,(- 0 (* 4 n))))          ; mov    %eax,-<0xn>(%ebp)
112
113 (define (i386:base->local n)
114   (or n base->local)
115   `(#x89 #x55 ,(- 0 (* 4 n))))          ; mov    %edx,-<0xn>(%ebp)
116
117 (define (i386:base->global n)
118   (or n base->global)
119   `(#x89 #x15 ,@(int->bv32 n)))         ; mov    %edx,0x0
120
121 (define (i386:accu->global n)
122   (or n accu->global)
123   `(#xa3 ,@(int->bv32 n)))              ; mov    %eax,0x0
124
125 (define (i386:accu->global-address n)
126   (or n accu->global-address)
127   `(#x8b #x15 ,@(int->bv32 n)           ; mov    0x<n>,%edx
128          #x89 #x02 ))                   ; mov    %eax,(%edx)
129
130 (define (i386:accu-zero?)
131   '(#x85 #xc0))                         ; cmpl   %eax,%eax
132
133 (define (i386:accu-non-zero?)
134   (append '(#x85 #xc0)                  ; cmpl   %eax,%eax
135           (i386:xor-zf)))
136
137 (define (i386:accu-shl n)
138   (or n accu:shl n)
139   `(#xc1 #xe0 ,n))                      ; shl    $0x8,%eax
140
141 (define (i386:accu+accu)
142   '(#x01 #xc0))                         ; add    %eax,%eax
143
144 (define (i386:accu+base)
145   `(#x01 #xd0))                         ; add    %edx,%eax
146
147 (define (i386:accu+value v)
148   (or v accu+value)
149   `(#x05 ,@(int->bv32 v)))              ; add    %eax,%eax
150
151 (define (i386:accu-base)
152   `(#x29 #xd0))                         ; sub    %edx,%eax
153
154 ;; (define (i386:accu/base)
155 ;;   '(#xf7 #xf2))                         ; div    %edx,%eax
156
157 (define (i386:accu/base)
158   '(#x86 #xd3                           ; mov    %edx,%ebx
159     #x31 #xd2                           ; xor    %edx,%edx
160     #xf7 #xf3))                         ; div    %ebx
161
162 (define (i386:base->accu)
163   '(#x89 #xd0))                         ; mov    %edx,%eax
164
165 (define (i386:local->accu n)
166   (or n local->accu)
167   `(#x8b #x45 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%eax
168
169 (define (i386:local-address->accu n)
170   (or n ladd)
171   `(#x8d #x45 ,(- 0 (* 4 n))))          ; lea 0x<n>(%ebp),%eax
172
173 (define (i386:local-ptr->accu n)
174   (or n local-ptr->accu)
175   `(#x89 #xe8                           ; mov    %ebp,%eax
176          #x83 #xc0 ,(- 0 (* 4 n))))     ; add    $0x<n>,%eax
177
178 (define (i386:byte-local->accu n)
179   (or n byte-local->accu)
180   `(#x0f #xb6 #x45 ,(- 0 (* 4 n))))     ; movzbl 0x<n>(%ebp),%eax
181
182 (define (i386:local->base n)
183   (or n local->base)
184   `(#x8b #x55 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%edx
185
186 (define (i386:local-address->base n) ;; DE-REF
187   (or n local-address->base)
188   `(#x8d #x55 ,(- 0 (* 4 n))))          ; lea    0x<n>(%ebp),%edx
189
190 (define (i386:local-ptr->base n)
191   (or n local-ptr->base)
192   `(#x89 #xea                           ; mov    %ebp,%edx
193          #x83 #xc2 ,(- 0 (* 4 n))))     ; add    $0x<n>,%edx
194
195 (define (i386:global->base n)
196   (or n global->base)
197   `(#xba ,@(int->bv32 n)))              ; mov   $<n>,%edx
198
199 (define (i386:global-address->accu n)
200   (or n global-address->accu)
201   `(#xa1 ,@(int->bv32 n)))              ; mov    0x<n>,%eax
202
203 (define (i386:global-address->base n)
204   (or n global-address->base)
205   `(#x8b #x15 ,@(int->bv32 n)))         ; mov    0x<n>,%edx
206
207 (define (i386:byte-base-mem->accu)
208   '(#x01 #xd0                           ; add    %edx,%eax
209          #x0f #xb6 #x00))               ; movzbl (%eax),%eax
210
211 (define (i386:byte-mem->accu)
212   '(#x0f #xb6 #x00))                    ; movzbl (%eax),%eax
213
214 (define (i386:byte-mem->base)
215   '(#x0f #xb6 #x10))                    ; movzbl (%eax),%edx
216
217 (define (i386:base-mem->accu)
218   '(#x01 #xd0                           ; add    %edx,%eax
219          #x8b #x00))                    ; mov    (%eax),%eax
220
221 (define (i386:mem->accu)
222   '(#x8b #x00))                         ; mov    (%eax),%eax
223
224 (define (i386:mem+n->accu n)
225   `(#x8b #x40 ,n))                      ; mov    0x<n>(%eax),%eax
226
227 (define (i386:base-mem+n->accu n)
228   (or n base-mem+n->accu)
229   `(#x01 #xd0                           ; add    %edx,%eax
230          #x8b #x40 ,n))                 ; mov    <n>(%eax),%eax
231
232 (define (i386:value->accu v)
233   (or v urg:value->accu)
234   `(#xb8 ,@(int->bv32 v)))              ; mov    $<v>,%eax
235
236 (define (i386:value->accu-address v)
237   `(#xc7 #x00 ,@(int->bv32 v)))         ; movl   $0x<v>,(%eax)
238
239 (define (i386:value->accu-address+n n v)
240   (or v urg:value->accu-address+n)
241   `(#xc7 #x40 ,n ,@(int->bv32 v)))      ; movl   $<v>,0x<n>(%eax)
242
243 (define (i386:base->accu-address)
244   '(#x89 #x10))                         ; mov    %edx,(%eax)
245
246 (define (i386:byte-base->accu-address)
247   '(#x88 #x10))                         ; mov    %dl,(%eax)
248
249 (define (i386:byte-base->accu-address+n n)
250   (or n byte-base->accu-address+n)
251   `(#x88 #x50 ,n))                      ; mov    %dl,0x<n>(%eax)
252
253 (define (i386:value->base v)
254   (or v urg:value->base)
255   `(#xba ,@(int->bv32 v)))              ; mov    $<v>,%edx
256
257 (define (i386:local-add n v)
258   (or n urg:local-add)
259   `(#x83 #x45 ,(- 0 (* 4 n)) ,v))       ; addl   $<v>,0x<n>(%ebp)
260
261 (define (i386:global-add n v)
262   (or n urg:global-add)
263   `(#x83 #x05 ,@(int->bv32 n) ,v))      ; addl   $<v>,0x<n>
264
265 (define (i386:global->accu o)
266   (or o urg:global->accu)
267   `(#xb8 ,@(int->bv32 o)))              ; mov    $<>,%eax
268
269 (define (i386:value->global n v)
270   (or n value->global)
271   `(#xc7 #x05 ,@(int->bv32 n)           ; movl   $<v>,(<n>)
272          ,@(int->bv32 v)))
273
274 (define (i386:value->local n v)
275   (or n value->local)
276   `(#xc7 #x45 ,(- 0 (* 4 n))            ; movl   $<v>,0x<n>(%ebp)
277          ,@(int->bv32 v)))
278
279 (define (i386:local-test n v)
280   (or n local-test)
281   `(#x83 #x7d ,(- 0 (* 4 n)) ,v))       ; cmpl   $<v>,0x<n>(%ebp)
282
283 (define (i386:call f g ta t d address . arguments)
284   (or address urg:call)
285   (let* ((pushes (append-map (i386:push-arg f g ta t d) (reverse arguments)))
286          (s (length pushes))
287          (n (length arguments)))
288    `(
289      ,@pushes                           ; push args
290      #xe8 ,@(int->bv32 (- address 5 s)) ; call relative
291      #x83 #xc4 ,(* n 4)                 ; add    $00,%esp
292      )))
293
294 (define (i386:call-accu f g ta t d . arguments)
295   ;;(or address urg:call)
296   (let* ((pushes (append-map (i386:push-arg f g ta t d) (reverse arguments)))
297          (s (length pushes))
298          (n (length arguments)))
299     `(
300       ,@(i386:push-accu)
301       ,@pushes    ; push args
302       ;;#xe8 ,@(int->bv32 (- address 5 s)) ; call relative
303       ;; FIXME: add t?/address
304       ;; #x50                               ; push %eax
305       ;; #xc3                               ; ret
306       ,@(i386:pop-accu)
307       ;; #x05 ,@(int->bv32 t)              ; add    <t>,%eax
308       ;; #x05 ,@(int->bv32 ta)             ; add    <ta>,%eax
309       #xff #xd0                         ; call   *%eax
310       #x83 #xc4 ,(* n 4)                ; add    $00,%esp
311       )))
312  
313 (define (i386:accu-not)
314   `(#x0f #x94 #xc0                      ; sete %al
315          #x0f #xb6 #xc0))               ; movzbl %al,%eax
316
317 (define (i386:xor-accu v)
318   (or n urg:xor-accu)
319   `(#x35 ,@(int->bv32 v)))              ;xor    $0xff,%eax
320
321 (define (i386:xor-zf)
322   '(#x9f                                ; lahf   
323     #x80 #xf4 #x40                      ; xor    $0x40,%ah
324     #x9e))                              ; sahf   
325
326 (define (i386:accu-cmp-value v)
327   `(#x83 #xf8 ,v))                      ; cmp    $<v>,%eax
328
329 (define (i386:accu-test)
330   '(#x85 #xc0))                         ; test   %eax,%eax
331
332 (define (i386:Xjump n)
333   (or n urg:Xjump)
334   `(#xe9 ,@(int->bv32 (if (>= n 0) n (- n 5))))) ; jmp . + <n>
335
336 (define (i386:Xjump-nz n)
337   (or n urg:Xjump-nz)
338   `(#x0f #x85 ,@(int->bv32 n)))         ; jnz . + <n>
339
340 (define (i386:jump n) ;;FIXME: NEED THIS WEIRDNESS for t.c
341   (when (or (> n #x80) (< n #x-80))
342     (format (current-error-port) "JUMP n=~a\n" n)
343     barf)
344   `(#xeb ,(if (>= n 0) (- n 2) (- n 2)))) ; jmp <n>
345
346 (define (i386:jump-c n)
347   (or n jump-c)
348   `(#x72 ,(if (>= n 0) n (- n 2))))     ; jc <n>
349
350 (define (i386:jump-cz n)
351   (or n jump-cz)
352   `(#x76 ,(if (>= n 0) n (- n 2))))     ; jna <n>
353
354 (define (i386:jump-ncz n)
355   (or n jump-ncz)
356   `(#x77 ,(if (>= n 0) n (- n 2))))     ; ja <n>
357
358 (define (i386:jump-nc n)
359   (or n jump-nc)
360   `(#x73 ,(if (>= n 0) n (- n 2))))     ; jnc <n>
361
362 (define (i386:jump-z n)
363   (or n jump-z)
364   `(#x74 ,(if (>= n 0) n (- n 2)))) ; jz <n>
365
366 (define (i386:jump-nz n)
367   (or n jump-nz)
368   `(#x75 ,(if (>= n 0) n (- n 2)))) ; jnz <n>
369
370 (define (i386:test-jump-z n)
371   (or n jump-z)
372   `(#x85 #xc0                           ; test   %eax,%eax
373     #x74 ,(if (>= n 0) n (- n 4))))     ; jz <n>
374
375 (define (i386:jump-byte-nz n)
376   (or n jump-byte-nz)
377   `(#x84 #xc0                           ; test   %al,%al
378     #x75 ,(if (>= n 0) n (- n 4))))     ; jne <n>
379
380 (define (i386:jump-byte-z n)
381   (or n jump-byte-z)
382   `(#x84 #xc0                           ; test   %al,%al
383     #x74 ,(if (>= n 0) n (- n 4))))     ; jne <n>
384
385 (define (i386:byte-test-base)
386   `(#x38 #xc2))                         ; cmp    %al,%dl
387
388 (define (i386:test-base)
389   `(#x39 #xd0))                         ; cmp    %edx,%eax
390
391 (define (i386:byte-sub-base)
392   `(#x28 #xd0))                         ; sub    %dl,%al
393
394 (define (i386:byte-base-sub)
395   `(#x28 #xd0))                         ; sub    %al,%dl
396
397 (define (i386:sub-base)
398   `(#x29 #xd0))                         ; sub    %edx,%eax
399
400 (define (i386:base-sub)
401   `(#x29 #xc2))                         ; sub    %eax,%edx
402
403 ;;;\f libc bits
404 (define (i386:exit f g ta t d)
405   `(
406     #x5b                                ; pop    %ebx
407     #x5b                                ; pop    %ebx
408     #xb8 #x01 #x00 #x00 #x00            ; mov    $0x1,%eax
409     #xcd #x80                           ; int    $0x80
410     ))
411
412 (define (i386:open f g ta t d)
413   `(
414     #x55                                ; push   %ebp
415     #x89 #xe5                           ; mov    %esp,%ebp
416
417     #x8b #x5d #x08                      ; mov    0x8(%ebp),%ebx
418     #x8b #x4d #x0c                      ; mov    0xc(%ebp),%ecx
419
420     #xb8 #x05 #x00 #x00 #x00            ; mov    $0x5,%eax
421     #xcd #x80                           ; int    $0x80
422
423     #xc9                                ; leave
424     #xc3                                ; ret
425     ))
426
427 (define (i386:read f g ta t d)
428   `(
429     #x55                                ; push   %ebp
430     #x89 #xe5                           ; mov    %esp,%ebp
431
432     #x8b #x5d #x08                      ; mov    0x8(%ebp),%ebx
433     #x8b #x4d #x0c                      ; mov    0xc(%ebp),%ecx
434     #x8b #x55 #x10                      ; mov    0x10(%ebp),%edx
435
436     #xb8 #x03 #x00 #x00 #x00            ; mov    $0x3,%eax
437     #xcd #x80                           ; int    $0x80
438
439     #xc9                                ; leave
440     #xc3                                ; ret
441     ))
442
443 (define (i386:write f g ta t d)
444   `(
445     #x55                                ; push   %ebp
446     #x89 #xe5                           ; mov    %esp,%ebp
447
448     #x8b #x5d #x08                      ; mov    0x8(%ebp),%ebx
449     #x8b #x4d #x0c                      ; mov    0xc(%ebp),%ecx
450     #x8b #x55 #x10                      ; mov    0x10(%ebp),%edx
451
452     #xb8 #x04 #x00 #x00 #x00            ; mov    $0x4,%eax
453     #xcd #x80                           ; int    $0x80
454
455     #xc9                                ; leave
456     #xc3                                ; ret
457     ))
458
459 #!
460 08048121 <strcmp>:
461  8048121:       55                      push   %ebp
462  8048122:       89 e5                   mov    %esp,%ebp
463  8048124:       83 ec 10                sub    $0x10,%esp
464  8048127:       eb 08                   jmp    8048131 <strcmp+0x10>
465
466 <body>
467  8048129:       83 45 08 01             addl   $0x1,0x8(%ebp)
468  804812d:       83 45 0c 01             addl   $0x1,0xc(%ebp)
469
470 <test> *a
471  8048131:       8b 45 08                mov    0x8(%ebp),%eax
472  8048134:       0f b6 00                movzbl (%eax),%eax
473  8048137:       84 c0                   test   %al,%al
474  8048139:       74 08                   je     8048143 <strcmp+0x22>
475
476 <test1> *b
477  804813b:       8b 45 0c                mov    0xc(%ebp),%eax
478  804813e:       0f b6 00                movzbl (%eax),%eax
479  8048141:       84 c0                   test   %al,%al
480  8048143:       74 10                   je     8048155 <strcmp+0x34>
481
482 <test2> *a == *b
483  8048145:       8b 45 08                mov    0x8(%ebp),%eax
484  8048148:       0f b6 10                movzbl (%eax),%edx
485  804814b:       8b 45 0c                mov    0xc(%ebp),%eax
486  804814e:       0f b6 00                movzbl (%eax),%eax
487  8048151:       38 c2                   cmp    %al,%dl
488  8048153:       84 c0                   test   %al,%al
489  8048155:       75 d2                   jne    8048129 <strcmp+0x8>
490
491
492  8048157:       8b 45 08                mov    0x8(%ebp),%eax
493  804815a:       0f b6 10                movzbl (%eax),%edx
494  804815d:       8b 45 0c                mov    0xc(%ebp),%eax
495  8048160:       0f b6 00                movzbl (%eax),%eax
496  8048163:       28 d0                   sub    %dl,%al
497  8048165:       c9                      leave
498  8048166:       c3                      ret  
499 !#