# The stack shouldn't grow into the code area. == code check-stack: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax # 89/<- %eax 4/r32/esp 81 7/subop/compare %eax 0x48600/imm32 { 7f/jump-if-> break/disp8 (abort "stack overflow") } $check-stack:end: # . restore registers 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return show-stack-state: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax 51/push-ecx 52/push-edx # 89/<- %edx 4/r32/esp # save old cursor position (cursor-position 0) # => eax, ecx # print at top-right (set-cursor-position 0 0x70 0) (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %edx 0xf 0xc) # restore cursor position (set-cursor-position %eax %ecx) $check-stack:end: # . restore registers 5a/pop-to-edx 59/pop-to-ecx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return # Helper for debugging deeply recursive calls without logs or traces. # Turn it on, insert calls in the right places, and you get a terse sense of # important parts of the call stack. A poor sophont's stack trace. debug-print: # x: (addr array byte), fg: int, bg: int # x is very short; usually a single character # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax 51/push-ecx # { 81 7/subop/compare *Really-debug-print 0/imm32/false 74/jump-if-= break/disp8 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # clear the screen and continue if we got too close to the bottom (cursor-position 0) # => eax, ecx 81 7/subop/compare %ecx 0x28/imm32 75/jump-if-!= break/disp8 (clear-screen 0) (set-cursor-position 0 0 0) } $debug-print:end: # . restore registers 59/pop-to-ecx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return == data Really-debug-print: 0/imm32/false #? 1/imm32/true