https://github.com/akkartik/mu/blob/master/081table.subx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 == code
21
22
23
24
25
26
27 get:
28
29
30
31
32
33
34
35
36
37
38 55/push-ebp
39 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
40
41 51/push-ecx
42 52/push-edx
43 56/push-esi
44
45 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 .
46
47 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 .
48
49 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . .
50 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . .
51 $get:search-loop:
52
53 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . .
54 73/jump-if-addr>= $get:abort/disp8
55
56
57
58 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
59 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
60
61 e8/call string-equal?/disp32
62
63 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
64
65 3d/compare-eax-and 0/imm32/false
66 74/jump-if-= $get:mismatch/disp8
67 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 .
68 eb/jump $get:end/disp8
69 $get:mismatch:
70
71 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 .
72
73 eb/jump $get:search-loop/disp8
74 $get:end:
75
76 5e/pop-to-esi
77 5a/pop-to-edx
78 59/pop-to-ecx
79
80 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
81 5d/pop-to-ebp
82 c3/return
83
84 $get:abort:
85
86
87 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 .
88 68/push 2/imm32/stderr
89
90 e8/call _write/disp32
91
92 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
93
94
95 68/push ": get: key not found: "/imm32
96 68/push 2/imm32/stderr
97
98 e8/call _write/disp32
99
100 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
101
102
103 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
104 68/push 2/imm32/stderr
105
106 e8/call _write/disp32
107
108 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
109
110
111 68/push Newline/imm32
112 68/push 2/imm32/stderr
113
114 e8/call _write/disp32
115
116 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
117
118 bb/copy-to-ebx 1/imm32
119 b8/copy-to-eax 1/imm32/exit
120 cd/syscall 0x80/imm8
121
122
123 test-get:
124
125 55/push-ebp
126 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
127
128
129 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32
130 68/push 0x10/imm32/length
131 68/push 0/imm32/read
132 68/push 0/imm32/write
133 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . .
134
135
136 68/push 8/imm32/row-size
137 68/push "code"/imm32
138 51/push-ecx
139
140 e8/call get-or-insert/disp32
141
142 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
143
144
145 68/push 8/imm32/row-size
146 68/push "data"/imm32
147 51/push-ecx
148
149 e8/call get-or-insert/disp32
150
151 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
152 $test-get:check1:
153
154
155 68/push 8/imm32/row-size
156 68/push "code"/imm32
157 51/push-ecx
158
159 e8/call get/disp32
160
161 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
162
163
164
165 68/push "F - test-get/0"/imm32
166 68/push 0x10/imm32
167 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
168 50/push-eax
169
170 e8/call check-ints-equal/disp32
171
172 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
173 $test-get:check2:
174
175
176 68/push 8/imm32/row-size
177 68/push "data"/imm32
178 51/push-ecx
179
180 e8/call get/disp32
181
182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
183
184
185
186 68/push "F - test-get/1"/imm32
187 68/push 0x18/imm32
188 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
189 50/push-eax
190
191 e8/call check-ints-equal/disp32
192
193 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
194 $test-get:end:
195
196 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
197 5d/pop-to-ebp
198 c3/return
199
200
201 get-slice:
202
203
204
205
206
207
208
209
210
211
212 55/push-ebp
213 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
214
215 51/push-ecx
216 52/push-edx
217 56/push-esi
218
219 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 .
220
221 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 .
222
223 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . .
224 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . .
225 $get-slice:search-loop:
226
227 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . .
228 73/jump-if-addr>= $get-slice:abort/disp8
229
230
231
232 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
233 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
234
235 e8/call slice-equal?/disp32
236
237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
238
239 3d/compare-eax-and 0/imm32/false
240 74/jump-if-= $get-slice:mismatch/disp8
241 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 .
242 eb/jump $get-slice:end/disp8
243 $get-slice:mismatch:
244
245 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 .
246
247 eb/jump $get-slice:search-loop/disp8
248 $get-slice:end:
249
250 5e/pop-to-esi
251 5a/pop-to-edx
252 59/pop-to-ecx
253
254 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
255 5d/pop-to-ebp
256 c3/return
257
258 $get-slice:abort:
259
260
261 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 .
262 68/push 2/imm32/stderr
263
264 e8/call _write/disp32
265
266 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
267
268
269 68/push ": get-slice: key not found: "/imm32
270 68/push 2/imm32/stderr
271
272 e8/call _write/disp32
273
274 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
275
276
277 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
278 68/push Stderr/imm32
279
280 e8/call write-slice-buffered/disp32
281
282 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
283
284
285 68/push Stderr/imm32
286
287 e8/call flush/disp32
288
289 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
290
291
292 68/push Newline/imm32
293 68/push 2/imm32/stderr
294
295 e8/call _write/disp32
296
297 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
298
299 bb/copy-to-ebx 1/imm32
300 b8/copy-to-eax 1/imm32/exit
301 cd/syscall 0x80/imm8
302
303
304 test-get-slice:
305
306 55/push-ebp
307 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
308
309
310 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32
311 68/push 0x10/imm32/length
312 68/push 0/imm32/read
313 68/push 0/imm32/write
314 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . .
315
316
317 68/push 8/imm32/row-size
318 68/push "code"/imm32
319 51/push-ecx
320
321 e8/call get-or-insert/disp32
322
323 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
324
325
326 68/push 8/imm32/row-size
327 68/push "data"/imm32
328 51/push-ecx
329
330 e8/call get-or-insert/disp32
331
332 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
333 $test-get-slice:check1:
334
335 b8/copy-to-eax "code"/imm32
336 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . .
337 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 .
338 05/add-to-eax 4/imm32
339
340 52/push-edx
341 50/push-eax
342 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . .
343
344
345 68/push 8/imm32/row-size
346 52/push-edx
347 51/push-ecx
348
349 e8/call get-slice/disp32
350
351 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
352
353
354
355 68/push "F - test-get-slice/0"/imm32
356 68/push 0x10/imm32
357 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
358 50/push-eax
359
360 e8/call check-ints-equal/disp32
361
362 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
363 $test-get-slice:check2:
364
365 b8/copy-to-eax "data"/imm32
366 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . .
367 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 .
368 05/add-to-eax 4/imm32
369
370 52/push-edx
371 50/push-eax
372 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . .
373
374
375 68/push 8/imm32/row-size
376 52/push-edx
377 51/push-ecx
378
379 e8/call get-slice/disp32
380
381 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
382
383
384
385 68/push "F - test-get-slice/1"/imm32
386 68/push 0x18/imm32
387 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
388 50/push-eax
389
390 e8/call check-ints-equal/disp32
391
392 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
393 $test-get-slice:end:
394
395 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
396 5d/pop-to-ebp
397 c3/return
398
399
400
401
402
403
404 get-or-insert:
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 55/push-ebp
421 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
422
423 51/push-ecx
424 52/push-edx
425 56/push-esi
426
427 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 .
428
429 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 .
430
431 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . .
432 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . .
433 $get-or-insert:search-loop:
434
435 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . .
436 73/jump-if-addr>= $get-or-insert:not-found/disp8
437
438
439
440 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
441 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
442
443 e8/call string-equal?/disp32
444
445 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
446
447 3d/compare-eax-and 0/imm32/false
448 74/jump-if-= $get-or-insert:mismatch/disp8
449 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 .
450 eb/jump $get-or-insert:end/disp8
451 $get-or-insert:mismatch:
452
453 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 .
454
455 eb/jump $get-or-insert:search-loop/disp8
456 $get-or-insert:not-found:
457
458 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . .
459
460 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . .
461 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 .
462 73/jump-if-addr>= $get-or-insert:abort/disp8
463
464
465 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 .
466 52/push-edx
467
468 e8/call zero-out/disp32
469
470 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
471
472
473 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 .
474
475 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . .
476
477
478 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 .
479
480 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . .
481
482
483 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . .
484
485 05/add-to-eax 4/imm32
486 $get-or-insert:end:
487
488 5e/pop-to-esi
489 5a/pop-to-edx
490 59/pop-to-ecx
491
492 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
493 5d/pop-to-ebp
494 c3/return
495
496 $get-or-insert:abort:
497
498
499 68/push "get-or-insert: table is full\n"/imm32
500 68/push 2/imm32/stderr
501
502 e8/call _write/disp32
503
504 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
505
506 bb/copy-to-ebx 1/imm32
507 b8/copy-to-eax 1/imm32/exit
508 cd/syscall 0x80/imm8
509
510
511 test-get-or-insert:
512
513 55/push-ebp
514 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
515
516 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32
517 68/push 0x10/imm32/length
518 68/push 0/imm32/read
519 68/push 0/imm32/write
520 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . .
521 $test-get-or-insert:first-call:
522
523
524
525 68/push 8/imm32/row-size
526 68/push "code"/imm32
527 51/push-ecx
528
529 e8/call get-or-insert/disp32
530
531 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
532
533
534
535 68/push "F - test-get-or-insert/0"/imm32
536 68/push 0x10/imm32
537 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
538 50/push-eax
539
540 e8/call check-ints-equal/disp32
541
542 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
543 $test-get-or-insert:check2:
544
545
546 68/push "F - test-get-or-insert/1"/imm32
547 68/push 8/imm32/row-size
548 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
549
550 e8/call check-ints-equal/disp32
551
552 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
553
554
555 68/push "F - test-get-or-insert/2"/imm32
556 68/push "code"/imm32
557 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 .
558
559 e8/call check-strings-equal/disp32
560
561 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
562 $test-get-or-insert:second-call:
563
564
565
566 68/push 8/imm32/row-size
567 68/push "code"/imm32
568 51/push-ecx
569
570 e8/call get-or-insert/disp32
571
572 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
573
574
575
576 68/push "F - test-get-or-insert/3"/imm32
577 68/push 0x10/imm32
578 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
579 50/push-eax
580
581 e8/call check-ints-equal/disp32
582
583 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
584
585
586
587 68/push "F - test-get-or-insert/4"/imm32
588 68/push 8/imm32/row-size
589 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
590
591 e8/call check-ints-equal/disp32
592
593 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
594
595
596 68/push "F - test-get-or-insert/5"/imm32
597 68/push "code"/imm32
598 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 .
599
600 e8/call check-strings-equal/disp32
601
602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
603 $test-get-or-insert:third-call:
604
605
606
607 68/push 8/imm32/row-size
608 68/push "data"/imm32
609 51/push-ecx
610
611 e8/call get-or-insert/disp32
612
613 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
614
615
616
617
618 68/push "F - test-get-or-insert/6"/imm32
619 68/push 0x18/imm32
620 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . .
621 50/push-eax
622
623 e8/call check-ints-equal/disp32
624
625 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
626
627
628 68/push "F - test-get-or-insert/7"/imm32
629 68/push 0x10/imm32/two-rows
630 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . .
631
632 e8/call check-ints-equal/disp32
633
634 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
635
636
637
638 68/push "F - test-get-or-insert/8"/imm32
639 68/push "data"/imm32
640 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x14/disp8 .
641
642 e8/call check-strings-equal/disp32
643
644 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
645 $test-get-or-insert:end:
646
647 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
648 5d/pop-to-ebp
649 c3/return
650
651
652
653
654
655 leaky-get-or-insert-slice:
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671 55/push-ebp
672 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
673
674 51/push-ecx
675 52/push-edx
676 56/push-esi
j < SIZE(inst.words); ++j) {
const word& curr = inst.words.at(j);
if (!contains_key(address, curr.data)) {
if (!looks_like_hex_int(curr.data))
raise << "missing reference to global '" << curr.data << "'\n" << end();
new_inst.words.push_back(curr);
continue;
}
if (!valid_use_of_global_variable(curr)) {
raise << "'" << to_string(inst) << "': can't refer to global variable '" << curr.data << "'\n" << end();
return;
}
emit_hex_bytes(new_inst, get(address, curr.data), 4);
}
inst.words.swap(new_inst.words);
trace(99, "transform") << "instruction after transform: '" << data_to_string(inst) << "'" << end();
}
}
void replace_global_variables_in_data_segment(segment& data, const map<string, uint32_t>& address) {
for (int i = 0; i < SIZE(data.lines); ++i) {
line& l = data.lines.at(i);
line new_l;
for (int j = 0; j < SIZE(l.words); ++j) {
const word& curr = l.words.at(j);
if (!contains_key(address, curr.data)) {
if (looks_like_hex_int(curr.data)) {
if (has_operand_metadata(curr, "imm32"))
emit_hex_bytes(new_l, curr, 4);
else if (has_operand_metadata(curr, "imm16"))
emit_hex_bytes(new_l, curr, 2);
else if (has_operand_metadata(curr, "imm8"))
emit_hex_bytes(new_l, curr, 1);
else if (has_operand_metadata(curr, "disp8"))
raise << "can't use /disp8 in a non-code segment\n" << end();
else if (has_operand_metadata(curr, "disp16"))
raise << "can't use /disp16 in a non-code segment\n" << end();
else if (has_operand_metadata(curr, "disp32"))
raise << "can't use /disp32 in a non-code segment\n" << end();
else
new_l.words.push_back(curr);
}
else {
raise << "missing reference to global '" << curr.data << "'\n" << end();
new_l.words.push_back(curr);
}
continue;
}
trace(99, "transform") << curr.data << " maps to " << HEXWORD << get(address, curr.data) << end();
emit_hex_bytes(new_l, get(address, curr.data), 4);
}
l.words.swap(new_l.words);
trace(99, "transform") << "after transform: '" << data_to_string(l) << "'" << end();
}
}
bool valid_use_of_global_variable(const word& curr) {
if (has_operand_metadata(curr, "imm32")) return true;
// End Valid Uses Of Global Variable(curr)
return false;
}
//:: a more complex sanity check for how we use global variables
//: requires first saving some data early before we pack operands
:(after "Begin Level-2 Transforms")
Transform.push_back(correlate_disp32_with_mod);
:(code)
void correlate_disp32_with_mod(program& p) {
if (p.segments.empty()) return;
segment& code = *find(p, "code");
for (int i = 0; i < SIZE(code.lines); ++i) {
line& inst = code.lines.at(i);
for (int j = 0; j < SIZE(inst.words); ++j) {
word& curr = inst.words.at(j);
if (has_operand_metadata(curr, "disp32")
&& has_operand_metadata(inst, "mod"))
curr.metadata.push_back("has_mod");
}
}
}
:(before "End Valid Uses Of Global Variable(curr)")
if (has_operand_metadata(curr, "disp32"))
return has_metadata(curr, "has_mod");
// todo: more sophisticated check, to ensure we don't use global variable
// addresses as a real displacement added to other operands.
:(code)
bool has_metadata(const word& w, const string& m) {
for (int i = 0; i < SIZE(w.metadata); ++i)
if (w.metadata.at(i) == m) return true;
return false;
}
void test_global_variable_disallowed_in_jump() {
Hide_errors = true;
run(
"== code 0x1\n"
"eb/jump x/disp8\n"
"== data 0x2000\n"
"x:\n"
" 00 00 00 00\n"
);
CHECK_TRACE_CONTENTS(
"error: 'eb/jump x/disp8': can't refer to global variable 'x'\n"
// sub-optimal error message; should be
//? "error: can't jump to data (variable 'x')\n"
);
}
void test_global_variable_disallowed_in_call() {
Hide_errors = true;
run(
"== code 0x1\n"
"e8/call x/disp32\n"
"== data 0x2000\n"
"x:\n"
" 00 00 00 00\n"
);
CHECK_TRACE_CONTENTS(
"error: 'e8/call x/disp32': can't refer to global variable 'x'\n"
// sub-optimal error message; should be
//? "error: can't call to the data segment ('x')\n"
);
}
void test_global_variable_in_data_segment() {
run(
"== code 0x1\n"
"b9 x/imm32\n"
"== data 0x2000\n"
"x:\n"
" y/imm32\n"
"y:\n"
" 00 00 00 00\n"
);
// check that we loaded 'x' with the address of 'y'
CHECK_TRACE_CONTENTS(
"load: 0x00002000 -> 04\n"
"load: 0x00002001 -> 20\n"
"load: 0x00002002 -> 00\n"
"load: 0x00002003 -> 00\n"
);
CHECK_TRACE_COUNT("error", 0);
}
void test_raw_number_with_imm32_in_data_segment() {
run(
"== code 0x1\n"
"b9 x/imm32\n"
"== data 0x2000\n"
"x:\n"
" 1/imm32\n"
);
// check that we loaded 'x' with the address of 1
CHECK_TRACE_CONTENTS(
"load: 0x00002000 -> 01\n"
"load: 0x00002001 -> 00\n"
"load: 0x00002002 -> 00\n"
"load: 0x00002003 -> 00\n"
);
CHECK_TRACE_COUNT("error", 0);
}
void test_duplicate_global_variable() {
Hide_errors = true;
run(
"== code 0x1\n"
"40/increment-EAX\n"
"== data 0x2000\n"
"x:\n"
"x:\n"
" 00\n"
);
CHECK_TRACE_CONTENTS(
"error: duplicate global 'x'\n"
);
}
void test_global_variable_disp32_with_modrm() {
run(
"== code 0x1\n"
"8b/copy 0/mod/indirect 5/rm32/.disp32 2/r32/EDX x/disp32\n"
"== data 0x2000\n"
"x:\n"
" 00 00 00 00\n"
);
CHECK_TRACE_COUNT("error", 0);
}
void test_global_variable_disp32_with_call() {
transform(
"== code 0x1\n"
"foo:\n"
" e8/call bar/disp32\n"
"bar:\n"
);
CHECK_TRACE_COUNT("error", 0);
}
string to_full_string(const line& in) {
ostringstream out;
for (int i = 0; i < SIZE(in.words); ++i) {
if (i > 0) out << ' ';
out << in.words.at(i).data;
for (int j = 0; j < SIZE(in.words.at(i).metadata); ++j)
out << '/' << in.words.at(i).metadata.at(j);
}
return out.str();
}