0de8c92b210bc2ee3a53ed2a443e21d24da155dd
[mes.git] / module / mes / as-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 i386 assembly
24
25 ;;; Code:
26
27 (cond-expand
28  (guile-2)
29  (guile)
30  (mes
31   (mes-use-module (mes elf))))
32
33 (define (i386:function-preamble)
34   '(#x55                                ; push   %ebp
35     #x89 #xe5))                         ; mov    %esp,%ebp
36
37 ;; (define (i386:function-locals)
38 ;;   '(#x83 #xec #x20))               ; sub    $0x10,%esp -- 8 local vars
39
40 (define (i386:function-locals)
41   '(#x83 #xec #x40))              ; sub    $0x10,%esp -- 16 local vars
42
43 (define (i386:push-global-address o)
44   (or o (error "invalid value: push-global-address: " o))
45   `(#x68 ,@(int->bv32 o)))              ; push  $0x<o>
46
47 (define (i386:push-global o)
48   (or o (error "invalid value: push-global: " o))
49   `(#xa1 ,@(int->bv32 o)                ; mov    0x804a000,%eax
50          #x50))                         ; push  %eax
51
52 (define (i386:push-local n)
53   (or n (error "invalid value: push-local: " n))
54   `(#xff #x75 ,(- 0 (* 4 n))))          ; pushl  0x<n>(%ebp)
55
56 (define (i386:push-local-address n)
57   (or n (error "invalid value: push-local-address: " n))
58   `(#x8d #x45 ,(- 0 (* 4 n))            ; lea 0x<n>(%ebp),%eax
59          #x50))                         ; push %eax
60
61 (define (i386:push-byte-local-de-ref n)
62   (or n (error "invalid value: push-byte-local-de-ref: " n))
63   `(#x8b #x45 ,(- 0 (* 4 n))            ; mov    -0x<n>(%ebp),%eax
64          #x0f #xb6 #x00                 ; movzbl (%eax),%eax
65          #x50))                         ; push   %eax
66
67 (define (i386:push-byte-local-de-de-ref n)
68   (or n (error "invalid value: push-byte-local-de-de-ref: " n))
69   `(#x8b #x45 ,(- 0 (* 4 n))            ; mov    -0x<n>(%ebp),%eax
70          #x8b #x00                      ; mov    (%eax),%eax
71          #x0f #xb6 #x00                 ; movzbl (%eax),%eax
72          #x50))
73
74 (define (i386:push-local-de-ref n)
75   (or n (error "invalid value: push-byte-local-de-ref: " n))
76   `(#x8b #x45 ,(- 0 (* 4 n))            ; mov    -0x<n>(%ebp),%eax
77          #x8b #x00                      ; mov (%eax),%eax
78          #x50))                         ; push   %eax
79
80 (define (i386:pop-accu)
81   '(#x58))                              ; pop %eax
82
83 (define (i386:push-accu)
84   '(#x50))                              ; push %eax
85
86 (define (i386:pop-base)
87   '(#x5a))                              ; pop %edx
88
89 (define (i386:push-base)
90   '(#x52))                              ; push %edx
91
92 (define (i386:ret)
93   '(#xc9                                ; leave
94     #xc3))                              ; ret
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 (error "invalid value: accu->base-address+n: " n))
107   `(#x89 #x42 ,n))                      ; mov    %eax,$0x<n>%(edx)
108
109 (define (i386:accu->local n)
110   (or n (error "invalid value: accu->local: " n))
111   `(#x89 #x45 ,(- 0 (* 4 n))))          ; mov    %eax,-<0xn>(%ebp)
112
113 ;; (define (i386:accu->local-address n)
114 ;;   (or n (error "invalid value: accu->local: " n))
115 ;;   `(#x89 #x45 ,(- 0 (* 4 n))))          ; mov    %eax,-<0xn>(%ebp)
116
117 (define (i386:base->local n)
118   (or n (error "invalid value: base->local: " n))
119   `(#x89 #x55 ,(- 0 (* 4 n))))          ; mov    %edx,-<0xn>(%ebp)
120
121 (define (i386:base->global n)
122   (or n (error "invalid value: base->global: " n))
123   `(#x89 #x15 ,@(int->bv32 n)))         ; mov    %edx,0x0
124
125 (define (i386:accu->global n)
126   (or n (error "invalid value: accu->global: " n))
127   `(#xa3 ,@(int->bv32 n)))              ; mov    %eax,0x0
128
129 (define (i386:accu->global-address n)
130   (or n (error "invalid value: accu->global-address: " n))
131   `(#x8b #x15 ,@(int->bv32 n)           ; mov    0x<n>,%edx
132          #x89 #x02 ))                   ; mov    %eax,(%edx)
133
134 (define (i386:accu-zero?)
135   '(#x85 #xc0))                         ; cmpl   %eax,%eax
136
137 (define (i386:accu-non-zero?)
138   (append '(#x85 #xc0)                  ; cmpl   %eax,%eax
139           (i386:xor-zf)))
140
141 (define (i386:accu-shl n)
142   (or n (error "invalid value: accu:shl n: " n))
143   `(#xc1 #xe0 ,n))                      ; shl    $0x8,%eax
144
145 (define (i386:accu<<base)
146   '(#x31 #xc9                           ; xor    %ecx,%ecx
147     #x89 #xd1                           ; mov    %edx,%ecx
148     #xd3 #xe0))                         ; shl    %cl,%eax
149
150 (define (i386:accu>>base)
151   '(#x31 #xc9                           ; xor    %ecx,%ecx
152     #x89 #xd1                           ; mov    %edx,%ecx
153     #xd3 #xe8))                         ; shr    %cl,%eax
154
155 (define (i386:accu-or-base)
156   '(#x09 #xd0))                         ; or    %edx,%eax
157
158 (define (i386:accu-and-base)
159   '(#x21 #xd0))                         ; and    %edx,%eax
160
161 (define (i386:accu-xor-base)
162   '(#x31 #xd0))                         ; and    %edx,%eax
163
164 (define (i386:accu+accu)
165   '(#x01 #xc0))                         ; add    %eax,%eax
166
167 (define (i386:accu+base)
168   `(#x01 #xd0))                         ; add    %edx,%eax
169
170 (define (i386:accu+value v)
171   (or v (error "invalid value: accu+value: " v))
172   `(#x05 ,@(int->bv32 v)))              ; add    %eax,%eax
173
174 (define (i386:accu-base)
175   `(#x29 #xd0))                         ; sub    %edx,%eax
176
177 (define (i386:accu*base)
178   `(#xf7 #xe2))                         ; mul    %edx
179
180 (define (i386:accu/base)
181   '(#x86 #xd3                           ; mov    %edx,%ebx
182     #x31 #xd2                           ; xor    %edx,%edx
183     #xf7 #xf3))                         ; div    %ebx
184
185 (define (i386:accu%base)
186   '(#x86 #xd3                           ; mov    %edx,%ebx
187     #x31 #xd2                           ; xor    %edx,%edx
188     #xf7 #xf3                           ; div    %ebx
189     #x89 #xd0))                         ; mov    %edx,%eax
190
191 (define (i386:base->accu)
192   '(#x89 #xd0))                         ; mov    %edx,%eax
193
194 (define (i386:local->accu n)
195   (or n (error "invalid value: local->accu: " n))
196   `(#x8b #x45 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%eax
197
198 (define (i386:local-address->accu n)
199   (or n (error "invalid value: ladd: " n))
200   `(#x8d #x45 ,(- 0 (* 4 n))))          ; lea 0x<n>(%ebp),%eax
201
202 (define (i386:local-ptr->accu n)
203   (or n (error "invalid value: local-ptr->accu: " n))
204   `(#x89 #xe8                           ; mov    %ebp,%eax
205          #x83 #xc0 ,(- 0 (* 4 n))))     ; add    $0x<n>,%eax
206
207 (define (i386:byte-local->accu n)
208   (or n (error "invalid value: byte-local->accu: " n))
209   `(#x0f #xb6 #x45 ,(- 0 (* 4 n))))     ; movzbl 0x<n>(%ebp),%eax
210
211 (define (i386:byte-local->base n)
212   (or n (error "invalid value: byte-local->base: " n))
213   `(#x0f #xb6 #x55 ,(- 0 (* 4 n))))     ; movzbl 0x<n>(%ebp),%edx
214
215 (define (i386:local->base n)
216   (or n (error "invalid value: local->base: " n))
217   `(#x8b #x55 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%edx
218
219 (define (i386:local-address->base n) ;; DE-REF
220   (or n (error "invalid value: local-address->base: " n))
221   `(#x8d #x55 ,(- 0 (* 4 n))))          ; lea    0x<n>(%ebp),%edx
222
223 (define (i386:local-ptr->base n)
224   (or n (error "invalid value: local-ptr->base: " n))
225   `(#x89 #xea                           ; mov    %ebp,%edx
226          #x83 #xc2 ,(- 0 (* 4 n))))     ; add    $0x<n>,%edx
227
228 (define (i386:global->base n)
229   (or n (error "invalid value: global->base: " n))
230   `(#xba ,@(int->bv32 n)))              ; mov   $<n>,%edx
231
232 (define (i386:global-address->accu n)
233   (or n (error "invalid value: global-address->accu: " n))
234   `(#xa1 ,@(int->bv32 n)))              ; mov    0x<n>,%eax
235
236 (define (i386:global-address->base n)
237   (or n (error "invalid value: global-address->base: " n))
238   `(#x8b #x15 ,@(int->bv32 n)))         ; mov    0x<n>,%edx
239
240 (define (i386:byte-base-mem->accu)
241   '(#x01 #xd0                           ; add    %edx,%eax
242          #x0f #xb6 #x00))               ; movzbl (%eax),%eax
243
244 (define (i386:byte-mem->accu)
245   '(#x0f #xb6 #x00))                    ; movzbl (%eax),%eax
246
247 (define (i386:byte-mem->base)
248   '(#x0f #xb6 #x10))                    ; movzbl (%eax),%edx
249
250 (define (i386:base-mem->accu)
251   '(#x01 #xd0                           ; add    %edx,%eax
252          #x8b #x00))                    ; mov    (%eax),%eax
253
254 (define (i386:mem->accu)
255   '(#x8b #x00))                         ; mov    (%eax),%eax
256
257 (define (i386:mem+n->accu n)
258   `(#x8b #x40 ,n))                      ; mov    0x<n>(%eax),%eax
259
260 (define (i386:base-mem+n->accu n)
261   (or n (error "invalid value: base-mem+n->accu: " n))
262   `(#x01 #xd0                           ; add    %edx,%eax
263          #x8b #x40 ,n))                 ; mov    <n>(%eax),%eax
264
265 (define (i386:value->accu v)
266   (or v (error "invalid value: i386:value->accu: " v))
267   `(#xb8 ,@(int->bv32 v)))              ; mov    $<v>,%eax
268
269 (define (i386:value->accu-address v)
270   `(#xc7 #x00 ,@(int->bv32 v)))         ; movl   $0x<v>,(%eax)
271
272 (define (i386:value->accu-address+n n v)
273   (or v (error "invalid value: i386:value->accu-address+n: " v))
274   `(#xc7 #x40 ,n ,@(int->bv32 v)))      ; movl   $<v>,0x<n>(%eax)
275
276 (define (i386:base->accu-address)
277   '(#x89 #x10))                         ; mov    %edx,(%eax)
278
279 (define (i386:base-address->accu-address)
280   '(#x8b #x0a                           ; mov    (%edx),%ecx
281     #x89 #x08))                         ; mov    %ecx,(%eax)
282
283 (define (i386:accu+n n)
284   `(#x83 #xc0 ,n))                      ; add    $0x00,%eax
285
286 (define (i386:base+n n)
287   `(#x83 #xc2 ,n))                      ; add    $0x00,%edx
288
289 (define (i386:byte-base->accu-address)
290   '(#x88 #x10))                         ; mov    %dl,(%eax)
291
292 (define (i386:byte-base->accu-address+n n)
293   (or n (error "invalid value: byte-base->accu-address+n: " n))
294   `(#x88 #x50 ,n))                      ; mov    %dl,0x<n>(%eax)
295
296 (define (i386:value->base v)
297   (or v (error "invalid value: i386:value->base: " v))
298   `(#xba ,@(int->bv32 v)))              ; mov    $<v>,%edx
299
300 (define (i386:local-add n v)
301   (or n (error "invalid value: i386:local-add: " n))
302   `(#x83 #x45 ,(- 0 (* 4 n)) ,v))       ; addl   $<v>,0x<n>(%ebp)
303
304 (define (i386:accu-mem-add v)
305   `(#x83 #x00 ,v))                      ; addl   $<v>,(%eax)
306
307 (define (i386:global-add n v)
308   (or n (error "invalid value: i386:global-add: " n))
309   `(#x83 #x05 ,@(int->bv32 n) ,v))      ; addl   $<v>,0x<n>
310
311 (define (i386:global->accu o)
312   (or o (error "invalid value: i386:global->accu: " o))
313   `(#xb8 ,@(int->bv32 o)))              ; mov    $<>,%eax
314
315 (define (i386:value->global n v)
316   (or n (error "invalid value: value->global: " n))
317   `(#xc7 #x05 ,@(int->bv32 n)           ; movl   $<v>,(<n>)
318          ,@(int->bv32 v)))
319
320 (define (i386:value->local n v)
321   (or n (error "invalid value: value->local: " n))
322   `(#xc7 #x45 ,(- 0 (* 4 n))            ; movl   $<v>,0x<n>(%ebp)
323          ,@(int->bv32 v)))
324
325 (define (i386:local-test n v)
326   (or n (error "invalid value: local-test: " n))
327   `(#x83 #x7d ,(- 0 (* 4 n)) ,v))       ; cmpl   $<v>,0x<n>(%ebp)
328
329 (define (i386:call f g ta t d address n)
330   (or address (error "invalid value: i386:call: " address))
331   `(#xe8 ,@(int->bv32 (- address 5))    ; call   relative $00
332          #x83 #xc4 ,(* n 4)))           ; add    $00,%esp
333
334 (define (i386:call-accu f g ta t d n)
335   `(,@(i386:push-accu)
336     ,@(i386:pop-accu)
337     #xff #xd0                           ; call   *%eax
338     #x83 #xc4 ,(* n 4)))                ; add    $00,%esp
339
340 (define (i386:accu-not)
341   `(#x0f #x94 #xc0                      ; sete %al
342          #x0f #xb6 #xc0))               ; movzbl %al,%eax
343
344 (define (i386:xor-accu v)
345   (or v (error "invalid value: i386:xor-accu: n: " v))
346   `(#x35 ,@(int->bv32 v)))              ;xor    $0xff,%eax
347
348 (define (i386:xor-zf)
349   '(#x9f                                ; lahf   
350     #x80 #xf4 #x40                      ; xor    $0x40,%ah
351     #x9e))                              ; sahf   
352
353 (define (i386:accu-cmp-value v)
354   `(#x83 #xf8 ,v))                      ; cmp    $<v>,%eax
355
356 (define (i386:accu-test)
357   '(#x85 #xc0))                         ; test   %eax,%eax
358
359 (define (i386:Xjump n)
360   (or n (error "invalid value: i386:Xjump: n: " n))
361   `(#xe9 ,@(int->bv32 (if (>= n 0) n (- n 5))))) ; jmp . + <n>
362
363 (define (i386:XXjump n)
364   (or n (error "invalid value: i386:XXjump: n: " n))
365   `(#xe9 ,@(int->bv32 n)))              ; jmp . + <n>
366
367 (define (i386:Xjump-nz n)
368   (or n (error "invalid value: i386:Xjump-nz: n: " n))
369   `(#x0f #x85 ,@(int->bv32 n)))         ; jnz . + <n>
370
371 (define (i386:Xjump-z n)
372   (or n (error "invalid value: i386:Xjump-z: n: " n))
373   `(#x0f #x84 ,@(int->bv32 n)))         ; jz . + <n>
374
375 (define (i386:jump n) ;;FIXME: NEED THIS WEIRDNESS for t.c
376   (when (or (> n #x80) (< n #x-80))
377     (error "JUMP n=" n))
378   `(#xeb ,(if (>= n 0) (- n 2) (- n 2)))) ; jmp <n>
379
380 (define (i386:jump-c n)
381   (when (or (> n #x80) (< n #x-80))
382     (error "JUMP n=" n))
383   `(#x72 ,(if (>= n 0) n (- n 2))))     ; jc <n>
384
385 (define (i386:jump-cz n)
386   (when (or (> n #x80) (< n #x-80))
387     (error "JUMP n=" n))
388   `(#x76 ,(if (>= n 0) n (- n 2))))     ; jbe <n>
389
390 (define (i386:jump-ncz n)
391   (when (or (> n #x80) (< n #x-80))
392     (error "JUMP-ncz n=" n))
393   `(#x77 ,(if (>= n 0) n (- n 2))))     ; ja <n>
394
395 (define (i386:jump-nc n)
396   (when (or (> n #x80) (< n #x-80))
397     (error "JUMP-nc n=" n))
398   `(#x73 ,(if (>= n 0) n (- n 2))))     ; jnc <n>
399
400 ;; unsigned
401 (define (i386:Xjump-nc n)
402   (or n (error "invalid value i386:Xjump-nc: " n))
403   `(#x0f #x83 ,@(int->bv32 n)))         ; jnc <n>
404
405 ;; unsigned
406 (define (i386:Xjump-ncz n)
407   (or n (error "invalid value: i386:Xjump-ncz" n))
408   `(#x0f #x87 ,@(int->bv32 n)))         ; ja <n>
409
410 ;; unsigned
411 ;; (define (i386:Xjump-c n)
412 ;;   (or n urg:Xjump-c)
413 ;;   `(#x0f #x82 ,@(int->bv32 n)))     ; jc <n>
414
415 ;; unsigned
416 ;; (define (i386:Xjump-cz n)
417 ;;   (or n urg:Xjump-cz)
418 ;;   `(#x0f #x86 ,@(int->bv32 n)))         ; jbe <n>
419
420 ;; signed
421 (define (i386:Xjump-g n)
422   (or n (error "invalid value: i386:Xjump-g: " n))
423   `(#x0f #x8f ,@(int->bv32 n)))         ; jg/jnle <n>
424
425 ;; signed
426 (define (i386:Xjump-ge n)
427   (or n (error "invalid value: Xjump-ge: " n))
428   `(#x0f #x8d ,@(int->bv32 n)))         ; jge/jnl <n>
429
430 ;; ;; signed
431 ;; (define (i386:Xjump-l n)
432 ;;   (or n urg:Xjump-l)
433 ;;   `(#x0f #x8c ,@(int->bv32 n)))         ; jl/jnge <n>
434
435 ;; ;; signed
436 ;; (define (i386:Xjump-le n)
437 ;;   (or n urg:Xjump-le)
438 ;;   `(#x0f #x8e ,@(int->bv32 n)))         ; jle/jgn <n>
439
440 (define (i386:jump-z n)
441   (when (or (> n #x80) (< n #x-80))
442     (error "JUMP-z n=" n))
443   `(#x74 ,(if (>= n 0) n (- n 2))))     ; jz <n>
444
445 (define (i386:jump-nz n)
446   (when (or (> n #x80) (< n #x-80))
447     (error "JUMP-nz n=" n))
448   `(#x75 ,(if (>= n 0) n (- n 2))))     ; jnz <n>
449
450 (define (i386:test-jump-z n)
451   (when (or (> n #x80) (< n #x-80))
452     (error "JUMP-z n=" n))
453   `(#x85 #xc0                           ; test   %eax,%eax
454     #x74 ,(if (>= n 0) n (- n 4))))     ; jz <n>
455
456 (define (i386:jump-byte-nz n)
457   (when (or (> n #x80) (< n #x-80))
458     (error "JUMP-byte-nz n=" n))
459   `(#x84 #xc0                           ; test   %al,%al
460     #x75 ,(if (>= n 0) n (- n 4))))     ; jne <n>
461
462 (define (i386:jump-byte-z n)
463   (when (or (> n #x80) (< n #x-80))
464     (error "JUMP-byte-z n=" n))
465   `(#x84 #xc0                           ; test   %al,%al
466     #x74 ,(if (>= n 0) n (- n 4))))     ; jne <n>
467
468 (define (i386:byte-test-base)
469   `(#x38 #xc2))                         ; cmp    %al,%dl
470
471 (define (i386:test-base)
472   `(#x39 #xd0))                         ; cmp    %edx,%eax
473
474 (define (i386:byte-sub-base)
475   `(#x28 #xd0))                         ; sub    %dl,%al
476
477 (define (i386:byte-base-sub)
478   `(#x28 #xd0))                         ; sub    %al,%dl
479
480 (define (i386:sub-base)
481   `(#x29 #xd0))                         ; sub    %edx,%eax
482
483 (define (i386:base-sub)
484   `(#x29 #xc2))                         ; sub    %eax,%edx
485
486 (define (i386:nz->accu)
487   '(#x0f #x95 #xc0                      ; setne   %al
488          #x0f #xb6 #xc0))               ; movzbl %al,%eax
489
490 (define (i386:z->accu)
491   '(#x0f #x94 #xc0                      ; sete   %al
492          #x0f #xb6 #xc0))               ; movzbl %al,%eax
493
494 (define (i386:accu<->stack)
495   '(#x87 #x04 #x24))                    ; xchg   %eax,(%esp)
496