|
4 | 4 | [asm-interp (-> (listof instruction?) any/c)] |
5 | 5 | [asm-interp/io (-> (listof instruction?) string? any/c)]) |
6 | 6 |
|
| 7 | +(define-logger a86) |
| 8 | + |
7 | 9 | (require "printer.rkt" "ast.rkt" "callback.rkt" "check-nasm.rkt" |
8 | 10 | (rename-in ffi/unsafe [-> _->])) |
9 | 11 | (require (submod "printer.rkt" private)) |
10 | 12 |
|
11 | 13 | ;; Check NASM availability when required to fail fast. |
12 | 14 | (check-nasm-available) |
13 | 15 |
|
| 16 | +(define *debug*? |
| 17 | + (let ((r (getenv "PLTSTDERR"))) |
| 18 | + (and r |
| 19 | + (string=? r "info@a86")))) |
| 20 | + |
14 | 21 | ;; Assembly code is linked with object files in this parameter |
15 | 22 | (define current-objs |
16 | 23 | (make-parameter '())) |
|
32 | 39 |
|
33 | 40 | (define fmt (if (eq? (system-type 'os) 'macosx) 'macho64 'elf64)) |
34 | 41 |
|
| 42 | +;; WARNING: The heap is re-used, so make sure you're done with it |
| 43 | +;; before calling asm-interp again |
| 44 | +(define *heap* |
| 45 | + ; IMPROVE ME: hard-coded heap size |
| 46 | + (malloc _int64 20000 'raw)) |
| 47 | + |
| 48 | + |
| 49 | +;; Integer64 -> String |
| 50 | +(define (int64->binary-string n) |
| 51 | + (format "#b~a" |
| 52 | + (~r n #:base 2 #:min-width 64 #:pad-string "0"))) |
| 53 | + |
| 54 | +;; Integer64 -> String |
| 55 | +(define (int64->octal-string n) |
| 56 | + (format "#o~a" |
| 57 | + (~r n #:base 8 #:min-width 22 #:pad-string "0"))) |
| 58 | + |
| 59 | +;; Integer64 |
| 60 | +(define (int64->hex-string n) |
| 61 | + (format "#x~a" |
| 62 | + (~r n #:base 16 #:min-width 16 #:pad-string "0"))) |
| 63 | + |
| 64 | +(define (show-state . regs) |
| 65 | + (format "\n~a" |
| 66 | + (map (lambda (r v) |
| 67 | + (format "(~a ~a)" r (int64->hex-string v))) |
| 68 | + '(rax rbx rcx rdx rbp rsp rsi rdi |
| 69 | + r8 r9 r10 r11 r12 r13 r14 r15 instr flags) |
| 70 | + regs))) |
| 71 | + |
35 | 72 | ;; Asm String -> (cons Value String) |
36 | 73 | ;; Like asm-interp, but uses given string for input and returns |
37 | 74 | ;; result with string output |
38 | 75 | (define (asm-interp/io a input) |
| 76 | + |
| 77 | + (log-a86-info (~v a)) |
| 78 | + |
39 | 79 | (define t.s (make-temporary-file "nasm~a.s")) |
40 | 80 | (define t.o (path-replace-extension t.s #".o")) |
41 | 81 | (define t.so (path-replace-extension t.s #".so")) |
|
46 | 86 | #:exists 'truncate |
47 | 87 | (λ () |
48 | 88 | (parameterize ((current-shared? #t)) |
49 | | - (asm-display a)))) |
| 89 | + (asm-display (if *debug*? |
| 90 | + (debug-transform a) |
| 91 | + a))))) |
50 | 92 |
|
51 | 93 | (nasm t.s t.o) |
52 | 94 | (ld t.o t.so) |
|
69 | 111 | (set-ffi-obj! "error_handler" libt.so _pointer |
70 | 112 | (function-ptr (λ () (raise 'err)) (_fun _-> _void)))) |
71 | 113 |
|
| 114 | + (when *debug*? |
| 115 | + (define log (ffi-obj-ref log-label libt.so (thunk #f))) |
| 116 | + (when log |
| 117 | + (set-ffi-obj! log-label libt.so _pointer |
| 118 | + (function-ptr |
| 119 | + (λ () (log-a86-info |
| 120 | + (apply show-state |
| 121 | + (build-list 18 (lambda (i) (ptr-ref log _int64 (add1 i))))))) |
| 122 | + (_fun _-> _void))))) |
72 | 123 |
|
73 | | - (define current-heap #f) |
| 124 | + (define has-heap? #f) |
74 | 125 |
|
75 | | - ;; allocate a heap |
76 | 126 | (when (ffi-obj-ref "heap" libt.so (thunk #f)) |
77 | | - (set! current-heap (make-c-parameter "heap" libt.so _pointer)) |
78 | | - |
79 | | - (if (ffi-obj-ref "from" libt.so (thunk #f)) |
80 | | - (begin |
81 | | - (current-heap |
82 | | - ; IMPROVE ME: hard-coded heap size |
83 | | - (malloc _int64 20000 'raw)) |
84 | | - (set-ffi-obj! "from" libt.so _pointer (current-heap)) |
85 | | - (set-ffi-obj! "to" libt.so _pointer (ptr-add (current-heap) 10000 _int64)) |
86 | | - (set-ffi-obj! "types" libt.so _pointer (malloc _int32 10000))) |
87 | | - (current-heap |
88 | | - ; IMPROVE ME: hard-coded heap size |
89 | | - (malloc _int64 10000 'raw)))) |
| 127 | + (set! has-heap? #t) |
| 128 | + |
| 129 | + ;; This is a GC-enabled run-time so set from, to, and types space |
| 130 | + (when (ffi-obj-ref "from" libt.so (thunk #f)) |
| 131 | + ;; FIXME: leaks types memory |
| 132 | + (set-ffi-obj! "from" libt.so _pointer *heap*) |
| 133 | + (set-ffi-obj! "to" libt.so _pointer (ptr-add *heap* 10000 _int64)) |
| 134 | + (set-ffi-obj! "types" libt.so _pointer (malloc _int32 10000)))) |
90 | 135 |
|
91 | 136 | (delete-file t.s) |
92 | 137 | (delete-file t.o) |
|
109 | 154 | (current-out (fopen t.out "w")) |
110 | 155 |
|
111 | 156 | (define result |
112 | | - (begin0 |
113 | | - (with-handlers ((symbol? identity)) |
114 | | - (guard-foreign-escape |
115 | | - (if current-heap |
116 | | - (cons (current-heap) (entry (current-heap))) |
117 | | - (entry #f)))) |
118 | | - #; |
119 | | - (when current-heap |
120 | | - (free (current-heap))))) |
| 157 | + (with-handlers ((symbol? identity)) |
| 158 | + (guard-foreign-escape |
| 159 | + (entry *heap*)))) |
121 | 160 |
|
122 | 161 | (fflush (current-out)) |
123 | 162 | (fclose (current-in)) |
|
128 | 167 | (delete-file t.out) |
129 | 168 | (cons result output)) |
130 | 169 |
|
131 | | - (begin0 |
132 | | - (with-handlers ((symbol? identity)) |
133 | | - (guard-foreign-escape |
134 | | - (if current-heap |
135 | | - (cons (current-heap) (entry (current-heap))) |
136 | | - (entry #f)))) |
137 | | - #; |
138 | | - (when current-heap |
139 | | - (free (current-heap)))))) |
| 170 | + (with-handlers ((symbol? identity)) |
| 171 | + (guard-foreign-escape |
| 172 | + (entry *heap*))))) |
140 | 173 |
|
141 | 174 |
|
142 | 175 | (define (string-splice xs) |
|
192 | 225 | (regexp-match #rx"undefined reference to `(.*)'" err-msg)) ; linux |
193 | 226 | [(list _ symbol) (ld:undef-symbol symbol)] |
194 | 227 | [_ (ld:error (format "unknown link error.\n\n~a" err-msg))]))) |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | +;; Debugging facilities |
| 232 | + |
| 233 | +(define log-label (symbol->label (gensym 'log))) |
| 234 | + |
| 235 | +(define (Log i) |
| 236 | + (seq (save-registers) |
| 237 | + (Pushf) |
| 238 | + (Mov 'rax i) |
| 239 | + (Mov (Offset log-label (* 8 17)) 'rax) |
| 240 | + (Mov 'rax (Offset 'rsp 0)) |
| 241 | + (Mov (Offset log-label (* 8 18)) 'rax) |
| 242 | + (Call (Offset log-label 0)) |
| 243 | + (Popf) |
| 244 | + (restore-registers))) |
| 245 | + |
| 246 | +(define (instrument is) |
| 247 | + (for/fold ([ls '()] |
| 248 | + #:result (reverse ls)) |
| 249 | + ([idx (in-naturals)] |
| 250 | + [ins (in-list is)]) |
| 251 | + (if (serious-instruction? ins) |
| 252 | + (seq ins (reverse (Log idx)) ls) |
| 253 | + (seq ins ls)))) |
| 254 | + |
| 255 | +(define (serious-instruction? ins) |
| 256 | + (match ins |
| 257 | + [(Label _) #f] |
| 258 | + [(Global _) #f] |
| 259 | + [(? Comment?) #f] |
| 260 | + [_ #t])) |
| 261 | + |
| 262 | +(define (debug-transform is) |
| 263 | + (seq (instrument is) |
| 264 | + ;; End of user program |
| 265 | + (Data) |
| 266 | + (Global log-label) |
| 267 | + (Label log-label) |
| 268 | + (Dq 0) ; callback placeholder |
| 269 | + (static-alloc-registers) |
| 270 | + (Dq 0) ; index of instruction |
| 271 | + (Dq 0) ; flags |
| 272 | + )) |
| 273 | + |
| 274 | +(define registers |
| 275 | + '(rax rbx rcx rdx rbp rsp rsi rdi |
| 276 | + r8 r9 r10 r11 r12 r13 r14 r15)) |
| 277 | + |
| 278 | +(define (static-alloc-registers) |
| 279 | + (apply seq |
| 280 | + (map (λ (r) (seq (Dq 0) (% (~a r)))) |
| 281 | + registers))) |
| 282 | + |
| 283 | +(define (save-registers) |
| 284 | + (apply seq |
| 285 | + (map (λ (r i) (seq (Mov (Offset log-label (* 8 i)) r))) |
| 286 | + registers |
| 287 | + (build-list (length registers) add1)))) |
| 288 | + |
| 289 | +(define (restore-registers) |
| 290 | + (apply seq |
| 291 | + (map (λ (r i) (seq (Mov r (Offset log-label (* 8 i))))) |
| 292 | + registers |
| 293 | + (build-list (length registers) add1)))) |
0 commit comments