From c98d4b1c6ae2d103acc7b4f15e4dc6336f30de17 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 2 Dec 2018 14:41:21 -0800 Subject: 4818 --- html/subx/apps/crenshaw2-1.subx.html | 1095 +++++++++++++++++----------------- 1 file changed, 548 insertions(+), 547 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 05687d5e..5fd8df12 100644 --- a/html/subx/apps/crenshaw2-1.subx.html +++ b/html/subx/apps/crenshaw2-1.subx.html @@ -154,553 +154,554 @@ if ('onhashchange' in window) { 88 # . save registers 89 50/push-EAX 90 51/push-ECX - 91 # . Look = get-char(in) - 92 # . . push args - 93 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 94 # . . call - 95 e8/call get-char/disp32 - 96 # . . discard args - 97 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 98 # var num/ECX : (address stream) on the stack - 99 # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. -100 # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. -101 # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. -102 # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. -103 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP -104 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX -105 # initialize the stream -106 # . num->length = 7 -107 c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) -108 # . clear-stream(num) -109 # . . push args -110 51/push-ECX -111 # . . call -112 e8/call clear-stream/disp32 -113 # . . discard args -114 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -115 # read a digit from 'in' into 'num' -116 # . get-num(in, num, err, ed) -117 # . . push args -118 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) -119 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) -120 51/push-ECX/num -121 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) -122 # . . call -123 e8/call get-num/disp32 -124 # . . discard args -125 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -126 # render 'num' into the following template on 'out': -127 # bb/copy-to-EBX _num_ -128 # b8/copy-to-EAX 1/imm32/exit -129 # cd/syscall 0x80/imm8 -130 # -131 # . EAX = write(out, "bb/copy-to-EBX ") -132 # . . push args -133 68/push "bb/copy-to-EBX "/imm32 -134 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -135 # . . call -136 e8/call write/disp32 -137 # . . discard args -138 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -139 # . write-stream(out, num) -140 # . . push args -141 51/push-ECX/num -142 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -143 # . . call -144 e8/call write-stream/disp32 -145 # . . discard args -146 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -147 # . write(out, Newline) -148 # . . push args -149 68/push Newline/imm32 -150 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -151 # . . call -152 e8/call write/disp32 -153 # . . discard args -154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -155 # . write(out, "b8/copy-to-EAX 1/imm32/exit") -156 # . . push args -157 68/push "b8/copy-to-EAX 1/imm32/exit"/imm32 -158 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -159 # . . call -160 e8/call write/disp32 -161 # . . discard args -162 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -163 # . write(out, Newline) -164 # . . push args -165 68/push Newline/imm32 -166 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -167 # . . call -168 e8/call write/disp32 -169 # . . discard args -170 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -171 # . write(out, "cd/syscall 0x80/imm8") -172 # . . push args -173 68/push "cd/syscall 0x80/imm8"/imm32 -174 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -175 # . . call -176 e8/call write/disp32 -177 # . . discard args -178 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -179 # . write(out, Newline) -180 # . . push args -181 68/push Newline/imm32 -182 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -183 # . . call -184 e8/call write/disp32 -185 # . . discard args -186 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -187 # . restore registers -188 59/pop-to-ECX -189 58/pop-to-EAX -190 # . epilog -191 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -192 5d/pop-to-EBP -193 c3/return -194 -195 # Read a single digit into 'out'. Abort if there are none, or if there is no space in 'out'. -196 # Input comes from the global variable 'Look', and we leave the next byte from -197 # 'in' into it on exit. -198 get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> -199 # pseudocode: -200 # if !is-digit?(Look) expected(ed, err, "integer") -201 # if out.write >= out.length -202 # write(err, "Error: too many digits in number\n") -203 # stop(ed, 1) -204 # out.data[out.write] = LSB(Look) -205 # ++out.write -206 # Look = get-char(in) -207 # -208 # registers: -209 # ESI : in -210 # EDI : out -211 # EAX : temp -212 # ECX : out->write -213 # EDX : out->length -214 # EBX : temp2 -215 # We can't allocate Look to a register because it gets written implicitly in -216 # get-char in each iteration of the loop. (Thereby demonstrating that it's -217 # not the right interface for us. But we'll keep it just to follow Crenshaw.) -218 # -219 # . prolog -220 55/push-EBP -221 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -222 # - if is-digit?(Look) expected(ed, err, "integer") -223 # . EAX = is-digit?(Look) -224 # . . push args -225 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look -226 # . . call -227 e8/call is-digit?/disp32 -228 # . . discard args -229 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -230 # . if EAX == 0 -231 3d/compare-EAX 0/imm32 -232 75/jump-if-not-equal $get-num:main/disp8 -233 # . expected(ed, err, "integer") -234 # . . push args -235 68/push "integer"/imm32 -236 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) -237 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) -238 # . . call -239 e8/call expected/disp32 # never returns -240 # . . discard args -241 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -242 $get-num:main: -243 # - otherwise read a digit -244 # . save registers -245 50/push-EAX -246 51/push-ECX -247 52/push-EDX -248 53/push-EBX -249 56/push-ESI -250 57/push-EDI -251 # read necessary variables to registers -252 # ESI = in -253 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -254 # EDI = out -255 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI -256 # ECX = out->write -257 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX -258 # EDX = out->length -259 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX -260 # if out->write >= out->length error -261 3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare EDX with ECX -262 7d/jump-if-lesser $get-num:stage2/disp8 -263 # . error(ed, err, msg) # TODO: show full number -264 # . . push args -265 68/push "get-num: too many digits in number"/imm32 -266 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) -267 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) -268 # . . call -269 e8/call error/disp32 # never returns -270 # . . discard args -271 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -272 $get-num:stage2: -273 # out->data[out->write] = LSB(Look) -274 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 -275 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX -276 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX -277 # ++out->write -278 41/increment-ECX -279 # Look = get-char(in) -280 # . . push args -281 56/push-ESI -282 # . . call -283 e8/call get-char/disp32 -284 # . . discard args -285 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -286 $get-num:loop-end: -287 # persist necessary variables from registers -288 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI -289 # . restore registers -290 5f/pop-to-EDI -291 5e/pop-to-ESI -292 5b/pop-to-EBX -293 5a/pop-to-EDX -294 59/pop-to-ECX -295 58/pop-to-EAX -296 # . epilog -297 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -298 5d/pop-to-EBP -299 c3/return -300 -301 test-get-num-reads-single-digit: -302 # - check that get-num returns first character if it's a digit -303 # This test uses exit-descriptors. Use EBP for setting up local variables. -304 55/push-EBP -305 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -306 # setup -307 # . clear-stream(_test-stream) -308 # . . push args -309 68/push _test-stream/imm32 -310 # . . call -311 e8/call clear-stream/disp32 -312 # . . discard args -313 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -314 # . clear-stream(_test-buffered-file+4) -315 # . . push args -316 b8/copy-to-EAX _test-buffered-file/imm32 -317 05/add-to-EAX 4/imm32 -318 50/push-EAX -319 # . . call -320 e8/call clear-stream/disp32 -321 # . . discard args -322 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -323 # . clear-stream(_test-output-stream) -324 # . . push args -325 68/push _test-output-stream/imm32 -326 # . . call -327 e8/call clear-stream/disp32 -328 # . . discard args -329 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -330 # . clear-stream(_test-error-stream) -331 # . . push args -332 68/push _test-error-stream/imm32 -333 # . . call -334 e8/call clear-stream/disp32 -335 # . . discard args -336 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -337 # initialize 'in' -338 # . write(_test-stream, "3") -339 # . . push args -340 68/push "3"/imm32 -341 68/push _test-stream/imm32 -342 # . . call -343 e8/call write/disp32 -344 # . . discard args -345 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -346 # initialize exit-descriptor 'ed' for the call to 'get-num' below -347 # . var ed/EAX : exit-descriptor -348 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -349 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX -350 # . tailor-exit-descriptor(ed, 16) -351 # . . push args -352 68/push 0x10/imm32/nbytes-of-args-for-get-num -353 50/push-EAX/ed -354 # . . call -355 e8/call tailor-exit-descriptor/disp32 -356 # . . discard args -357 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -358 # prime the pump -359 # . get-char(_test-buffered-file) -360 # . . push args -361 68/push _test-buffered-file/imm32 -362 # . . call -363 e8/call get-char/disp32 -364 # . . discard args -365 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -366 # get-num(in, out, err, ed) -367 # . . push args -368 50/push-EAX/ed -369 68/push _test-error-stream/imm32 -370 68/push _test-output-stream/imm32 -371 68/push _test-buffered-file/imm32 -372 # . . call -373 e8/call get-num/disp32 -374 # registers except ESP may be clobbered at this point -375 # . . discard args -376 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -377 # check-ints-equal(*_test-output-stream.data, '3') -378 # . . push args -379 68/push "F - test-get-num-reads-single-digit"/imm32 -380 68/push 0x33/imm32 -381 b8/copy-to-EAX _test-output-stream/imm32 -382 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -383 # . . call -384 e8/call check-ints-equal/disp32 -385 # . . discard args -386 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -387 # . reclaim locals -388 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -389 5d/pop-to-EBP -390 c3/return -391 -392 test-get-num-aborts-on-non-digit-in-Look: -393 # - check that get-num returns first character if it's a digit -394 # This test uses exit-descriptors. Use EBP for setting up local variables. -395 55/push-EBP -396 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -397 # setup -398 # . clear-stream(_test-stream) -399 # . . push args -400 68/push _test-stream/imm32 -401 # . . call -402 e8/call clear-stream/disp32 -403 # . . discard args -404 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -405 # . clear-stream(_test-buffered-file+4) -406 # . . push args -407 b8/copy-to-EAX _test-buffered-file/imm32 -408 05/add-to-EAX 4/imm32 -409 50/push-EAX -410 # . . call -411 e8/call clear-stream/disp32 -412 # . . discard args -413 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -414 # . clear-stream(_test-output-stream) -415 # . . push args -416 68/push _test-output-stream/imm32 -417 # . . call -418 e8/call clear-stream/disp32 -419 # . . discard args -420 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -421 # . clear-stream(_test-error-stream) -422 # . . push args -423 68/push _test-error-stream/imm32 -424 # . . call -425 e8/call clear-stream/disp32 -426 # . . discard args -427 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -428 # initialize 'in' -429 # . write(_test-stream, "3") -430 # . . push args -431 68/push "3"/imm32 -432 68/push _test-stream/imm32 -433 # . . call -434 e8/call write/disp32 -435 # . . discard args -436 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -437 # initialize exit-descriptor 'ed' for the call to 'get-num' below -438 # . var ed/EAX : (address exit-descriptor) -439 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -440 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX -441 # . tailor-exit-descriptor(ed, 16) -442 # . . push args -443 68/push 0x10/imm32/nbytes-of-args-for-get-num -444 50/push-EAX/ed -445 # . . call -446 e8/call tailor-exit-descriptor/disp32 -447 # . . discard args -448 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -449 # *don't* prime the pump -450 # get-num(in, out, err, ed) -451 # . . push args -452 50/push-EAX/ed -453 68/push _test-error-stream/imm32 -454 68/push _test-output-stream/imm32 -455 68/push _test-buffered-file/imm32 -456 # . . call -457 e8/call get-num/disp32 -458 # registers except ESP may be clobbered at this point -459 # . . discard args -460 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -461 # check that get-num tried to call exit(1) -462 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 -463 # . . push args -464 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 -465 68/push 2/imm32 -466 # . . push ed->value -467 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -468 # . . call -469 e8/call check-ints-equal/disp32 -470 # . . discard args -471 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -472 # . reclaim locals -473 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -474 5d/pop-to-EBP -475 c3/return -476 -477 ## helpers -478 -479 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) -480 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> -481 # . prolog -482 55/push-EBP -483 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -484 # write(f, "Error: ") -485 # . . push args -486 68/push "Error: "/imm32 -487 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -488 # . . call -489 e8/call write/disp32 -490 # . . discard args -491 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -492 # write(f, s) -493 # . . push args -494 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) -495 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -496 # . . call -497 e8/call write/disp32 -498 # . . discard args -499 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -500 # write(f, " expected") -501 # . . push args -502 68/push " expected"/imm32 -503 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -504 # . . call -505 e8/call write/disp32 -506 # . . discard args -507 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -508 # write(f, Newline) -509 # . . push args -510 68/push Newline/imm32 -511 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -512 # . . call -513 e8/call write/disp32 -514 # . . discard args -515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -516 # stop(ed, 1) -517 # . . push args -518 68/push 1/imm32 -519 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) -520 # . . call -521 e8/call stop/disp32 -522 # should never get past this point -523 # . epilog -524 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -525 5d/pop-to-EBP -526 c3/return -527 -528 # write(f, "Error: "+s+"\n") then stop(ed, 1) -529 error: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> -530 # . prolog -531 55/push-EBP -532 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -533 # write(f, "Error: ") -534 # . . push args -535 68/push "Error: "/imm32 -536 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -537 # . . call -538 e8/call write/disp32 -539 # . . discard args -540 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -541 # write(f, s) -542 # . . push args -543 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) -544 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -545 # . . call -546 e8/call write/disp32 -547 # . . discard args -548 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -549 # write(f, Newline) -550 # . . push args -551 68/push Newline/imm32 -552 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) -553 # . . call -554 e8/call write/disp32 -555 # . . discard args -556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -557 # stop(ed, 1) -558 # . . push args -559 68/push 1/imm32 -560 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) -561 # . . call -562 e8/call stop/disp32 -563 # should never get past this point -564 # . epilog -565 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -566 5d/pop-to-EBP -567 c3/return -568 -569 # read a byte from 'f', and save it in 'Look' -570 get-char: # f : (address buffered-file) -> <void> -571 # . prolog -572 55/push-EBP -573 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -574 # . save registers -575 50/push-EAX -576 # read-byte(f) -577 # . . push args -578 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) -579 # . . call -580 e8/call read-byte/disp32 -581 # . . discard args -582 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -583 # save EAX to Look -584 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look -585 # . restore registers -586 58/pop-to-EAX -587 # . epilog -588 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -589 5d/pop-to-EBP -590 c3/return -591 -592 is-digit?: # c : int -> bool/EAX -593 # . prolog -594 55/push-EBP -595 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -596 # EAX = false -597 b8/copy-to-EAX 0/imm32 -598 # if c < '0' return false -599 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 0x30/imm32 # compare *(EBP+8) -600 7c/jump-if-lesser $is-digit?:end/disp8 -601 # if c > '9' return false -602 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 0x39/imm32 # compare *(EBP+8) -603 7f/jump-if-greater $is-digit?:end/disp8 -604 # otherwise return true -605 b8/copy-to-EAX 1/imm32 -606 $is-digit?:end: -607 # . epilog -608 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -609 5d/pop-to-EBP -610 c3/return -611 -612 == data -613 -614 Look: # (char) -615 00 00 00 00 # = 0 -616 -617 _test-output-stream: -618 # current write index -619 00 00 00 00 -620 # current read index -621 00 00 00 00 -622 # length (= 8) -623 08 00 00 00 -624 # data -625 00 00 00 00 00 00 00 00 # 8 bytes -626 -627 _test-error-stream: -628 # current write index -629 00 00 00 00 -630 # current read index -631 00 00 00 00 -632 # length (= 8) -633 08 00 00 00 -634 # data -635 00 00 00 00 00 00 00 00 # 8 bytes -636 -637 # . . vim:nowrap:textwidth=0 + 91 # prime the pump + 92 # . Look = get-char(in) + 93 # . . push args + 94 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + 95 # . . call + 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 +100 # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. +101 # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. +102 # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. +103 # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. +104 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP +105 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX +106 # initialize the stream +107 # . num->length = 7 +108 c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) +109 # . clear-stream(num) +110 # . . push args +111 51/push-ECX +112 # . . call +113 e8/call clear-stream/disp32 +114 # . . discard args +115 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +116 # read a digit from 'in' into 'num' +117 # . get-num(in, num, err, ed) +118 # . . push args +119 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) +120 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) +121 51/push-ECX/num +122 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) +123 # . . call +124 e8/call get-num/disp32 +125 # . . discard args +126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +127 # render 'num' into the following template on 'out': +128 # bb/copy-to-EBX _num_ +129 # b8/copy-to-EAX 1/imm32/exit +130 # cd/syscall 0x80/imm8 +131 # +132 # . EAX = write(out, "bb/copy-to-EBX ") +133 # . . push args +134 68/push "bb/copy-to-EBX "/imm32 +135 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +136 # . . call +137 e8/call write/disp32 +138 # . . discard args +139 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +140 # . write-stream(out, num) +141 # . . push args +142 51/push-ECX/num +143 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +144 # . . call +145 e8/call write-stream/disp32 +146 # . . discard args +147 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +148 # . write(out, Newline) +149 # . . push args +150 68/push Newline/imm32 +151 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +152 # . . call +153 e8/call write/disp32 +154 # . . discard args +155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +156 # . write(out, "b8/copy-to-EAX 1/imm32/exit") +157 # . . push args +158 68/push "b8/copy-to-EAX 1/imm32/exit"/imm32 +159 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +160 # . . call +161 e8/call write/disp32 +162 # . . discard args +163 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +164 # . write(out, Newline) +165 # . . push args +166 68/push Newline/imm32 +167 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +168 # . . call +169 e8/call write/disp32 +170 # . . discard args +171 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +172 # . write(out, "cd/syscall 0x80/imm8") +173 # . . push args +174 68/push "cd/syscall 0x80/imm8"/imm32 +175 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +176 # . . call +177 e8/call write/disp32 +178 # . . discard args +179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +180 # . write(out, Newline) +181 # . . push args +182 68/push Newline/imm32 +183 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +184 # . . call +185 e8/call write/disp32 +186 # . . discard args +187 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +188 # . restore registers +189 59/pop-to-ECX +190 58/pop-to-EAX +191 # . epilog +192 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +193 5d/pop-to-EBP +194 c3/return +195 +196 # Read a single digit into 'out'. Abort if there are none, or if there is no space in 'out'. +197 # Input comes from the global variable 'Look', and we leave the next byte from +198 # 'in' into it on exit. +199 get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> +200 # pseudocode: +201 # if !is-digit?(Look) expected(ed, err, "integer") +202 # if out->write >= out->length +203 # write(err, "Error: too many digits in number\n") +204 # stop(ed, 1) +205 # out->data[out->write] = LSB(Look) +206 # ++out->write +207 # Look = get-char(in) +208 # +209 # registers: +210 # ESI : in +211 # EDI : out +212 # EAX : temp +213 # ECX : out->write +214 # EDX : out->length +215 # EBX : temp2 +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 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) +238 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 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 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +255 # EDI = out +256 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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 3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # 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 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) +268 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 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 # . restore registers +291 5f/pop-to-EDI +292 5e/pop-to-ESI +293 5b/pop-to-EBX +294 5a/pop-to-EDX +295 59/pop-to-ECX +296 58/pop-to-EAX +297 # . epilog +298 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +299 5d/pop-to-EBP +300 c3/return +301 +302 test-get-num-reads-single-digit: +303 # - check that get-num returns first character if it's a digit +304 # This test uses exit-descriptors. Use EBP for setting up local variables. +305 55/push-EBP +306 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +307 # clear all streams +308 # . clear-stream(_test-stream) +309 # . . push args +310 68/push _test-stream/imm32 +311 # . . call +312 e8/call clear-stream/disp32 +313 # . . discard args +314 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +315 # . clear-stream(_test-buffered-file+4) +316 # . . push args +317 b8/copy-to-EAX _test-buffered-file/imm32 +318 05/add-to-EAX 4/imm32 +319 50/push-EAX +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-output-stream) +325 # . . push args +326 68/push _test-output-stream/imm32 +327 # . . call +328 e8/call clear-stream/disp32 +329 # . . discard args +330 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +331 # . clear-stream(_test-error-stream) +332 # . . push args +333 68/push _test-error-stream/imm32 +334 # . . call +335 e8/call clear-stream/disp32 +336 # . . discard args +337 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +338 # initialize 'in' +339 # . write(_test-stream, "3") +340 # . . push args +341 68/push "3"/imm32 +342 68/push _test-stream/imm32 +343 # . . call +344 e8/call write/disp32 +345 # . . discard args +346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +347 # initialize exit-descriptor 'ed' for the call to 'get-num' below +348 # . var ed/EAX : exit-descriptor +349 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +350 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX +351 # . tailor-exit-descriptor(ed, 16) +352 # . . push args +353 68/push 0x10/imm32/nbytes-of-args-for-get-num +354 50/push-EAX/ed +355 # . . call +356 e8/call tailor-exit-descriptor/disp32 +357 # . . discard args +358 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +359 # prime the pump +360 # . get-char(_test-buffered-file) +361 # . . push args +362 68/push _test-buffered-file/imm32 +363 # . . call +364 e8/call get-char/disp32 +365 # . . discard args +366 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +367 # get-num(in, out, err, ed) +368 # . . push args +369 50/push-EAX/ed +370 68/push _test-error-stream/imm32 +371 68/push _test-output-stream/imm32 +372 68/push _test-buffered-file/imm32 +373 # . . call +374 e8/call get-num/disp32 +375 # registers except ESP may be clobbered at this point +376 # . . discard args +377 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +378 # check-ints-equal(*_test-output-stream->data, '3') +379 # . . push args +380 68/push "F - test-get-num-reads-single-digit"/imm32 +381 68/push 0x33/imm32 +382 b8/copy-to-EAX _test-output-stream/imm32 +383 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +384 # . . call +385 e8/call check-ints-equal/disp32 +386 # . . discard args +387 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +388 # . reclaim locals +389 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +390 5d/pop-to-EBP +391 c3/return +392 +393 test-get-num-aborts-on-non-digit-in-Look: +394 # - check that get-num returns first character if it's a digit +395 # This test uses exit-descriptors. Use EBP for setting up local variables. +396 55/push-EBP +397 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +398 # clear all streams +399 # . clear-stream(_test-stream) +400 # . . push args +401 68/push _test-stream/imm32 +402 # . . call +403 e8/call clear-stream/disp32 +404 # . . discard args +405 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +406 # . clear-stream(_test-buffered-file+4) +407 # . . push args +408 b8/copy-to-EAX _test-buffered-file/imm32 +409 05/add-to-EAX 4/imm32 +410 50/push-EAX +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-output-stream) +416 # . . push args +417 68/push _test-output-stream/imm32 +418 # . . call +419 e8/call clear-stream/disp32 +420 # . . discard args +421 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +422 # . clear-stream(_test-error-stream) +423 # . . push args +424 68/push _test-error-stream/imm32 +425 # . . call +426 e8/call clear-stream/disp32 +427 # . . discard args +428 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +429 # initialize 'in' +430 # . write(_test-stream, "3") +431 # . . push args +432 68/push "3"/imm32 +433 68/push _test-stream/imm32 +434 # . . call +435 e8/call write/disp32 +436 # . . discard args +437 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +438 # initialize exit-descriptor 'ed' for the call to 'get-num' below +439 # . var ed/EAX : (address exit-descriptor) +440 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +441 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX +442 # . tailor-exit-descriptor(ed, 16) +443 # . . push args +444 68/push 0x10/imm32/nbytes-of-args-for-get-num +445 50/push-EAX/ed +446 # . . call +447 e8/call tailor-exit-descriptor/disp32 +448 # . . discard args +449 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +450 # *don't* prime the pump +451 # get-num(in, out, err, ed) +452 # . . push args +453 50/push-EAX/ed +454 68/push _test-error-stream/imm32 +455 68/push _test-output-stream/imm32 +456 68/push _test-buffered-file/imm32 +457 # . . call +458 e8/call get-num/disp32 +459 # registers except ESP may be clobbered at this point +460 # . . discard args +461 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +462 # check that get-num tried to call exit(1) +463 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 +464 # . . push args +465 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 +466 68/push 2/imm32 +467 # . . push ed->value +468 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +469 # . . call +470 e8/call check-ints-equal/disp32 +471 # . . discard args +472 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +473 # . reclaim locals +474 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +475 5d/pop-to-EBP +476 c3/return +477 +478 ## helpers +479 +480 # write(f, "Error: "+s+" expected\n") then stop(ed, 1) +481 expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> +482 # . prolog +483 55/push-EBP +484 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +485 # write(f, "Error: ") +486 # . . push args +487 68/push "Error: "/imm32 +488 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +489 # . . call +490 e8/call write/disp32 +491 # . . discard args +492 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +493 # write(f, s) +494 # . . push args +495 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) +496 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +497 # . . call +498 e8/call write/disp32 +499 # . . discard args +500 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +501 # write(f, " expected") +502 # . . push args +503 68/push " expected"/imm32 +504 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +505 # . . call +506 e8/call write/disp32 +507 # . . discard args +508 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +509 # write(f, Newline) +510 # . . push args +511 68/push Newline/imm32 +512 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +513 # . . call +514 e8/call write/disp32 +515 # . . discard args +516 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +517 # stop(ed, 1) +518 # . . push args +519 68/push 1/imm32 +520 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) +521 # . . call +522 e8/call stop/disp32 +523 # should never get past this point +524 # . epilog +525 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +526 5d/pop-to-EBP +527 c3/return +528 +529 # write(f, "Error: "+s+"\n") then stop(ed, 1) +530 error: # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void> +531 # . prolog +532 55/push-EBP +533 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +534 # write(f, "Error: ") +535 # . . push args +536 68/push "Error: "/imm32 +537 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +538 # . . call +539 e8/call write/disp32 +540 # . . discard args +541 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +542 # write(f, s) +543 # . . push args +544 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) +545 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +546 # . . call +547 e8/call write/disp32 +548 # . . discard args +549 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +550 # write(f, Newline) +551 # . . push args +552 68/push Newline/imm32 +553 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) +554 # . . call +555 e8/call write/disp32 +556 # . . discard args +557 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +558 # stop(ed, 1) +559 # . . push args +560 68/push 1/imm32 +561 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) +562 # . . call +563 e8/call stop/disp32 +564 # should never get past this point +565 # . epilog +566 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +567 5d/pop-to-EBP +568 c3/return +569 +570 # read a byte from 'f', and save it in 'Look' +571 get-char: # f : (address buffered-file) -> <void> +572 # . prolog +573 55/push-EBP +574 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +575 # . save registers +576 50/push-EAX +577 # read-byte(f) +578 # . . push args +579 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) +580 # . . call +581 e8/call read-byte/disp32 +582 # . . discard args +583 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +584 # save EAX to Look +585 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look +586 # . restore registers +587 58/pop-to-EAX +588 # . epilog +589 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +590 5d/pop-to-EBP +591 c3/return +592 +593 is-digit?: # c : int -> bool/EAX +594 # . prolog +595 55/push-EBP +596 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +597 # EAX = false +598 b8/copy-to-EAX 0/imm32 +599 # if c < '0' return false +600 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 0x30/imm32 # compare *(EBP+8) +601 7c/jump-if-lesser $is-digit?:end/disp8 +602 # if c > '9' return false +603 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 0x39/imm32 # compare *(EBP+8) +604 7f/jump-if-greater $is-digit?:end/disp8 +605 # otherwise return true +606 b8/copy-to-EAX 1/imm32 +607 $is-digit?:end: +608 # . epilog +609 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +610 5d/pop-to-EBP +611 c3/return +612 +613 == data +614 +615 Look: # (char) +616 00 00 00 00 # = 0 +617 +618 _test-output-stream: +619 # current write index +620 00 00 00 00 +621 # current read index +622 00 00 00 00 +623 # length (= 8) +624 08 00 00 00 +625 # data +626 00 00 00 00 00 00 00 00 # 8 bytes +627 +628 _test-error-stream: +629 # current write index +630 00 00 00 00 +631 # current read index +632 00 00 00 00 +633 # length (= 8) +634 08 00 00 00 +635 # data +636 00 00 00 00 00 00 00 00 # 8 bytes +637 +638 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0