From 9309600c5a8a5a86ac5aeebdee7bf0656409fc26 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Thu, 14 Feb 2019 23:00:47 -0800 Subject: 4967 --- html/subx/apps/crenshaw2-1.subx.html | 789 +++++++++++++++++------------------ 1 file changed, 394 insertions(+), 395 deletions(-) (limited to 'html/subx/apps/crenshaw2-1.subx.html') diff --git a/html/subx/apps/crenshaw2-1.subx.html b/html/subx/apps/crenshaw2-1.subx.html index 28b25517..9e4dbb9f 100644 --- a/html/subx/apps/crenshaw2-1.subx.html +++ b/html/subx/apps/crenshaw2-1.subx.html @@ -100,7 +100,7 @@ if ('onhashchange' in window) { 37 # main: run tests if necessary, call 'compile' if not 38 # . prolog 39 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 40 # - if argc > 1 and argv[1] == "test" then return run_tests() + 40 # - if argc > 1 and argv[1] == "test", then return run_tests() 41 # . argc > 1 42 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 43 7e/jump-if-lesser-or-equal $run-main/disp8 @@ -156,7 +156,7 @@ if ('onhashchange' in window) { 93 # . . push args 94 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 95 # . . call - 96 e8/call get-char/disp32 + 96 e8/call get-char/disp32 97 # . . discard args 98 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 99 # var num/ECX : (address stream) on the stack @@ -262,8 +262,8 @@ if ('onhashchange' in window) { 199 # 'in' into it on exit. 200 get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> 201 # pseudocode: -202 # if !is-digit?(Look) expected(ed, err, "integer") -203 # if out->write >= out->length +202 # if (!is-digit?(Look)) expected(ed, err, "integer") +203 # if (out->write >= out->length) 204 # write(err, "Error: too many digits in number\n") 205 # stop(ed, 1) 206 # out->data[out->write] = LSB(Look) @@ -271,397 +271,396 @@ if ('onhashchange' in window) { 208 # Look = get-char(in) 209 # 210 # registers: -211 # ESI : in -212 # EDI : out -213 # EAX : temp -214 # ECX : out->write (persisted back at end) -215 # EDX : out->length -216 # EBX : temp2 -217 # We can't allocate Look to a register because it gets written implicitly in -218 # get-char in each iteration of the loop. (Thereby demonstrating that it's -219 # not the right interface for us. But we'll keep it just to follow Crenshaw.) -220 # -221 # . prolog -222 55/push-EBP -223 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -224 # - if is-digit?(Look) expected(ed, err, "integer") -225 # . EAX = is-digit?(Look) -226 # . . push args -227 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look -228 # . . call -229 e8/call is-digit?/disp32 -230 # . . discard args -231 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -232 # . if EAX == 0 -233 3d/compare-EAX 0/imm32 -234 75/jump-if-not-equal $get-num:main/disp8 -235 # . expected(ed, err, "integer") -236 # . . push args -237 68/push "integer"/imm32 -238 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -239 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -240 # . . call -241 e8/call expected/disp32 # never returns -242 # . . discard args -243 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -244 $get-num:main: -245 # - otherwise read a digit -246 # . save registers -247 50/push-EAX -248 51/push-ECX -249 52/push-EDX -250 53/push-EBX -251 56/push-ESI -252 57/push-EDI -253 # read necessary variables to registers -254 # ESI = in -255 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -256 # EDI = out -257 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI -258 # ECX = out->write -259 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX -260 # EDX = out->length -261 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX -262 # if out->write >= out->length error -263 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX -264 7d/jump-if-lesser $get-num:stage2/disp8 -265 # . error(ed, err, msg) # TODO: show full number -266 # . . push args -267 68/push "get-num: too many digits in number"/imm32 -268 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -269 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -270 # . . call -271 e8/call error/disp32 # never returns -272 # . . discard args -273 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -274 $get-num:stage2: -275 # out->data[out->write] = LSB(Look) -276 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 -277 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX -278 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX -279 # ++out->write -280 41/increment-ECX -281 # Look = get-char(in) -282 # . . push args -283 56/push-ESI -284 # . . call -285 e8/call get-char/disp32 -286 # . . discard args -287 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -288 $get-num:loop-end: -289 # persist necessary variables from registers -290 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI -291 $get-num:end: -292 # . restore registers -293 5f/pop-to-EDI -294 5e/pop-to-ESI -295 5b/pop-to-EBX -296 5a/pop-to-EDX -297 59/pop-to-ECX -298 58/pop-to-EAX -299 # . epilog -300 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -301 5d/pop-to-EBP -302 c3/return -303 -304 test-get-num-reads-single-digit: -305 # - check that get-num returns first character if it's a digit -306 # This test uses exit-descriptors. Use EBP for setting up local variables. -307 55/push-EBP -308 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -309 # clear all streams -310 # . clear-stream(_test-stream) -311 # . . push args -312 68/push _test-stream/imm32 -313 # . . call -314 e8/call clear-stream/disp32 -315 # . . discard args -316 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -317 # . clear-stream(_test-buffered-file+4) -318 # . . push args -319 b8/copy-to-EAX _test-buffered-file/imm32 -320 05/add-to-EAX 4/imm32 -321 50/push-EAX -322 # . . call -323 e8/call clear-stream/disp32 -324 # . . discard args -325 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -326 # . clear-stream(_test-output-stream) -327 # . . push args -328 68/push _test-output-stream/imm32 -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-error-stream) -334 # . . push args -335 68/push _test-error-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 # initialize 'in' -341 # . write(_test-stream, "3") -342 # . . push args -343 68/push "3"/imm32 -344 68/push _test-stream/imm32 -345 # . . call -346 e8/call write/disp32 -347 # . . discard args -348 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -349 # initialize exit-descriptor 'ed' for the call to 'get-num' below -350 # . var ed/EAX : exit-descriptor -351 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -352 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -353 # . tailor-exit-descriptor(ed, 16) -354 # . . push args -355 68/push 0x10/imm32/nbytes-of-args-for-get-num -356 50/push-EAX/ed -357 # . . call -358 e8/call tailor-exit-descriptor/disp32 -359 # . . discard args -360 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -361 # prime the pump -362 # . get-char(_test-buffered-file) -363 # . . push args -364 68/push _test-buffered-file/imm32 -365 # . . call -366 e8/call get-char/disp32 -367 # . . discard args -368 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -369 # get-num(in, out, err, ed) -370 # . . push args -371 50/push-EAX/ed -372 68/push _test-error-stream/imm32 -373 68/push _test-output-stream/imm32 -374 68/push _test-buffered-file/imm32 -375 # . . call -376 e8/call get-num/disp32 -377 # registers except ESP may be clobbered at this point -378 # . . discard args -379 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -380 # check-ints-equal(*_test-output-stream->data, '3', msg) -381 # . . push args -382 68/push "F - test-get-num-reads-single-digit"/imm32 -383 68/push 0x33/imm32 -384 b8/copy-to-EAX _test-output-stream/imm32 -385 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -386 # . . call -387 e8/call check-ints-equal/disp32 -388 # . . discard args -389 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -390 # . reclaim locals -391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -392 5d/pop-to-EBP -393 c3/return -394 -395 test-get-num-aborts-on-non-digit-in-Look: -396 # - check that get-num returns first character if it's a digit -397 # This test uses exit-descriptors. Use EBP for setting up local variables. -398 55/push-EBP -399 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -400 # clear all streams -401 # . clear-stream(_test-stream) -402 # . . push args -403 68/push _test-stream/imm32 -404 # . . call -405 e8/call clear-stream/disp32 -406 # . . discard args -407 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -408 # . clear-stream(_test-buffered-file+4) -409 # . . push args -410 b8/copy-to-EAX _test-buffered-file/imm32 -411 05/add-to-EAX 4/imm32 -412 50/push-EAX -413 # . . call -414 e8/call clear-stream/disp32 -415 # . . discard args -416 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -417 # . clear-stream(_test-output-stream) -418 # . . push args -419 68/push _test-output-stream/imm32 -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-error-stream) -425 # . . push args -426 68/push _test-error-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 # initialize 'in' -432 # . write(_test-stream, "3") -433 # . . push args -434 68/push "3"/imm32 -435 68/push _test-stream/imm32 -436 # . . call -437 e8/call write/disp32 -438 # . . discard args -439 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -440 # initialize exit-descriptor 'ed' for the call to 'get-num' below -441 # . var ed/EAX : (address exit-descriptor) -442 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -443 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -444 # . tailor-exit-descriptor(ed, 16) -445 # . . push args -446 68/push 0x10/imm32/nbytes-of-args-for-get-num -447 50/push-EAX/ed -448 # . . call -449 e8/call tailor-exit-descriptor/disp32 -450 # . . discard args -451 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -452 # *don't* prime the pump -453 # get-num(in, out, err, ed) -454 # . . push args -455 50/push-EAX/ed -456 68/push _test-error-stream/imm32 -457 68/push _test-output-stream/imm32 -458 68/push _test-buffered-file/imm32 -459 # . . call -460 e8/call get-num/disp32 -461 # registers except ESP may be clobbered at this point -462 # . . discard args -463 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -464 # check that get-num tried to call exit(1) -465 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 -466 # . . push args -467 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 -468 68/push 2/imm32 -469 # . . push ed->value -470 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -471 # . . call -472 e8/call check-ints-equal/disp32 -473 # . . discard args -474 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -475 # . reclaim locals -476 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -477 5d/pop-to-EBP -478 c3/return -479 -480 ## helpers -481 -482 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) -483 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> -484 # . prolog -485 55/push-EBP -486 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -487 # write(f, "Error: ") -488 # . . push args -489 68/push "Error: "/imm32 -490 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -491 # . . call -492 e8/call write/disp32 -493 # . . discard args -494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -495 # write(f, s) -496 # . . push args -497 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -498 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -499 # . . call -500 e8/call write/disp32 -501 # . . discard args -502 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -503 # write(f, " expected") -504 # . . push args -505 68/push " expected"/imm32 -506 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -507 # . . call -508 e8/call write/disp32 -509 # . . discard args -510 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -511 # write(f, Newline) -512 # . . push args -513 68/push Newline/imm32 -514 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -515 # . . call -516 e8/call write/disp32 -517 # . . discard args -518 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -519 # stop(ed, 1) -520 # . . push args -521 68/push 1/imm32 -522 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -523 # . . call -524 e8/call stop/disp32 -525 # should never get past this point -526 $expected:dead-end: -527 # . epilog -528 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -529 5d/pop-to-EBP -530 c3/return -531 -532 # read a byte from 'f', and save it in 'Look' -533 get-char: # f : (address buffered-file) -> <void> -534 # . prolog -535 55/push-EBP -536 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -537 # . save registers -538 50/push-EAX -539 # read-byte(f) -540 # . . push args -541 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -542 # . . call -543 e8/call read-byte/disp32 -544 # . . discard args -545 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -546 # save EAX to Look -547 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look -548 $get-char:end: -549 # . restore registers -550 58/pop-to-EAX -551 # . epilog -552 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -553 5d/pop-to-EBP -554 c3/return -555 -556 is-digit?: # c : int -> EAX : boolean -557 # . prolog -558 55/push-EBP -559 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -560 # EAX = false -561 b8/copy-to-EAX 0/imm32 -562 # if c < '0' return false -563 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) -564 7c/jump-if-lesser $is-digit?:end/disp8 -565 # if c > '9' return false -566 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) -567 7f/jump-if-greater $is-digit?:end/disp8 -568 # otherwise return true -569 b8/copy-to-EAX 1/imm32 -570 $is-digit?:end: -571 # . epilog -572 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -573 5d/pop-to-EBP -574 c3/return -575 -576 == data -577 -578 Look: # (char) -579 00 00 00 00 # = 0 -580 -581 _test-output-stream: -582 # current write index -583 00 00 00 00 -584 # current read index -585 00 00 00 00 -586 # length (= 8) -587 08 00 00 00 -588 # data -589 00 00 00 00 00 00 00 00 # 8 bytes -590 -591 _test-error-stream: -592 # current write index -593 00 00 00 00 -594 # current read index -595 00 00 00 00 -596 # length (= 8) -597 08 00 00 00 -598 # data -599 00 00 00 00 00 00 00 00 # 8 bytes -600 -601 # . . vim:nowrap:textwidth=0 +211 # in: ESI +212 # out: EDI +213 # out->write: ECX (cached copy; need to keep in sync) +214 # out->length: EDX +215 # temporaries: EAX, EBX +216 # We can't allocate Look to a register because it gets written implicitly in +217 # get-char in each iteration of the loop. (Thereby demonstrating that it's +218 # not the right interface for us. But we'll keep it just to follow Crenshaw.) +219 # +220 # . prolog +221 55/push-EBP +222 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +223 # - if (is-digit?(Look)) expected(ed, err, "integer") +224 # . EAX = is-digit?(Look) +225 # . . push args +226 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look +227 # . . call +228 e8/call is-digit?/disp32 +229 # . . discard args +230 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +231 # . if (EAX == 0) +232 3d/compare-EAX 0/imm32 +233 75/jump-if-not-equal $get-num:main/disp8 +234 # . expected(ed, err, "integer") +235 # . . push args +236 68/push "integer"/imm32 +237 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +238 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +239 # . . call +240 e8/call expected/disp32 # never returns +241 # . . discard args +242 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +243 $get-num:main: +244 # - otherwise read a digit +245 # . save registers +246 50/push-EAX +247 51/push-ECX +248 52/push-EDX +249 53/push-EBX +250 56/push-ESI +251 57/push-EDI +252 # read necessary variables to registers +253 # ESI = in +254 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +255 # EDI = out +256 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI +257 # ECX = out->write +258 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX +259 # EDX = out->length +260 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX +261 # if (out->write >= out->length) error +262 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX +263 7d/jump-if-lesser $get-num:stage2/disp8 +264 # . error(ed, err, msg) # TODO: show full number +265 # . . push args +266 68/push "get-num: too many digits in number"/imm32 +267 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +268 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +269 # . . call +270 e8/call error/disp32 # never returns +271 # . . discard args +272 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +273 $get-num:stage2: +274 # out->data[out->write] = LSB(Look) +275 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 +276 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX +277 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX +278 # ++out->write +279 41/increment-ECX +280 # Look = get-char(in) +281 # . . push args +282 56/push-ESI +283 # . . call +284 e8/call get-char/disp32 +285 # . . discard args +286 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +287 $get-num:loop-end: +288 # persist necessary variables from registers +289 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI +290 $get-num:end: +291 # . restore registers +292 5f/pop-to-EDI +293 5e/pop-to-ESI +294 5b/pop-to-EBX +295 5a/pop-to-EDX +296 59/pop-to-ECX +297 58/pop-to-EAX +298 # . epilog +299 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +300 5d/pop-to-EBP +301 c3/return +302 +303 test-get-num-reads-single-digit: +304 # - check that get-num returns first character if it's a digit +305 # This test uses exit-descriptors. Use EBP for setting up local variables. +306 55/push-EBP +307 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +308 # clear all streams +309 # . clear-stream(_test-stream) +310 # . . push args +311 68/push _test-stream/imm32 +312 # . . call +313 e8/call clear-stream/disp32 +314 # . . discard args +315 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +316 # . clear-stream(_test-buffered-file+4) +317 # . . push args +318 b8/copy-to-EAX _test-buffered-file/imm32 +319 05/add-to-EAX 4/imm32 +320 50/push-EAX +321 # . . call +322 e8/call clear-stream/disp32 +323 # . . discard args +324 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +325 # . clear-stream(_test-output-stream) +326 # . . push args +327 68/push _test-output-stream/imm32 +328 # . . call +329 e8/call clear-stream/disp32 +330 # . . discard args +331 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +332 # . clear-stream(_test-error-stream) +333 # . . push args +334 68/push _test-error-stream/imm32 +335 # . . call +336 e8/call clear-stream/disp32 +337 # . . discard args +338 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +339 # initialize 'in' +340 # . write(_test-stream, "3") +341 # . . push args +342 68/push "3"/imm32 +343 68/push _test-stream/imm32 +344 # . . call +345 e8/call write/disp32 +346 # . . discard args +347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +348 # initialize exit-descriptor 'ed' for the call to 'get-num' below +349 # . var ed/EAX : exit-descriptor +350 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +351 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +352 # . tailor-exit-descriptor(ed, 16) +353 # . . push args +354 68/push 0x10/imm32/nbytes-of-args-for-get-num +355 50/push-EAX/ed +356 # . . call +357 e8/call tailor-exit-descriptor/disp32 +358 # . . discard args +359 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +360 # prime the pump +361 # . get-char(_test-buffered-file) +362 # . . push args +363 68/push _test-buffered-file/imm32 +364 # . . call +365 e8/call get-char/disp32 +366 # . . discard args +367 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +368 # get-num(in, out, err, ed) +369 # . . push args +370 50/push-EAX/ed +371 68/push _test-error-stream/imm32 +372 68/push _test-output-stream/imm32 +373 68/push _test-buffered-file/imm32 +374 # . . call +375 e8/call get-num/disp32 +376 # registers except ESP may be clobbered at this point +377 # . . discard args +378 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +379 # check-ints-equal(*_test-output-stream->data, '3', msg) +380 # . . push args +381 68/push "F - test-get-num-reads-single-digit"/imm32 +382 68/push 0x33/imm32 +383 b8/copy-to-EAX _test-output-stream/imm32 +384 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +385 # . . call +386 e8/call check-ints-equal/disp32 +387 # . . discard args +388 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +389 # . reclaim locals +390 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +391 5d/pop-to-EBP +392 c3/return +393 +394 test-get-num-aborts-on-non-digit-in-Look: +395 # - check that get-num returns first character if it's a digit +396 # This test uses exit-descriptors. Use EBP for setting up local variables. +397 55/push-EBP +398 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +399 # clear all streams +400 # . clear-stream(_test-stream) +401 # . . push args +402 68/push _test-stream/imm32 +403 # . . call +404 e8/call clear-stream/disp32 +405 # . . discard args +406 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +407 # . clear-stream(_test-buffered-file+4) +408 # . . push args +409 b8/copy-to-EAX _test-buffered-file/imm32 +410 05/add-to-EAX 4/imm32 +411 50/push-EAX +412 # . . call +413 e8/call clear-stream/disp32 +414 # . . discard args +415 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +416 # . clear-stream(_test-output-stream) +417 # . . push args +418 68/push _test-output-stream/imm32 +419 # . . call +420 e8/call clear-stream/disp32 +421 # . . discard args +422 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +423 # . clear-stream(_test-error-stream) +424 # . . push args +425 68/push _test-error-stream/imm32 +426 # . . call +427 e8/call clear-stream/disp32 +428 # . . discard args +429 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +430 # initialize 'in' +431 # . write(_test-stream, "3") +432 # . . push args +433 68/push "3"/imm32 +434 68/push _test-stream/imm32 +435 # . . call +436 e8/call write/disp32 +437 # . . discard args +438 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +439 # initialize exit-descriptor 'ed' for the call to 'get-num' below +440 # . var ed/EAX : (address exit-descriptor) +441 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +442 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +443 # . tailor-exit-descriptor(ed, 16) +444 # . . push args +445 68/push 0x10/imm32/nbytes-of-args-for-get-num +446 50/push-EAX/ed +447 # . . call +448 e8/call tailor-exit-descriptor/disp32 +449 # . . discard args +450 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +451 # *don't* prime the pump +452 # get-num(in, out, err, ed) +453 # . . push args +454 50/push-EAX/ed +455 68/push _test-error-stream/imm32 +456 68/push _test-output-stream/imm32 +457 68/push _test-buffered-file/imm32 +458 # . . call +459 e8/call get-num/disp32 +460 # registers except ESP may be clobbered at this point +461 # . . discard args +462 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +463 # check that get-num tried to call exit(1) +464 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 +465 # . . push args +466 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 +467 68/push 2/imm32 +468 # . . push ed->value +469 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +470 # . . call +471 e8/call check-ints-equal/disp32 +472 # . . discard args +473 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +474 # . reclaim locals +475 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +476 5d/pop-to-EBP +477 c3/return +478 +479 ## helpers +480 +481 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) +482 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> +483 # . prolog +484 55/push-EBP +485 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +486 # write(f, "Error: ") +487 # . . push args +488 68/push "Error: "/imm32 +489 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +490 # . . call +491 e8/call write/disp32 +492 # . . discard args +493 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +494 # write(f, s) +495 # . . push args +496 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +497 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +498 # . . call +499 e8/call write/disp32 +500 # . . discard args +501 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +502 # write(f, " expected") +503 # . . push args +504 68/push " expected"/imm32 +505 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +506 # . . call +507 e8/call write/disp32 +508 # . . discard args +509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +510 # write(f, Newline) +511 # . . push args +512 68/push Newline/imm32 +513 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +514 # . . call +515 e8/call write/disp32 +516 # . . discard args +517 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +518 # stop(ed, 1) +519 # . . push args +520 68/push 1/imm32 +521 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +522 # . . call +523 e8/call stop/disp32 +524 # should never get past this point +525 $expected:dead-end: +526 # . epilog +527 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +528 5d/pop-to-EBP +529 c3/return +530 +531 # read a byte from 'f', and save it in 'Look' +532 get-char: # f : (address buffered-file) -> <void> +533 # . prolog +534 55/push-EBP +535 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +536 # . save registers +537 50/push-EAX +538 # read-byte(f) +539 # . . push args +540 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +541 # . . call +542 e8/call read-byte/disp32 +543 # . . discard args +544 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +545 # save EAX to Look +546 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look +547 $get-char:end: +548 # . restore registers +549 58/pop-to-EAX +550 # . epilog +551 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +552 5d/pop-to-EBP +553 c3/return +554 +555 is-digit?: # c : int -> EAX : boolean +556 # . prolog +557 55/push-EBP +558 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +559 # EAX = false +560 b8/copy-to-EAX 0/imm32 +561 # if (c < '0') return false +562 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) +563 7c/jump-if-lesser $is-digit?:end/disp8 +564 # if (c > '9') return false +565 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) +566 7f/jump-if-greater $is-digit?:end/disp8 +567 # otherwise return true +568 b8/copy-to-EAX 1/imm32 +569 $is-digit?:end: +570 # . epilog +571 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +572 5d/pop-to-EBP +573 c3/return +574 +575 == data +576 +577 Look: # (char) +578 00 00 00 00 # = 0 +579 +580 _test-output-stream: +581 # current write index +582 00 00 00 00 +583 # current read index +584 00 00 00 00 +585 # length (= 8) +586 08 00 00 00 +587 # data +588 00 00 00 00 00 00 00 00 # 8 bytes +589 +590 _test-error-stream: +591 # current write index +592 00 00 00 00 +593 # current read index +594 00 00 00 00 +595 # length (= 8) +596 08 00 00 00 +597 # data +598 00 00 00 00 00 00 00 00 # 8 bytes +599 +600 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0