From ce2c1efc41470764126e9a1a7f4e0cfec4213587 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 14 Jul 2019 09:42:36 -0700 Subject: . --- html/subx/apps/crenshaw2-1b.subx.html | 1516 +++++++++++++++++---------------- 1 file changed, 760 insertions(+), 756 deletions(-) (limited to 'html/subx/apps/crenshaw2-1b.subx.html') diff --git a/html/subx/apps/crenshaw2-1b.subx.html b/html/subx/apps/crenshaw2-1b.subx.html index 92ae9cd8..e4e147a8 100644 --- a/html/subx/apps/crenshaw2-1b.subx.html +++ b/html/subx/apps/crenshaw2-1b.subx.html @@ -3,8 +3,8 @@ Mu - subx/apps/crenshaw2-1b.subx - - + + @@ -14,18 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS2Comment { color: #8a8a8a; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .SpecialChar { color: #d70000; } -.Constant { color: #008787; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.subxMinorFunction { color: #875f5f; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxTest { color: #5f8700; } -.CommentedCode { color: #8a8a8a; } -.subxH1Comment { color: #005faf; text-decoration: underline; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Constant { color: #008787; } +.subxMinorFunction { color: #875f5f; } +.subxS2Comment { color: #8a8a8a; } --> @@ -42,7 +41,7 @@ function JumpToLine() if (lineNum.indexOf('L') == -1) { lineNum = 'L'+lineNum; } - lineElem = document.getElementById(lineNum); + var lineElem = document.getElementById(lineNum); /* Always jump to new location even if the line was hidden inside a fold, or * we corrected the raw number to a line ID. */ @@ -94,753 +93,758 @@ if ('onhashchange' in window) { 31 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 32 33 Entry: # run tests if necessary, call 'compile' if not - 34 - 35 #? # for debugging: run a single test; don't bother setting status code - 36 #? e8/call test-get-num-reads-single-digit/disp32 - 37 #? eb/jump $main:end/disp8 - 38 - 39 # . prolog - 40 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 41 # - if argc > 1 and argv[1] == "test", then return run_tests() - 42 # . argc > 1 - 43 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP - 44 7e/jump-if-lesser-or-equal $run-main/disp8 - 45 # . argv[1] == "test" - 46 # . . push args - 47 68/push "test"/imm32 - 48 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 49 # . . call - 50 e8/call kernel-string-equal?/disp32 - 51 # . . discard args - 52 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 53 # . check result - 54 3d/compare-EAX-and 1/imm32 - 55 75/jump-if-not-equal $run-main/disp8 - 56 # . run-tests() - 57 e8/call run-tests/disp32 - 58 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 59 eb/jump $main:end/disp8 - 60 $run-main: - 61 # - otherwise read a program from stdin and emit its translation to stdout - 62 # var ed/EAX : exit-descriptor - 63 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 64 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - 65 # configure ed to really exit() - 66 # . ed->target = 0 - 67 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - 68 # return compile(Stdin, 1/stdout, 2/stderr, ed) - 69 # . . push args - 70 50/push-EAX/ed - 71 68/push 2/imm32/stderr - 72 68/push 1/imm32/stdout - 73 68/push Stdin/imm32 - 74 # . . call - 75 e8/call compile/disp32 - 76 # . . discard args - 77 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - 78 # . syscall(exit, 0) - 79 bb/copy-to-EBX 0/imm32 - 80 $main:end: - 81 b8/copy-to-EAX 1/imm32/exit - 82 cd/syscall 0x80/imm8 - 83 - 84 # the main entry point - 85 compile: # in : (address buffered-file), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> - 86 # . prolog - 87 55/push-EBP - 88 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 89 # . save registers - 90 50/push-EAX - 91 51/push-ECX - 92 # prime the pump - 93 # . Look = get-char(in) - 94 # . . push args - 95 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 96 # . . call - 97 e8/call get-char/disp32 - 98 # . . discard args - 99 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -100 # var num/ECX : (address stream) on the stack -101 # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. -102 # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. -103 # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. -104 # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. -105 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP -106 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -107 # initialize the stream -108 # . num->length = 7 -109 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) -110 # . clear-stream(num) -111 # . . push args -112 51/push-ECX -113 # . . call -114 e8/call clear-stream/disp32 -115 # . . discard args -116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -117 # read a digit from 'in' into 'num' -118 # . get-num(in, num, err, ed) -119 # . . push args -120 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -121 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -122 51/push-ECX/num -123 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -124 # . . call -125 e8/call get-num/disp32 -126 # . . discard args -127 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -128 # render 'num' into the following template on 'out': -129 # bb/copy-to-EBX _num_ -130 # b8/copy-to-EAX 1/imm32/exit -131 # cd/syscall 0x80/imm8 -132 # -133 # . write(out, "bb/copy-to-EBX ") -134 # . . push args -135 68/push "bb/copy-to-EBX "/imm32 -136 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -137 # . . call -138 e8/call write/disp32 -139 # . . discard args -140 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -141 # . write-stream(out, num) -142 # . . push args -143 51/push-ECX/num -144 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -145 # . . call -146 e8/call write-stream/disp32 -147 # . . discard args -148 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -149 # . write(out, Newline) -150 # . . push args -151 68/push Newline/imm32 -152 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -153 # . . call -154 e8/call write/disp32 -155 # . . discard args -156 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -157 # . write(out, "b8/copy-to-EAX 1/imm32/exit\n") -158 # . . push args -159 68/push "b8/copy-to-EAX 1/imm32/exit\n"/imm32 -160 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -161 # . . call -162 e8/call write/disp32 -163 # . . discard args -164 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -165 # . write(out, "cd/syscall 0x80/imm8\n") -166 # . . push args -167 68/push "cd/syscall 0x80/imm8\n"/imm32 -168 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -169 # . . call -170 e8/call write/disp32 -171 # . . discard args -172 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -173 $compile:end: -174 # . restore registers -175 59/pop-to-ECX -176 58/pop-to-EAX -177 # . epilog -178 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -179 5d/pop-to-EBP -180 c3/return -181 -182 # Read a sequence of digits into 'out'. Abort if there are none, or if there is -183 # no space in 'out'. -184 # Input comes from the global variable 'Look' (first byte) and the argument -185 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit. -186 get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> -187 # pseudocode: -188 # if (!is-digit?(Look)) expected(ed, err, "integer") -189 # do -190 # if out->write >= out->length -191 # write(err, "Error: too many digits in number\n") -192 # stop(ed, 1) -193 # out->data[out->write] = LSB(Look) -194 # ++out->write -195 # Look = get-char(in) -196 # while is-digit?(Look) -197 # This is complicated because I don't want to hard-code the error strategy in -198 # a general helper like write-byte-buffered. Maybe I should just create a -199 # local helper. -200 # -201 # within the loop we'll try to keep things in registers: -202 # in: ESI -203 # out: EDI -204 # out->write: ECX (cached copy; need to keep in sync) -205 # out->length: EDX -206 # temporaries: EAX, EBX -207 # We can't allocate Look to a register because it gets written implicitly in -208 # get-char in each iteration of the loop. (Thereby demonstrating that it's -209 # not the right interface for us. But we'll keep it just to follow Crenshaw.) -210 # -211 # . prolog -212 55/push-EBP -213 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -214 # - if (is-digit?(Look)) expected(ed, err, "integer") -215 # . EAX = is-digit?(Look) -216 # . . push args -217 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look -218 # . . call -219 e8/call is-digit?/disp32 -220 # . . discard args -221 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -222 # . if (EAX == 0) -223 3d/compare-EAX-and 0/imm32 -224 75/jump-if-not-equal $get-num:main/disp8 -225 # . expected(ed, err, "integer") -226 # . . push args -227 68/push "integer"/imm32 -228 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -229 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -230 # . . call -231 e8/call expected/disp32 # never returns -232 # . . discard args -233 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -234 $get-num:main: -235 # - otherwise read a digit -236 # . save registers -237 50/push-EAX -238 51/push-ECX -239 52/push-EDX -240 53/push-EBX -241 56/push-ESI -242 57/push-EDI -243 # read necessary variables to registers -244 # ESI = in -245 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -246 # EDI = out -247 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI -248 # ECX = out->write -249 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX -250 # EDX = out->length -251 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX -252 $get-num:loop: -253 # if (out->write >= out->length) error -254 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX -255 7d/jump-if-lesser $get-num:loop-stage2/disp8 -256 # . error(ed, err, msg) # TODO: show full number -257 # . . push args -258 68/push "get-num: too many digits in number"/imm32 -259 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -260 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -261 # . . call -262 e8/call error/disp32 # never returns -263 # . . discard args -264 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -265 $get-num:loop-stage2: -266 # out->data[out->write] = LSB(Look) -267 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX -268 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX -269 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX -270 # ++out->write -271 41/increment-ECX -272 # Look = get-char(in) -273 # . . push args -274 56/push-ESI -275 # . . call -276 e8/call get-char/disp32 -277 # . . discard args -278 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -279 # if (is-digit?(Look)) loop -280 # . EAX = is-digit?(Look) -281 # . . push args -282 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look -283 # . . call -284 e8/call is-digit?/disp32 -285 # . . discard args -286 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -287 # . if (EAX != 0) loop -288 3d/compare-EAX-and 0/imm32 -289 0f 85/jump-if-not-equal $get-num:loop/disp32 -290 $get-num:loop-end: -291 # persist necessary variables from registers -292 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI -293 $get-num:end: -294 # . restore registers -295 5f/pop-to-EDI -296 5e/pop-to-ESI -297 5b/pop-to-EBX -298 5a/pop-to-EDX -299 59/pop-to-ECX -300 58/pop-to-EAX -301 # . epilog -302 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -303 5d/pop-to-EBP -304 c3/return -305 -306 test-get-num-reads-single-digit: -307 # - check that get-num returns first character if it's a digit -308 # This test uses exit-descriptors. Use EBP for setting up local variables. -309 55/push-EBP -310 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -311 # clear all streams -312 # . clear-stream(_test-stream) -313 # . . push args -314 68/push _test-stream/imm32 -315 # . . call -316 e8/call clear-stream/disp32 -317 # . . discard args -318 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -319 # . clear-stream(_test-buffered-file+4) -320 # . . push args -321 b8/copy-to-EAX _test-buffered-file/imm32 -322 05/add-to-EAX 4/imm32 -323 50/push-EAX -324 # . . call -325 e8/call clear-stream/disp32 -326 # . . discard args -327 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -328 # . clear-stream(_test-output-stream) -329 # . . push args -330 68/push _test-output-stream/imm32 -331 # . . call -332 e8/call clear-stream/disp32 -333 # . . discard args -334 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -335 # . clear-stream(_test-error-stream) -336 # . . push args -337 68/push _test-error-stream/imm32 -338 # . . call -339 e8/call clear-stream/disp32 -340 # . . discard args -341 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -342 # initialize 'in' -343 # . write(_test-stream, "3") -344 # . . push args -345 68/push "3"/imm32 -346 68/push _test-stream/imm32 -347 # . . call -348 e8/call write/disp32 -349 # . . discard args -350 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -351 # initialize exit-descriptor 'ed' for the call to 'get-num' below -352 # . var ed/EAX : exit-descriptor -353 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -354 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -355 # . tailor-exit-descriptor(ed, 16) -356 # . . push args -357 68/push 0x10/imm32/nbytes-of-args-for-get-num -358 50/push-EAX/ed -359 # . . call -360 e8/call tailor-exit-descriptor/disp32 -361 # . . discard args -362 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -363 # prime the pump -364 # . get-char(_test-buffered-file) -365 # . . push args -366 68/push _test-buffered-file/imm32 -367 # . . call -368 e8/call get-char/disp32 -369 # . . discard args -370 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -371 # get-num(in, out, err, ed) -372 # . . push args -373 50/push-EAX/ed -374 68/push _test-error-stream/imm32 -375 68/push _test-output-stream/imm32 -376 68/push _test-buffered-file/imm32 -377 # . . call -378 e8/call get-num/disp32 -379 # registers except ESP may be clobbered at this point -380 # . . discard args -381 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -382 # check-ints-equal(*_test-output-stream->data, '3', msg) -383 # . . push args -384 68/push "F - test-get-num-reads-single-digit"/imm32 -385 68/push 0x33/imm32 -386 b8/copy-to-EAX _test-output-stream/imm32 -387 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -388 # . . call -389 e8/call check-ints-equal/disp32 -390 # . . discard args -391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -392 # . reclaim locals -393 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -394 5d/pop-to-EBP -395 c3/return -396 -397 test-get-num-aborts-on-non-digit-in-Look: -398 # - check that get-num returns first character if it's a digit -399 # This test uses exit-descriptors. Use EBP for setting up local variables. -400 55/push-EBP -401 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -402 # clear all streams -403 # . clear-stream(_test-stream) -404 # . . push args -405 68/push _test-stream/imm32 -406 # . . call -407 e8/call clear-stream/disp32 -408 # . . discard args -409 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -410 # . clear-stream(_test-buffered-file+4) -411 # . . push args -412 b8/copy-to-EAX _test-buffered-file/imm32 -413 05/add-to-EAX 4/imm32 -414 50/push-EAX -415 # . . call -416 e8/call clear-stream/disp32 -417 # . . discard args -418 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -419 # . clear-stream(_test-output-stream) -420 # . . push args -421 68/push _test-output-stream/imm32 -422 # . . call -423 e8/call clear-stream/disp32 -424 # . . discard args -425 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -426 # . clear-stream(_test-error-stream) -427 # . . push args -428 68/push _test-error-stream/imm32 -429 # . . call -430 e8/call clear-stream/disp32 -431 # . . discard args -432 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -433 # initialize 'in' -434 # . write(_test-stream, "3") -435 # . . push args -436 68/push "3"/imm32 -437 68/push _test-stream/imm32 -438 # . . call -439 e8/call write/disp32 -440 # . . discard args -441 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -442 # initialize exit-descriptor 'ed' for the call to 'get-num' below -443 # . var ed/EAX : (address exit-descriptor) -444 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -445 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -446 # . tailor-exit-descriptor(ed, 16) -447 # . . push args -448 68/push 0x10/imm32/nbytes-of-args-for-get-num -449 50/push-EAX/ed -450 # . . call -451 e8/call tailor-exit-descriptor/disp32 -452 # . . discard args -453 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -454 # *don't* prime the pump -455 # get-num(in, out, err, ed) -456 # . . push args -457 50/push-EAX/ed -458 68/push _test-error-stream/imm32 -459 68/push _test-output-stream/imm32 -460 68/push _test-buffered-file/imm32 -461 # . . call -462 e8/call get-num/disp32 -463 # registers except ESP may be clobbered at this point -464 # . . discard args -465 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -466 # check that get-num tried to call exit(1) -467 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 -468 # . . push args -469 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 -470 68/push 2/imm32 -471 # . . push ed->value -472 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -473 # . . call -474 e8/call check-ints-equal/disp32 -475 # . . discard args -476 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -477 # . reclaim locals -478 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -479 5d/pop-to-EBP -480 c3/return -481 -482 test-get-num-reads-multiple-digits: -483 # - check that get-num returns all initial digits until it encounters a non-digit -484 # This test uses exit-descriptors. Use EBP for setting up local variables. -485 55/push-EBP -486 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -487 # clear all streams -488 # . clear-stream(_test-stream) -489 # . . push args -490 68/push _test-stream/imm32 -491 # . . call -492 e8/call clear-stream/disp32 -493 # . . discard args -494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -495 # . clear-stream(_test-buffered-file+4) -496 # . . push args -497 b8/copy-to-EAX _test-buffered-file/imm32 -498 05/add-to-EAX 4/imm32 -499 50/push-EAX -500 # . . call -501 e8/call clear-stream/disp32 -502 # . . discard args -503 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -504 # . clear-stream(_test-output-stream) -505 # . . push args -506 68/push _test-output-stream/imm32 -507 # . . call -508 e8/call clear-stream/disp32 -509 # . . discard args -510 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -511 # . clear-stream(_test-error-stream) -512 # . . push args -513 68/push _test-error-stream/imm32 -514 # . . call -515 e8/call clear-stream/disp32 -516 # . . discard args -517 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -518 # initialize 'in' -519 # . write(_test-stream, "3456 x") -520 # . . push args -521 68/push "3456"/imm32 -522 68/push _test-stream/imm32 -523 # . . call -524 e8/call write/disp32 -525 # . . discard args -526 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -527 # initialize exit-descriptor 'ed' for the call to 'get-num' below -528 # . var ed/EAX : (address exit-descriptor) -529 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -530 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -531 # . tailor-exit-descriptor(ed, 16) -532 # . . push args -533 68/push 0x10/imm32/nbytes-of-args-for-get-num -534 50/push-EAX/ed -535 # . . call -536 e8/call tailor-exit-descriptor/disp32 -537 # . . discard args -538 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -539 # prime the pump -540 # . get-char(_test-buffered-file) -541 # . . push args -542 68/push _test-buffered-file/imm32 -543 # . . call -544 e8/call get-char/disp32 -545 # . . discard args -546 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -547 # get-num(in, out, err, ed) -548 # . . push args -549 50/push-EAX/ed -550 68/push _test-error-stream/imm32 -551 68/push _test-output-stream/imm32 -552 68/push _test-buffered-file/imm32 -553 # . . call -554 e8/call get-num/disp32 -555 # registers except ESP may be clobbered at this point -556 # . . discard args -557 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -558 # check-ints-equal(*_test-output-stream->data, '3456', msg) -559 # . . push args -560 68/push "F - test-get-num-reads-multiple-digits"/imm32 -561 68/push 0x36353433/imm32 -562 b8/copy-to-EAX _test-output-stream/imm32 -563 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -564 # . . call -565 e8/call check-ints-equal/disp32 -566 # . . discard args -567 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -568 # . reclaim locals -569 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -570 5d/pop-to-EBP -571 c3/return -572 -573 test-get-num-reads-multiple-digits-followed-by-nondigit: -574 # - check that get-num returns all initial digits until it encounters a non-digit -575 # This test uses exit-descriptors. Use EBP for setting up local variables. -576 55/push-EBP -577 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -578 # clear all streams -579 # . clear-stream(_test-stream) -580 # . . push args -581 68/push _test-stream/imm32 -582 # . . call -583 e8/call clear-stream/disp32 -584 # . . discard args -585 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -586 # . clear-stream(_test-buffered-file+4) -587 # . . push args -588 b8/copy-to-EAX _test-buffered-file/imm32 -589 05/add-to-EAX 4/imm32 -590 50/push-EAX -591 # . . call -592 e8/call clear-stream/disp32 -593 # . . discard args -594 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -595 # . clear-stream(_test-output-stream) -596 # . . push args -597 68/push _test-output-stream/imm32 -598 # . . call -599 e8/call clear-stream/disp32 -600 # . . discard args -601 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -602 # . clear-stream(_test-error-stream) -603 # . . push args -604 68/push _test-error-stream/imm32 -605 # . . call -606 e8/call clear-stream/disp32 -607 # . . discard args -608 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -609 # initialize 'in' -610 # . write(_test-stream, "3456 x") -611 # . . push args -612 68/push "3456 x"/imm32 -613 68/push _test-stream/imm32 -614 # . . call -615 e8/call write/disp32 -616 # . . discard args -617 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -618 # initialize exit-descriptor 'ed' for the call to 'get-num' below -619 # . var ed/EAX : (address exit-descriptor) -620 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -621 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -622 # . tailor-exit-descriptor(ed, 16) -623 # . . push args -624 68/push 0x10/imm32/nbytes-of-args-for-get-num -625 50/push-EAX/ed -626 # . . call -627 e8/call tailor-exit-descriptor/disp32 -628 # . . discard args -629 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -630 # prime the pump -631 # . get-char(_test-buffered-file) -632 # . . push args -633 68/push _test-buffered-file/imm32 -634 # . . call -635 e8/call get-char/disp32 -636 # . . discard args -637 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -638 # get-num(in, out, err, ed) -639 # . . push args -640 50/push-EAX/ed -641 68/push _test-error-stream/imm32 -642 68/push _test-output-stream/imm32 -643 68/push _test-buffered-file/imm32 -644 # . . call -645 e8/call get-num/disp32 -646 # registers except ESP may be clobbered at this point -647 # . . discard args -648 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -649 # check-ints-equal(*_test-output-stream->data, '3456', msg) -650 # . . push args -651 68/push "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32 -652 68/push 0x36353433/imm32 -653 b8/copy-to-EAX _test-output-stream/imm32 -654 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -655 # . . call -656 e8/call check-ints-equal/disp32 -657 # . . discard args -658 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -659 # . reclaim locals -660 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -661 5d/pop-to-EBP -662 c3/return -663 -664 ## helpers -665 -666 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) -667 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> -668 # . prolog -669 55/push-EBP -670 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -671 # write(f, "Error: ") -672 # . . push args -673 68/push "Error: "/imm32 -674 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -675 # . . call -676 e8/call write/disp32 -677 # . . discard args -678 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -679 # write(f, s) -680 # . . push args -681 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -682 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -683 # . . call -684 e8/call write/disp32 -685 # . . discard args -686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -687 # write(f, " expected\n") -688 # . . push args -689 68/push " expected\n"/imm32 -690 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -691 # . . call -692 e8/call write/disp32 -693 # . . discard args -694 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -695 # stop(ed, 1) -696 # . . push args -697 68/push 1/imm32 -698 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -699 # . . call -700 e8/call stop/disp32 -701 # should never get past this point -702 $expected:dead-end: -703 # . epilog -704 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -705 5d/pop-to-EBP -706 c3/return -707 -708 # read a byte from 'f', and save it in 'Look' -709 get-char: # f : (address buffered-file) -> <void> -710 # . prolog -711 55/push-EBP -712 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -713 # . save registers -714 50/push-EAX -715 # EAX = read-byte-buffered(f) -716 # . . push args -717 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -718 # . . call -719 e8/call read-byte-buffered/disp32 -720 # . . discard args -721 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -722 # save EAX to Look -723 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look -724 $get-char:end: -725 # . restore registers -726 58/pop-to-EAX -727 # . epilog -728 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -729 5d/pop-to-EBP -730 c3/return -731 -732 is-digit?: # c : int -> EAX : boolean -733 # . prolog -734 55/push-EBP -735 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -736 # EAX = false -737 b8/copy-to-EAX 0/imm32 -738 # if (c < '0') return false -739 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) -740 7c/jump-if-lesser $is-digit?:end/disp8 -741 # if (c > '9') return false -742 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) -743 7f/jump-if-greater $is-digit?:end/disp8 -744 # otherwise return true -745 b8/copy-to-EAX 1/imm32 -746 $is-digit?:end: -747 # . epilog -748 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -749 5d/pop-to-EBP -750 c3/return -751 -752 == data -753 -754 Look: # (char with some extra padding) -755 0/imm32 + 34 # initialize heap + 35 # . Heap = new-segment(64KB) + 36 # . . push args + 37 68/push Heap/imm32 + 38 68/push 0x10000/imm32/64KB + 39 # . . call + 40 e8/call new-segment/disp32 + 41 # . . discard args + 42 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 43 + 44 # . prolog + 45 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 46 # - if argc > 1 and argv[1] == "test", then return run_tests() + 47 # . argc > 1 + 48 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP + 49 7e/jump-if-lesser-or-equal $run-main/disp8 + 50 # . argv[1] == "test" + 51 # . . push args + 52 68/push "test"/imm32 + 53 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 54 # . . call + 55 e8/call kernel-string-equal?/disp32 + 56 # . . discard args + 57 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 58 # . check result + 59 3d/compare-EAX-and 1/imm32 + 60 75/jump-if-not-equal $run-main/disp8 + 61 # . run-tests() + 62 e8/call run-tests/disp32 + 63 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 64 eb/jump $main:end/disp8 + 65 $run-main: + 66 # - otherwise read a program from stdin and emit its translation to stdout + 67 # var ed/EAX : exit-descriptor + 68 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 69 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX + 70 # configure ed to really exit() + 71 # . ed->target = 0 + 72 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX + 73 # return compile(Stdin, 1/stdout, 2/stderr, ed) + 74 # . . push args + 75 50/push-EAX/ed + 76 68/push 2/imm32/stderr + 77 68/push 1/imm32/stdout + 78 68/push Stdin/imm32 + 79 # . . call + 80 e8/call compile/disp32 + 81 # . . discard args + 82 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 83 # . syscall(exit, 0) + 84 bb/copy-to-EBX 0/imm32 + 85 $main:end: + 86 b8/copy-to-EAX 1/imm32/exit + 87 cd/syscall 0x80/imm8 + 88 + 89 # the main entry point + 90 compile: # in : (address buffered-file), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> + 91 # . prolog + 92 55/push-EBP + 93 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 94 # . save registers + 95 50/push-EAX + 96 51/push-ECX + 97 # prime the pump + 98 # . Look = get-char(in) + 99 # . . push args +100 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +101 # . . call +102 e8/call get-char/disp32 +103 # . . discard args +104 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +105 # var num/ECX : (address stream) on the stack +106 # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. +107 # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. +108 # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. +109 # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. +110 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP +111 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +112 # initialize the stream +113 # . num->length = 7 +114 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) +115 # . clear-stream(num) +116 # . . push args +117 51/push-ECX +118 # . . call +119 e8/call clear-stream/disp32 +120 # . . discard args +121 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +122 # read a digit from 'in' into 'num' +123 # . get-num(in, num, err, ed) +124 # . . push args +125 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +126 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +127 51/push-ECX/num +128 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +129 # . . call +130 e8/call get-num/disp32 +131 # . . discard args +132 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +133 # render 'num' into the following template on 'out': +134 # bb/copy-to-EBX _num_ +135 # b8/copy-to-EAX 1/imm32/exit +136 # cd/syscall 0x80/imm8 +137 # +138 # . write(out, "bb/copy-to-EBX ") +139 # . . push args +140 68/push "bb/copy-to-EBX "/imm32 +141 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +142 # . . call +143 e8/call write/disp32 +144 # . . discard args +145 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +146 # . write-stream(out, num) +147 # . . push args +148 51/push-ECX/num +149 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +150 # . . call +151 e8/call write-stream/disp32 +152 # . . discard args +153 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +154 # . write(out, Newline) +155 # . . push args +156 68/push Newline/imm32 +157 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +158 # . . call +159 e8/call write/disp32 +160 # . . discard args +161 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +162 # . write(out, "b8/copy-to-EAX 1/imm32/exit\n") +163 # . . push args +164 68/push "b8/copy-to-EAX 1/imm32/exit\n"/imm32 +165 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +166 # . . call +167 e8/call write/disp32 +168 # . . discard args +169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +170 # . write(out, "cd/syscall 0x80/imm8\n") +171 # . . push args +172 68/push "cd/syscall 0x80/imm8\n"/imm32 +173 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +174 # . . call +175 e8/call write/disp32 +176 # . . discard args +177 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +178 $compile:end: +179 # . restore registers +180 59/pop-to-ECX +181 58/pop-to-EAX +182 # . epilog +183 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +184 5d/pop-to-EBP +185 c3/return +186 +187 # Read a sequence of digits into 'out'. Abort if there are none, or if there is +188 # no space in 'out'. +189 # Input comes from the global variable 'Look' (first byte) and the argument +190 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit. +191 get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> +192 # pseudocode: +193 # if (!is-digit?(Look)) expected(ed, err, "integer") +194 # do +195 # if out->write >= out->length +196 # write(err, "Error: too many digits in number\n") +197 # stop(ed, 1) +198 # out->data[out->write] = LSB(Look) +199 # ++out->write +200 # Look = get-char(in) +201 # while is-digit?(Look) +202 # This is complicated because I don't want to hard-code the error strategy in +203 # a general helper like write-byte-buffered. Maybe I should just create a +204 # local helper. +205 # +206 # within the loop we'll try to keep things in registers: +207 # in: ESI +208 # out: EDI +209 # out->write: ECX (cached copy; need to keep in sync) +210 # out->length: EDX +211 # temporaries: EAX, EBX +212 # We can't allocate Look to a register because it gets written implicitly in +213 # get-char in each iteration of the loop. (Thereby demonstrating that it's +214 # not the right interface for us. But we'll keep it just to follow Crenshaw.) +215 # +216 # . prolog +217 55/push-EBP +218 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +219 # - if (is-digit?(Look)) expected(ed, err, "integer") +220 # . EAX = is-digit?(Look) +221 # . . push args +222 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look +223 # . . call +224 e8/call is-digit?/disp32 +225 # . . discard args +226 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +227 # . if (EAX == 0) +228 3d/compare-EAX-and 0/imm32 +229 75/jump-if-not-equal $get-num:main/disp8 +230 # . expected(ed, err, "integer") +231 # . . push args +232 68/push "integer"/imm32 +233 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +234 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +235 # . . call +236 e8/call expected/disp32 # never returns +237 # . . discard args +238 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +239 $get-num:main: +240 # - otherwise read a digit +241 # . save registers +242 50/push-EAX +243 51/push-ECX +244 52/push-EDX +245 53/push-EBX +246 56/push-ESI +247 57/push-EDI +248 # read necessary variables to registers +249 # ESI = in +250 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +251 # EDI = out +252 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI +253 # ECX = out->write +254 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX +255 # EDX = out->length +256 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX +257 $get-num:loop: +258 # if (out->write >= out->length) error +259 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX +260 7d/jump-if-lesser $get-num:loop-stage2/disp8 +261 # . error(ed, err, msg) # TODO: show full number +262 # . . push args +263 68/push "get-num: too many digits in number"/imm32 +264 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +265 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +266 # . . call +267 e8/call error/disp32 # never returns +268 # . . discard args +269 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +270 $get-num:loop-stage2: +271 # out->data[out->write] = LSB(Look) +272 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX +273 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX +274 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX +275 # ++out->write +276 41/increment-ECX +277 # Look = get-char(in) +278 # . . push args +279 56/push-ESI +280 # . . call +281 e8/call get-char/disp32 +282 # . . discard args +283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +284 # if (is-digit?(Look)) loop +285 # . EAX = is-digit?(Look) +286 # . . push args +287 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look +288 # . . call +289 e8/call is-digit?/disp32 +290 # . . discard args +291 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +292 # . if (EAX != 0) loop +293 3d/compare-EAX-and 0/imm32 +294 0f 85/jump-if-not-equal $get-num:loop/disp32 +295 $get-num:loop-end: +296 # persist necessary variables from registers +297 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI +298 $get-num:end: +299 # . restore registers +300 5f/pop-to-EDI +301 5e/pop-to-ESI +302 5b/pop-to-EBX +303 5a/pop-to-EDX +304 59/pop-to-ECX +305 58/pop-to-EAX +306 # . epilog +307 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +308 5d/pop-to-EBP +309 c3/return +310 +311 test-get-num-reads-single-digit: +312 # - check that get-num returns first character if it's a digit +313 # This test uses exit-descriptors. Use EBP for setting up local variables. +314 55/push-EBP +315 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +316 # clear all streams +317 # . clear-stream(_test-stream) +318 # . . push args +319 68/push _test-stream/imm32 +320 # . . call +321 e8/call clear-stream/disp32 +322 # . . discard args +323 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +324 # . clear-stream(_test-buffered-file+4) +325 # . . push args +326 b8/copy-to-EAX _test-buffered-file/imm32 +327 05/add-to-EAX 4/imm32 +328 50/push-EAX +329 # . . call +330 e8/call clear-stream/disp32 +331 # . . discard args +332 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +333 # . clear-stream(_test-output-stream) +334 # . . push args +335 68/push _test-output-stream/imm32 +336 # . . call +337 e8/call clear-stream/disp32 +338 # . . discard args +339 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +340 # . clear-stream(_test-error-stream) +341 # . . push args +342 68/push _test-error-stream/imm32 +343 # . . call +344 e8/call clear-stream/disp32 +345 # . . discard args +346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +347 # initialize 'in' +348 # . write(_test-stream, "3") +349 # . . push args +350 68/push "3"/imm32 +351 68/push _test-stream/imm32 +352 # . . call +353 e8/call write/disp32 +354 # . . discard args +355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +356 # initialize exit-descriptor 'ed' for the call to 'get-num' below +357 # . var ed/EAX : exit-descriptor +358 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +359 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +360 # . tailor-exit-descriptor(ed, 16) +361 # . . push args +362 68/push 0x10/imm32/nbytes-of-args-for-get-num +363 50/push-EAX/ed +364 # . . call +365 e8/call tailor-exit-descriptor/disp32 +366 # . . discard args +367 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +368 # prime the pump +369 # . get-char(_test-buffered-file) +370 # . . push args +371 68/push _test-buffered-file/imm32 +372 # . . call +373 e8/call get-char/disp32 +374 # . . discard args +375 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +376 # get-num(in, out, err, ed) +377 # . . push args +378 50/push-EAX/ed +379 68/push _test-error-stream/imm32 +380 68/push _test-output-stream/imm32 +381 68/push _test-buffered-file/imm32 +382 # . . call +383 e8/call get-num/disp32 +384 # registers except ESP may be clobbered at this point +385 # . . discard args +386 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +387 # check-ints-equal(*_test-output-stream->data, '3', msg) +388 # . . push args +389 68/push "F - test-get-num-reads-single-digit"/imm32 +390 68/push 0x33/imm32 +391 b8/copy-to-EAX _test-output-stream/imm32 +392 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +393 # . . call +394 e8/call check-ints-equal/disp32 +395 # . . discard args +396 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +397 # . reclaim locals +398 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +399 5d/pop-to-EBP +400 c3/return +401 +402 test-get-num-aborts-on-non-digit-in-Look: +403 # - check that get-num returns first character if it's a digit +404 # This test uses exit-descriptors. Use EBP for setting up local variables. +405 55/push-EBP +406 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +407 # clear all streams +408 # . clear-stream(_test-stream) +409 # . . push args +410 68/push _test-stream/imm32 +411 # . . call +412 e8/call clear-stream/disp32 +413 # . . discard args +414 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +415 # . clear-stream(_test-buffered-file+4) +416 # . . push args +417 b8/copy-to-EAX _test-buffered-file/imm32 +418 05/add-to-EAX 4/imm32 +419 50/push-EAX +420 # . . call +421 e8/call clear-stream/disp32 +422 # . . discard args +423 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +424 # . clear-stream(_test-output-stream) +425 # . . push args +426 68/push _test-output-stream/imm32 +427 # . . call +428 e8/call clear-stream/disp32 +429 # . . discard args +430 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +431 # . clear-stream(_test-error-stream) +432 # . . push args +433 68/push _test-error-stream/imm32 +434 # . . call +435 e8/call clear-stream/disp32 +436 # . . discard args +437 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +438 # initialize 'in' +439 # . write(_test-stream, "3") +440 # . . push args +441 68/push "3"/imm32 +442 68/push _test-stream/imm32 +443 # . . call +444 e8/call write/disp32 +445 # . . discard args +446 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +447 # initialize exit-descriptor 'ed' for the call to 'get-num' below +448 # . var ed/EAX : (address exit-descriptor) +449 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +450 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +451 # . tailor-exit-descriptor(ed, 16) +452 # . . push args +453 68/push 0x10/imm32/nbytes-of-args-for-get-num +454 50/push-EAX/ed +455 # . . call +456 e8/call tailor-exit-descriptor/disp32 +457 # . . discard args +458 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +459 # *don't* prime the pump +460 # get-num(in, out, err, ed) +461 # . . push args +462 50/push-EAX/ed +463 68/push _test-error-stream/imm32 +464 68/push _test-output-stream/imm32 +465 68/push _test-buffered-file/imm32 +466 # . . call +467 e8/call get-num/disp32 +468 # registers except ESP may be clobbered at this point +469 # . . discard args +470 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +471 # check that get-num tried to call exit(1) +472 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 +473 # . . push args +474 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 +475 68/push 2/imm32 +476 # . . push ed->value +477 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +478 # . . call +479 e8/call check-ints-equal/disp32 +480 # . . discard args +481 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +482 # . reclaim locals +483 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +484 5d/pop-to-EBP +485 c3/return +486 +487 test-get-num-reads-multiple-digits: +488 # - check that get-num returns all initial digits until it encounters a non-digit +489 # This test uses exit-descriptors. Use EBP for setting up local variables. +490 55/push-EBP +491 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +492 # clear all streams +493 # . clear-stream(_test-stream) +494 # . . push args +495 68/push _test-stream/imm32 +496 # . . call +497 e8/call clear-stream/disp32 +498 # . . discard args +499 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +500 # . clear-stream(_test-buffered-file+4) +501 # . . push args +502 b8/copy-to-EAX _test-buffered-file/imm32 +503 05/add-to-EAX 4/imm32 +504 50/push-EAX +505 # . . call +506 e8/call clear-stream/disp32 +507 # . . discard args +508 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +509 # . clear-stream(_test-output-stream) +510 # . . push args +511 68/push _test-output-stream/imm32 +512 # . . call +513 e8/call clear-stream/disp32 +514 # . . discard args +515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +516 # . clear-stream(_test-error-stream) +517 # . . push args +518 68/push _test-error-stream/imm32 +519 # . . call +520 e8/call clear-stream/disp32 +521 # . . discard args +522 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +523 # initialize 'in' +524 # . write(_test-stream, "3456 x") +525 # . . push args +526 68/push "3456"/imm32 +527 68/push _test-stream/imm32 +528 # . . call +529 e8/call write/disp32 +530 # . . discard args +531 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +532 # initialize exit-descriptor 'ed' for the call to 'get-num' below +533 # . var ed/EAX : (address exit-descriptor) +534 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +535 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +536 # . tailor-exit-descriptor(ed, 16) +537 # . . push args +538 68/push 0x10/imm32/nbytes-of-args-for-get-num +539 50/push-EAX/ed +540 # . . call +541 e8/call tailor-exit-descriptor/disp32 +542 # . . discard args +543 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +544 # prime the pump +545 # . get-char(_test-buffered-file) +546 # . . push args +547 68/push _test-buffered-file/imm32 +548 # . . call +549 e8/call get-char/disp32 +550 # . . discard args +551 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +552 # get-num(in, out, err, ed) +553 # . . push args +554 50/push-EAX/ed +555 68/push _test-error-stream/imm32 +556 68/push _test-output-stream/imm32 +557 68/push _test-buffered-file/imm32 +558 # . . call +559 e8/call get-num/disp32 +560 # registers except ESP may be clobbered at this point +561 # . . discard args +562 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +563 # check-ints-equal(*_test-output-stream->data, '3456', msg) +564 # . . push args +565 68/push "F - test-get-num-reads-multiple-digits"/imm32 +566 68/push 0x36353433/imm32 +567 b8/copy-to-EAX _test-output-stream/imm32 +568 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +569 # . . call +570 e8/call check-ints-equal/disp32 +571 # . . discard args +572 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +573 # . reclaim locals +574 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +575 5d/pop-to-EBP +576 c3/return +577 +578 test-get-num-reads-multiple-digits-followed-by-nondigit: +579 # - check that get-num returns all initial digits until it encounters a non-digit +580 # This test uses exit-descriptors. Use EBP for setting up local variables. +581 55/push-EBP +582 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +583 # clear all streams +584 # . clear-stream(_test-stream) +585 # . . push args +586 68/push _test-stream/imm32 +587 # . . call +588 e8/call clear-stream/disp32 +589 # . . discard args +590 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +591 # . clear-stream(_test-buffered-file+4) +592 # . . push args +593 b8/copy-to-EAX _test-buffered-file/imm32 +594 05/add-to-EAX 4/imm32 +595 50/push-EAX +596 # . . call +597 e8/call clear-stream/disp32 +598 # . . discard args +599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +600 # . clear-stream(_test-output-stream) +601 # . . push args +602 68/push _test-output-stream/imm32 +603 # . . call +604 e8/call clear-stream/disp32 +605 # . . discard args +606 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +607 # . clear-stream(_test-error-stream) +608 # . . push args +609 68/push _test-error-stream/imm32 +610 # . . call +611 e8/call clear-stream/disp32 +612 # . . discard args +613 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +614 # initialize 'in' +615 # . write(_test-stream, "3456 x") +616 # . . push args +617 68/push "3456 x"/imm32 +618 68/push _test-stream/imm32 +619 # . . call +620 e8/call write/disp32 +621 # . . discard args +622 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +623 # initialize exit-descriptor 'ed' for the call to 'get-num' below +624 # . var ed/EAX : (address exit-descriptor) +625 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +626 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +627 # . tailor-exit-descriptor(ed, 16) +628 # . . push args +629 68/push 0x10/imm32/nbytes-of-args-for-get-num +630 50/push-EAX/ed +631 # . . call +632 e8/call tailor-exit-descriptor/disp32 +633 # . . discard args +634 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +635 # prime the pump +636 # . get-char(_test-buffered-file) +637 # . . push args +638 68/push _test-buffered-file/imm32 +639 # . . call +640 e8/call get-char/disp32 +641 # . . discard args +642 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +643 # get-num(in, out, err, ed) +644 # . . push args +645 50/push-EAX/ed +646 68/push _test-error-stream/imm32 +647 68/push _test-output-stream/imm32 +648 68/push _test-buffered-file/imm32 +649 # . . call +650 e8/call get-num/disp32 +651 # registers except ESP may be clobbered at this point +652 # . . discard args +653 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +654 # check-ints-equal(*_test-output-stream->data, '3456', msg) +655 # . . push args +656 68/push "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32 +657 68/push 0x36353433/imm32 +658 b8/copy-to-EAX _test-output-stream/imm32 +659 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +660 # . . call +661 e8/call check-ints-equal/disp32 +662 # . . discard args +663 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +664 # . reclaim locals +665 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +666 5d/pop-to-EBP +667 c3/return +668 +669 ## helpers +670 +671 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) +672 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> +673 # . prolog +674 55/push-EBP +675 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +676 # write(f, "Error: ") +677 # . . push args +678 68/push "Error: "/imm32 +679 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +680 # . . call +681 e8/call write/disp32 +682 # . . discard args +683 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +684 # write(f, s) +685 # . . push args +686 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +687 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +688 # . . call +689 e8/call write/disp32 +690 # . . discard args +691 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +692 # write(f, " expected\n") +693 # . . push args +694 68/push " expected\n"/imm32 +695 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +696 # . . call +697 e8/call write/disp32 +698 # . . discard args +699 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +700 # stop(ed, 1) +701 # . . push args +702 68/push 1/imm32 +703 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +704 # . . call +705 e8/call stop/disp32 +706 # should never get past this point +707 $expected:dead-end: +708 # . epilog +709 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +710 5d/pop-to-EBP +711 c3/return +712 +713 # read a byte from 'f', and save it in 'Look' +714 get-char: # f : (address buffered-file) -> <void> +715 # . prolog +716 55/push-EBP +717 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +718 # . save registers +719 50/push-EAX +720 # EAX = read-byte-buffered(f) +721 # . . push args +722 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +723 # . . call +724 e8/call read-byte-buffered/disp32 +725 # . . discard args +726 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +727 # save EAX to Look +728 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look +729 $get-char:end: +730 # . restore registers +731 58/pop-to-EAX +732 # . epilog +733 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +734 5d/pop-to-EBP +735 c3/return +736 +737 is-digit?: # c : int -> EAX : boolean +738 # . prolog +739 55/push-EBP +740 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +741 # EAX = false +742 b8/copy-to-EAX 0/imm32 +743 # if (c < '0') return false +744 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) +745 7c/jump-if-lesser $is-digit?:end/disp8 +746 # if (c > '9') return false +747 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) +748 7f/jump-if-greater $is-digit?:end/disp8 +749 # otherwise return true +750 b8/copy-to-EAX 1/imm32 +751 $is-digit?:end: +752 # . epilog +753 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +754 5d/pop-to-EBP +755 c3/return 756 -757 _test-output-stream: -758 # current write index -759 0/imm32 -760 # current read index -761 0/imm32 -762 # length -763 8/imm32 -764 # data -765 00 00 00 00 00 00 00 00 # 8 bytes -766 -767 _test-error-stream: -768 # current write index -769 0/imm32 -770 # current read index -771 0/imm32 -772 # length -773 0x40/imm32 -774 # data (4 lines x 16 bytes/line) -775 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -776 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -777 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -778 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -779 -780 # . . vim:nowrap:textwidth=0 +757 == data +758 +759 Look: # (char with some extra padding) +760 0/imm32 +761 +762 _test-output-stream: +763 # current write index +764 0/imm32 +765 # current read index +766 0/imm32 +767 # length +768 8/imm32 +769 # data +770 00 00 00 00 00 00 00 00 # 8 bytes +771 +772 _test-error-stream: +773 # current write index +774 0/imm32 +775 # current read index +776 0/imm32 +777 # length +778 0x40/imm32 +779 # data (4 lines x 16 bytes/line) +780 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +781 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +782 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +783 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +784 +785 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0