https://github.com/akkartik/mu/blob/main/baremetal/313index-bounds-check.subx
 1 # Helper to check an array's bounds, and to abort if they're violated.
 2 # Really only intended to be called from code generated by mu.subx.
 3 
 4 == code
 5 
 6 __check-mu-array-bounds:  # index: int, elem-size: int, arr-size: int, function-name: (addr array byte), array-name: (addr array byte)
 7     # . prologue
 8     55/push-ebp
 9     89/<- %ebp 4/r32/esp
10     # . save registers
11     50/push-eax
12     51/push-ecx
13     52/push-edx
14     # . not bothering saving ebx; it's only clobbered if we're going to abort
15     # ecx = arr-size
16     8b/-> *(ebp+0x10) 1/r32/ecx
17     # var overflow/edx: int = 0
18     ba/copy-to-edx 0/imm32
19     # var offset/eax: int = index * elem-size
20     8b/-> *(ebp+8) 0/r32/eax
21     f7 4/subop/multiply-eax-with *(ebp+0xc)
22     # check for overflow
23     81 7/subop/compare %edx 0/imm32
24     0f 85/jump-if-!= __check-mu-array-bounds:overflow/disp32
25     # check bounds
26     39/compare %eax 1/r32/ecx
27     0f 82/jump-if-unsigned< $__check-mu-array-bounds:end/disp32  # negative index should always abort
28     # abort if necessary
29     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0)  # 3=cyan
30     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0)  # 3=cyan
31     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset " 3 0)  # 3=cyan
32     (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax 3 0)  # 3=cyan
33     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 " is too large for array '" 3 0)  # 3=cyan
34     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0)  # 3=cyan
35     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "'" 3 0)  # 3=cyan
36     {
37       eb/jump loop/disp8
38     }
39     # never gets here
40 $__check-mu-array-bounds:end:
41     # . restore registers
42     5a/pop-to-edx
43     59/pop-to-ecx
44     58/pop-to-eax
45     # . epilogue
46     89/<- %esp 5/r32/ebp
47     5d/pop-to-ebp
48     c3/return
49 
50 __check-mu-array-bounds:overflow:
51     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0)  # 3=cyan
52     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0)  # 3=cyan
53     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset to array '" 3 0)  # 3=cyan
54     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "offset to array overflowed 32 bits" 3 0)  # 3=cyan
55     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0)  # 3=cyan
56     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "' overflowed 32 bits" 3 0)  # 3=cyan
57     {
58       eb/jump loop/disp8
59     }
60     # never gets here