From e9909be37441c463404098d53b9e16c3724243bf Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Thu, 6 Dec 2018 11:01:23 -0800 Subject: 4849 --- html/subx/apps/hex.subx.html | 2109 ++++++++++++++++++++++-------------------- 1 file changed, 1099 insertions(+), 1010 deletions(-) (limited to 'html/subx/apps') diff --git a/html/subx/apps/hex.subx.html b/html/subx/apps/hex.subx.html index b5bd7458..ce78a35f 100644 --- a/html/subx/apps/hex.subx.html +++ b/html/subx/apps/hex.subx.html @@ -108,893 +108,893 @@ if ('onhashchange' in window) { 42 # . run-tests() 43 #? e8/call test-hex-below-0/disp32 44 #? e8/call test-scan-next-byte/disp32 - 45 #? e8/call test-scan-next-byte-skips-comment/disp32 - 46 e8/call run-tests/disp32 - 47 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 48 eb/jump $main:end/disp8 - 49 $run-main: - 50 # - otherwise convert stdin - 51 # var ed/EAX : exit-descriptor - 52 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 53 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - 54 # configure ed to really exit() - 55 # . ed->target = 0 - 56 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - 57 # return convert(Stdin, 1/stdout, 2/stderr, ed) - 58 # . . push args - 59 50/push-EAX/ed - 60 68/push 2/imm32/stderr - 61 68/push 1/imm32/stdout - 62 68/push Stdin/imm32 - 63 # . . call - 64 e8/call convert/disp32 - 65 # . . discard args - 66 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - 67 # . syscall(exit, 0) - 68 bb/copy-to-EBX 0/imm32 - 69 $main:end: - 70 b8/copy-to-EAX 1/imm32/exit - 71 cd/syscall 0x80/imm8 - 72 - 73 # the main entry point - 74 convert: # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void> - 75 # . prolog - 76 55/push-EBP - 77 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 78 # . save registers - 79 $convert:end: - 80 # . restore registers - 81 # . epilog - 82 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 83 5d/pop-to-EBP - 84 c3/return - 85 - 86 # read bytes from 'in' until a sequence of two lowercase hex characters (0-9, a-f) - 87 # skip spaces and newlines - 88 # on '#' skip bytes until newline - 89 # raise an error and abort on all other unexpected bytes - 90 # return the binary value of the two hex characters in EAX - 91 # return 0xffffffff on end of file - 92 convert-next-hex-byte: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-eof/EAX - 93 # pseudocode: - 94 # EAX = scan-next-byte(in, err, ed) - 95 # if (EAX == 0xffffffff) return - 96 # ECX = EAX - 97 # EAX = scan-next-byte(in, err, ed) - 98 # if (EAX == 0xffffffff) error("partial byte found") - 99 # ECX = (ECX << 8) | EAX - 100 # return - 101 # - 102 # . prolog - 103 55/push-EBP - 104 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 105 # . save registers - 106 $convert-next-hex-byte:end: - 107 # . restore registers - 108 # . epilog - 109 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 110 5d/pop-to-EBP - 111 c3/return - 112 - 113 # read whitespace until a hex byte, and return it - 114 # return 0xffffffff if file ends without finding a hex byte - 115 # on '#' skip all bytes until newline - 116 # abort on any other byte - 117 scan-next-byte: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-eof/EAX - 118 # pseudocode: - 119 # repeatedly - 120 # EAX = read-byte(in) - 121 # if is-hex-lowercase-byte?(EAX) return EAX - 122 # if EAX == 0x20 continue - 123 # if EAX == '#' skip-until-newline(in) - 124 # else error-byte(ed, err, "unexpected byte: " EAX) - 125 # return 0xffffffff - 126 # - 127 # . prolog - 128 55/push-EBP - 129 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 130 # . save registers - 131 $scan-next-byte:loop: - 132 # EAX = read-byte(in) - 133 # . . push args - 134 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 135 # . . call - 136 e8/call read-byte/disp32 - 137 # . . discard args - 138 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 139 # if is-hex-lowercase-byte?(EAX) return EAX - 140 # . save EAX for now - 141 50/push-EAX - 142 # . is-hex-lowercase-byte?(EAX) - 143 # . . push args - 144 50/push-EAX - 145 # . . call - 146 e8/call is-hex-lowercase-byte?/disp32 - 147 # . . discard args - 148 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 149 # . compare with 'false' - 150 3d/compare-with-EAX 0/imm32 - 151 # . restore EAX (does not affect flags) - 152 58/pop-to-EAX - 153 # . check whether to return - 154 75/jump-if-not-equal $scan-next-byte:end/disp8 - 155 $scan-next-byte:check1: - 156 # if EAX == ' ' continue - 157 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x20/imm32 # compare EAX - 158 74/jump-if-equal $scan-next-byte:loop/disp8 - 159 # if EAX == '\t' continue - 160 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x9/imm32 # compare EAX - 161 74/jump-if-equal $scan-next-byte:loop/disp8 - 162 # if EAX == '\n' continue - 163 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX - 164 74/jump-if-equal $scan-next-byte:loop/disp8 - 165 $scan-next-byte:check2: - 166 # if EAX == '#' skip-until-newline(in) - 167 3d/compare-with-EAX 0x23/imm32 - 168 75/jump-if-not-equal $scan-next-byte:check3/disp8 - 169 # . skip-until-newline(in) - 170 # . . push args - 171 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 172 # . . call - 173 e8/call skip-until-newline/disp32 - 174 # . . discard args - 175 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 176 eb/jump $scan-next-byte:loop/disp8 - 177 $scan-next-byte:check3: - 178 # otherwise error-byte(ed, err, msg, EAX) - 179 # . . push args - 180 50/push-EAX - 181 68/push "scan-next-byte: invalid byte"/imm32 - 182 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - 183 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) - 184 # . . call - 185 e8/call error-byte/disp32 # never returns - 186 $scan-next-byte:end: - 187 # . restore registers - 188 # . epilog - 189 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 190 5d/pop-to-EBP - 191 c3/return - 192 - 193 test-scan-next-byte: - 194 # - check that the first byte of the input is returned - 195 # This test uses exit-descriptors. Use EBP for setting up local variables. - 196 55/push-EBP - 197 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 198 # clear all streams - 199 # . clear-stream(_test-stream) - 200 # . . push args - 201 68/push _test-stream/imm32 - 202 # . . call - 203 e8/call clear-stream/disp32 - 204 # . . discard args - 205 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 206 # . clear-stream(_test-buffered-file+4) - 207 # . . push args - 208 b8/copy-to-EAX _test-buffered-file/imm32 - 209 05/add-to-EAX 4/imm32 - 210 50/push-EAX - 211 # . . call - 212 e8/call clear-stream/disp32 - 213 # . . discard args - 214 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 215 # . clear-stream(_test-error-stream) - 216 # . . push args - 217 68/push _test-error-stream/imm32 - 218 # . . call - 219 e8/call clear-stream/disp32 - 220 # . . discard args - 221 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 222 # initialize '_test-stream' to "abc" - 223 # . write(_test-stream, "abc") - 224 # . . push args - 225 68/push "abc"/imm32 - 226 68/push _test-stream/imm32 - 227 # . . call - 228 e8/call write/disp32 - 229 # . . discard args - 230 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 231 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 232 # . var ed/ECX : exit-descriptor - 233 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 234 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 235 # . tailor-exit-descriptor(ed, 12) - 236 # . . push args - 237 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 238 51/push-ECX/ed - 239 # . . call - 240 e8/call tailor-exit-descriptor/disp32 - 241 # . . discard args - 242 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 243 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 244 # . . push args - 245 51/push-ECX/ed - 246 68/push _test-error-stream/imm32 - 247 68/push _test-buffered-file/imm32 - 248 # . . call - 249 e8/call scan-next-byte/disp32 - 250 # registers except ESP may be clobbered at this point - 251 # pop args to scan-next-bytes - 252 # . . discard first 2 args - 253 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 254 # . . restore ed - 255 59/pop-to-ECX - 256 # check that scan-next-byte didn't abort - 257 # . check-ints-equal(ed->value, 0, msg) - 258 # . . push args - 259 68/push "F - test-scan-next-byte: unexpected abort"/imm32 - 260 68/push 0/imm32 - 261 # . . push ed->value - 262 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 263 # . . call - 264 e8/call check-ints-equal/disp32 - 265 # . . discard args - 266 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 267 # return if abort - 268 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 269 75/jump-if-not-equal $test-scan-next-byte:end/disp8 - 270 # check-ints-equal(EAX, 0x61/a, msg) - 271 # . . push args - 272 68/push "F - test-scan-next-byte"/imm32 - 273 68/push 0x61/imm32/a - 274 50/push-EAX - 275 # . . call - 276 e8/call check-ints-equal/disp32 - 277 # . . discard args - 278 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 279 $test-scan-next-byte:end: - 280 # . epilog - 281 # don't restore ESP from EBP; manually reclaim locals - 282 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 283 5d/pop-to-EBP - 284 c3/return - 285 - 286 test-scan-next-byte-skips-whitespace: - 287 # - check that the first byte after whitespace is returned - 288 # This test uses exit-descriptors. Use EBP for setting up local variables. - 289 55/push-EBP - 290 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 291 # clear all streams - 292 # . clear-stream(_test-stream) - 293 # . . push args - 294 68/push _test-stream/imm32 - 295 # . . call - 296 e8/call clear-stream/disp32 - 297 # . . discard args - 298 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 299 # . clear-stream(_test-buffered-file+4) - 300 # . . push args - 301 b8/copy-to-EAX _test-buffered-file/imm32 - 302 05/add-to-EAX 4/imm32 - 303 50/push-EAX - 304 # . . call - 305 e8/call clear-stream/disp32 - 306 # . . discard args - 307 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 308 # . clear-stream(_test-error-stream) - 309 # . . push args - 310 68/push _test-error-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 # initialize '_test-stream' to input with leading whitespace - 316 # . write(_test-stream, text) - 317 # . . push args - 318 68/push " abc"/imm32 - 319 68/push _test-stream/imm32 - 320 # . . call - 321 e8/call write/disp32 - 322 # . . discard args - 323 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 324 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 325 # . var ed/ECX : exit-descriptor - 326 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 327 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 328 # . tailor-exit-descriptor(ed, 12) - 329 # . . push args - 330 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 331 51/push-ECX/ed - 332 # . . call - 333 e8/call tailor-exit-descriptor/disp32 - 334 # . . discard args - 335 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 336 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 337 # . . push args - 338 51/push-ECX/ed - 339 68/push _test-error-stream/imm32 - 340 68/push _test-buffered-file/imm32 - 341 # . . call - 342 e8/call scan-next-byte/disp32 - 343 # registers except ESP may be clobbered at this point - 344 # pop args to scan-next-bytes - 345 # . . discard first 2 args - 346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 347 # . . restore ed - 348 59/pop-to-ECX - 349 # check that scan-next-byte didn't abort - 350 # . check-ints-equal(ed->value, 0, msg) - 351 # . . push args - 352 68/push "F - test-scan-next-byte-skips-whitespace: unexpected abort"/imm32 - 353 68/push 0/imm32 - 354 # . . push ed->value - 355 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 356 # . . call - 357 e8/call check-ints-equal/disp32 - 358 # . . discard args - 359 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 360 # return if abort - 361 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 362 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace:end/disp8 - 363 # check-ints-equal(EAX, 0x61/a, msg) - 364 # . . push args - 365 68/push "F - test-scan-next-byte-skips-whitespace"/imm32 - 366 68/push 0x61/imm32/a - 367 50/push-EAX - 368 # . . call - 369 e8/call check-ints-equal/disp32 - 370 # . . discard args - 371 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 372 $test-scan-next-byte-skips-whitespace:end: - 373 # . epilog - 374 # don't restore ESP from EBP; manually reclaim locals - 375 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 376 5d/pop-to-EBP - 377 c3/return - 378 - 379 test-scan-next-byte-skips-comment: - 380 # - check that the first byte after a comment (and newline) is returned - 381 # This test uses exit-descriptors. Use EBP for setting up local variables. - 382 55/push-EBP - 383 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 384 # clear all streams - 385 # . clear-stream(_test-stream) - 386 # . . push args - 387 68/push _test-stream/imm32 - 388 # . . call - 389 e8/call clear-stream/disp32 - 390 # . . discard args - 391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 392 # . clear-stream(_test-buffered-file+4) - 393 # . . push args - 394 b8/copy-to-EAX _test-buffered-file/imm32 - 395 05/add-to-EAX 4/imm32 - 396 50/push-EAX - 397 # . . call - 398 e8/call clear-stream/disp32 - 399 # . . discard args - 400 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 401 # . clear-stream(_test-error-stream) - 402 # . . push args - 403 68/push _test-error-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 # initialize '_test-stream' to input with leading comment - 409 # . write(_test-stream, comment) - 410 # . . push args - 411 68/push "#x"/imm32 - 412 68/push _test-stream/imm32 - 413 # . . call - 414 e8/call write/disp32 - 415 # . . discard args - 416 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 417 # . write(_test-stream, Newline) - 418 # . . push args - 419 68/push Newline/imm32 - 420 68/push _test-stream/imm32 - 421 # . . call - 422 e8/call write/disp32 - 423 # . . discard args - 424 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 425 # . write(_test-stream, real text) - 426 # . . push args - 427 68/push "ab"/imm32 - 428 68/push _test-stream/imm32 - 429 # . . call - 430 e8/call write/disp32 - 431 # . . discard args - 432 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 433 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 434 # . var ed/ECX : exit-descriptor - 435 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 436 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 437 # . tailor-exit-descriptor(ed, 12) - 438 # . . push args - 439 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 440 51/push-ECX/ed - 441 # . . call - 442 e8/call tailor-exit-descriptor/disp32 - 443 # . . discard args - 444 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 445 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 446 # . . push args - 447 51/push-ECX/ed - 448 68/push _test-error-stream/imm32 - 449 68/push _test-buffered-file/imm32 - 450 # . . call - 451 e8/call scan-next-byte/disp32 - 452 # registers except ESP may be clobbered at this point - 453 # pop args to scan-next-bytes - 454 # . . discard first 2 args - 455 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 456 # . . restore ed - 457 59/pop-to-ECX - 458 # check that scan-next-byte didn't abort - 459 # . check-ints-equal(ed->value, 0, msg) - 460 # . . push args - 461 68/push "F - test-scan-next-byte-skips-comment: unexpected abort"/imm32 - 462 68/push 0/imm32 - 463 # . . push ed->value - 464 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 465 # . . call - 466 e8/call check-ints-equal/disp32 - 467 # . . discard args - 468 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 469 # return if abort - 470 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 471 75/jump-if-not-equal $test-scan-next-byte-skips-comment:end/disp8 - 472 # check-ints-equal(EAX, 0x61/a, msg) - 473 # . . push args - 474 68/push "F - test-scan-next-byte-skips-comment"/imm32 - 475 68/push 0x61/imm32/a - 476 50/push-EAX - 477 # . . call - 478 e8/call check-ints-equal/disp32 - 479 # . . discard args - 480 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 481 $test-scan-next-byte-skips-comment:end: - 482 # . epilog - 483 # don't restore ESP from EBP; manually reclaim locals - 484 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 485 5d/pop-to-EBP - 486 c3/return - 487 - 488 test-scan-next-byte-skips-comment-and-whitespace: - 489 # - check that the first byte after a comment and any further whitespace is returned - 490 # This test uses exit-descriptors. Use EBP for setting up local variables. - 491 55/push-EBP - 492 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 493 # clear all streams - 494 # . clear-stream(_test-stream) - 495 # . . push args - 496 68/push _test-stream/imm32 - 497 # . . call - 498 e8/call clear-stream/disp32 - 499 # . . discard args - 500 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 501 # . clear-stream(_test-buffered-file+4) - 502 # . . push args - 503 b8/copy-to-EAX _test-buffered-file/imm32 - 504 05/add-to-EAX 4/imm32 - 505 50/push-EAX - 506 # . . call - 507 e8/call clear-stream/disp32 - 508 # . . discard args - 509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 510 # . clear-stream(_test-error-stream) - 511 # . . push args - 512 68/push _test-error-stream/imm32 - 513 # . . call - 514 e8/call clear-stream/disp32 - 515 # . . discard args - 516 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 517 # initialize '_test-stream' to input with leading comment and more whitespace after newline - 518 # . write(_test-stream, comment) - 519 # . . push args - 520 68/push "#x"/imm32 - 521 68/push _test-stream/imm32 - 522 # . . call - 523 e8/call write/disp32 - 524 # . . discard args - 525 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 526 # . write(_test-stream, Newline) - 527 # . . push args - 528 68/push Newline/imm32 - 529 68/push _test-stream/imm32 - 530 # . . call - 531 e8/call write/disp32 - 532 # . . discard args - 533 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 534 # . write(_test-stream, real text) - 535 # . . push args - 536 68/push " ab"/imm32 - 537 68/push _test-stream/imm32 - 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 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 543 # . var ed/ECX : exit-descriptor - 544 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 545 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 546 # . tailor-exit-descriptor(ed, 12) - 547 # . . push args - 548 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 549 51/push-ECX/ed - 550 # . . call - 551 e8/call tailor-exit-descriptor/disp32 - 552 # . . discard args - 553 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 554 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 555 # . . push args - 556 51/push-ECX/ed - 557 68/push _test-error-stream/imm32 - 558 68/push _test-buffered-file/imm32 - 559 # . . call - 560 e8/call scan-next-byte/disp32 - 561 # registers except ESP may be clobbered at this point - 562 # pop args to scan-next-bytes - 563 # . . discard first 2 args - 564 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 565 # . . restore ed - 566 59/pop-to-ECX - 567 # check that scan-next-byte didn't abort - 568 # . check-ints-equal(ed->value, 0, msg) - 569 # . . push args - 570 68/push "F - test-scan-next-byte-skips-comment-and-whitespace: unexpected abort"/imm32 - 571 68/push 0/imm32 - 572 # . . push ed->value - 573 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 574 # . . call - 575 e8/call check-ints-equal/disp32 - 576 # . . discard args - 577 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 578 # return if abort - 579 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 580 75/jump-if-not-equal $test-scan-next-byte-skips-comment-and-whitespace:end/disp8 - 581 # check-ints-equal(EAX, 0x61/a, msg) - 582 # . . push args - 583 68/push "F - test-scan-next-byte-skips-comment-and-whitespace"/imm32 - 584 68/push 0x61/imm32/a - 585 50/push-EAX - 586 # . . call - 587 e8/call check-ints-equal/disp32 - 588 # . . discard args - 589 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 590 $test-scan-next-byte-skips-comment-and-whitespace:end: - 591 # . epilog - 592 # don't restore ESP from EBP; manually reclaim locals - 593 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 594 5d/pop-to-EBP - 595 c3/return - 596 - 597 test-scan-next-byte-skips-whitespace-and-comment: - 598 # - check that the first byte after any whitespace and comments is returned - 599 # This test uses exit-descriptors. Use EBP for setting up local variables. - 600 55/push-EBP - 601 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 602 # clear all streams - 603 # . clear-stream(_test-stream) - 604 # . . push args - 605 68/push _test-stream/imm32 - 606 # . . call - 607 e8/call clear-stream/disp32 - 608 # . . discard args - 609 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 610 # . clear-stream(_test-buffered-file+4) - 611 # . . push args - 612 b8/copy-to-EAX _test-buffered-file/imm32 - 613 05/add-to-EAX 4/imm32 - 614 50/push-EAX - 615 # . . call - 616 e8/call clear-stream/disp32 - 617 # . . discard args - 618 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 619 # . clear-stream(_test-error-stream) - 620 # . . push args - 621 68/push _test-error-stream/imm32 - 622 # . . call - 623 e8/call clear-stream/disp32 - 624 # . . discard args - 625 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 626 # initialize '_test-stream' to input with leading whitespace and comment - 627 # . write(_test-stream, comment) - 628 # . . push args - 629 68/push " #x"/imm32 - 630 68/push _test-stream/imm32 - 631 # . . call - 632 e8/call write/disp32 - 633 # . . discard args - 634 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 635 # . write(_test-stream, Newline) - 636 # . . push args - 637 68/push Newline/imm32 - 638 68/push _test-stream/imm32 - 639 # . . call - 640 e8/call write/disp32 - 641 # . . discard args - 642 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 643 # . write(_test-stream, real text) - 644 # . . push args - 645 68/push "ab"/imm32 - 646 68/push _test-stream/imm32 - 647 # . . call - 648 e8/call write/disp32 - 649 # . . discard args - 650 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 651 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 652 # . var ed/ECX : exit-descriptor - 653 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 654 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 655 # . tailor-exit-descriptor(ed, 12) - 656 # . . push args - 657 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 658 51/push-ECX/ed - 659 # . . call - 660 e8/call tailor-exit-descriptor/disp32 - 661 # . . discard args - 662 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 663 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 664 # . . push args - 665 51/push-ECX/ed - 666 68/push _test-error-stream/imm32 - 667 68/push _test-buffered-file/imm32 - 668 # . . call - 669 e8/call scan-next-byte/disp32 - 670 # registers except ESP may be clobbered at this point - 671 # pop args to scan-next-bytes - 672 # . . discard first 2 args - 673 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 674 # . . restore ed - 675 59/pop-to-ECX - 676 # check that scan-next-byte didn't abort - 677 # . check-ints-equal(ed->value, 0, msg) - 678 # . . push args - 679 68/push "F - test-scan-next-byte-skips-whitespace-and-comment: unexpected abort"/imm32 - 680 68/push 0/imm32 - 681 # . . push ed->value - 682 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 683 # . . call - 684 e8/call check-ints-equal/disp32 - 685 # . . discard args - 686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 687 # return if abort - 688 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 689 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace-and-comment:end/disp8 - 690 # check-ints-equal(EAX, 0x61/a, msg) - 691 # . . push args - 692 68/push "F - test-scan-next-byte-skips-whitespace-and-comment"/imm32 - 693 68/push 0x61/imm32/a - 694 50/push-EAX - 695 # . . call - 696 e8/call check-ints-equal/disp32 - 697 # . . discard args - 698 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 699 $test-scan-next-byte-skips-whitespace-and-comment:end: - 700 # . epilog - 701 # don't restore ESP from EBP; manually reclaim locals - 702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 703 5d/pop-to-EBP - 704 c3/return - 705 - 706 test-scan-next-byte-reads-final-byte: - 707 # - check that the final byte in input is returned - 708 # This test uses exit-descriptors. Use EBP for setting up local variables. - 709 55/push-EBP - 710 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 711 # clear all streams - 712 # . clear-stream(_test-stream) - 713 # . . push args - 714 68/push _test-stream/imm32 - 715 # . . call - 716 e8/call clear-stream/disp32 - 717 # . . discard args - 718 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 719 # . clear-stream(_test-buffered-file+4) - 720 # . . push args - 721 b8/copy-to-EAX _test-buffered-file/imm32 - 722 05/add-to-EAX 4/imm32 - 723 50/push-EAX - 724 # . . call - 725 e8/call clear-stream/disp32 - 726 # . . discard args - 727 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 728 # . clear-stream(_test-error-stream) - 729 # . . push args - 730 68/push _test-error-stream/imm32 - 731 # . . call - 732 e8/call clear-stream/disp32 - 733 # . . discard args - 734 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 735 # initialize '_test-stream' to input with single character - 736 # . write(_test-stream, character) - 737 # . . push args - 738 68/push "a"/imm32 - 739 68/push _test-stream/imm32 - 740 # . . call - 741 e8/call write/disp32 - 742 # . . discard args - 743 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 744 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - 745 # . var ed/ECX : exit-descriptor - 746 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 747 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX - 748 # . tailor-exit-descriptor(ed, 12) - 749 # . . push args - 750 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 751 51/push-ECX/ed - 752 # . . call - 753 e8/call tailor-exit-descriptor/disp32 - 754 # . . discard args - 755 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 756 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) - 757 # . . push args - 758 51/push-ECX/ed - 759 68/push _test-error-stream/imm32 - 760 68/push _test-buffered-file/imm32 - 761 # . . call - 762 e8/call scan-next-byte/disp32 - 763 # registers except ESP may be clobbered at this point - 764 # pop args to scan-next-bytes - 765 # . . discard first 2 args - 766 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 767 # . . restore ed - 768 59/pop-to-ECX - 769 # check that scan-next-byte didn't abort - 770 # . check-ints-equal(ed->value, 0, msg) - 771 # . . push args - 772 68/push "F - test-scan-next-byte-reads-final-byte: unexpected abort"/imm32 - 773 68/push 0/imm32 - 774 # . . push ed->value - 775 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - 776 # . . call - 777 e8/call check-ints-equal/disp32 - 778 # . . discard args - 779 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 780 # return if abort - 781 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 782 75/jump-if-not-equal $test-scan-next-byte-reads-final-byte:end/disp8 - 783 # check-ints-equal(EAX, 0x61/a, msg) - 784 # . . push args - 785 68/push "F - test-scan-next-byte-reads-final-byte"/imm32 - 786 68/push 0x61/imm32/a - 787 50/push-EAX - 788 # . . call - 789 e8/call check-ints-equal/disp32 - 790 # . . discard args - 791 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 792 $test-scan-next-byte-reads-final-byte:end: - 793 # . epilog - 794 # don't restore ESP from EBP; manually reclaim locals - 795 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 796 5d/pop-to-EBP - 797 c3/return - 798 - 799 is-hex-lowercase-byte?: # c : byte -> bool/EAX - 800 # . prolog - 801 55/push-EBP - 802 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 803 # . save registers - 804 51/push-ECX - 805 # ECX = c - 806 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - 807 # return false if c < '0' - 808 b8/copy-to-EAX 0/imm32/false - 809 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x30/imm32 # compare ECX - 810 7c/jump-if-lesser $is-hex-lowercase-byte?:end/disp8 - 811 # return false if c > 'f' - 812 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x66/imm32 # compare ECX - 813 7f/jump-if-greater $is-hex-lowercase-byte?:end/disp8 - 814 # return true if c <= '9' - 815 b8/copy-to-EAX 1/imm32/true - 816 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x39/imm32 # compare ECX - 817 7e/jump-if-lesser-or-equal $is-hex-lowercase-byte?:end/disp8 - 818 # return true if c >= 'a' - 819 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x61/imm32 # compare ECX - 820 7d/jump-if-greater-or-equal $is-hex-lowercase-byte?:end/disp8 - 821 # otherwise return false - 822 b8/copy-to-EAX 0/imm32/false - 823 $is-hex-lowercase-byte?:end: - 824 # . restore registers - 825 59/pop-to-ECX - 826 # . epilog - 827 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 828 5d/pop-to-EBP - 829 c3/return - 830 - 831 test-hex-below-0: - 832 # is-hex-lowercase-byte?(0x2f) - 833 # . . push args - 834 68/push 0x2f/imm32 - 835 # . . call - 836 e8/call is-hex-lowercase-byte?/disp32 - 837 # . . discard args - 838 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 839 # check-ints-equal(EAX, 0, msg) - 840 # . . push args - 841 68/push "F - test-hex-below-0"/imm32 - 842 68/push 0/imm32/false - 843 50/push-EAX - 844 # . . call - 845 e8/call check-ints-equal/disp32 - 846 # . . discard args - 847 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 848 c3/return - 849 - 850 test-hex-0-to-9: - 851 # is-hex-lowercase-byte?(0x30) - 852 # . . push args - 853 68/push 0x30/imm32 - 854 # . . call - 855 e8/call is-hex-lowercase-byte?/disp32 - 856 # . . discard args - 857 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 858 # check-ints-equal(EAX, 1, msg) - 859 # . . push args - 860 68/push "F - test-hex-at-0"/imm32 - 861 68/push 1/imm32/true - 862 50/push-EAX - 863 # . . call - 864 e8/call check-ints-equal/disp32 - 865 # . . discard args - 866 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 867 # is-hex-lowercase-byte?(0x39) - 868 # . . push args - 869 68/push 0x39/imm32 - 870 # . . call - 871 e8/call is-hex-lowercase-byte?/disp32 - 872 # . . discard args - 873 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 874 # check-ints-equal(EAX, 1, msg) - 875 # . . push args - 876 68/push "F - test-hex-at-9"/imm32 - 877 68/push 1/imm32/true - 878 50/push-EAX - 879 # . . call - 880 e8/call check-ints-equal/disp32 - 881 # . . discard args - 882 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 883 c3/return - 884 - 885 test-hex-above-9-to-a: - 886 # is-hex-lowercase-byte?(0x3a) - 887 # . . push args - 888 68/push 0x3a/imm32 - 889 # . . call - 890 e8/call is-hex-lowercase-byte?/disp32 - 891 # . . discard args - 892 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 893 # check-ints-equal(EAX, 0, msg) - 894 # . . push args - 895 68/push "F - test-hex-above-9-to-a"/imm32 - 896 68/push 0/imm32/false - 897 50/push-EAX - 898 # . . call - 899 e8/call check-ints-equal/disp32 - 900 # . . discard args - 901 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 902 c3/return - 903 - 904 test-hex-a-to-f: - 905 # is-hex-lowercase-byte?(0x61) - 906 # . . push args - 907 68/push 0x61/imm32 - 908 # . . call - 909 e8/call is-hex-lowercase-byte?/disp32 - 910 # . . discard args - 911 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 912 # check-ints-equal(EAX, 1, msg) - 913 # . . push args - 914 68/push "F - test-hex-at-a"/imm32 - 915 68/push 1/imm32/true - 916 50/push-EAX - 917 # . . call - 918 e8/call check-ints-equal/disp32 - 919 # . . discard args - 920 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 921 # is-hex-lowercase-byte?(0x66) + 45 #? e8/call test-scan-next-byte-handles-eof/disp32 + 46 #? e8/call test-scan-next-byte-skips-comment/disp32 + 47 e8/call run-tests/disp32 + 48 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 49 eb/jump $main:end/disp8 + 50 $run-main: + 51 # - otherwise convert stdin + 52 # var ed/EAX : exit-descriptor + 53 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 54 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX + 55 # configure ed to really exit() + 56 # . ed->target = 0 + 57 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX + 58 # return convert(Stdin, 1/stdout, 2/stderr, ed) + 59 # . . push args + 60 50/push-EAX/ed + 61 68/push 2/imm32/stderr + 62 68/push 1/imm32/stdout + 63 68/push Stdin/imm32 + 64 # . . call + 65 e8/call convert/disp32 + 66 # . . discard args + 67 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 68 # . syscall(exit, 0) + 69 bb/copy-to-EBX 0/imm32 + 70 $main:end: + 71 b8/copy-to-EAX 1/imm32/exit + 72 cd/syscall 0x80/imm8 + 73 + 74 # the main entry point + 75 convert: # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void> + 76 # . prolog + 77 55/push-EBP + 78 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 79 # . save registers + 80 $convert:end: + 81 # . restore registers + 82 # . epilog + 83 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 84 5d/pop-to-EBP + 85 c3/return + 86 + 87 # read bytes from 'in' until a sequence of two lowercase hex characters (0-9, a-f) + 88 # skip spaces and newlines + 89 # on '#' skip bytes until newline + 90 # raise an error and abort on all other unexpected bytes + 91 # return the binary value of the two hex characters in EAX + 92 # return 0xffffffff on end of file + 93 convert-next-hex-byte: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-eof/EAX + 94 # pseudocode: + 95 # EAX = scan-next-byte(in, err, ed) + 96 # if (EAX == 0xffffffff) return + 97 # ECX = EAX + 98 # EAX = scan-next-byte(in, err, ed) + 99 # if (EAX == 0xffffffff) error("partial byte found") + 100 # ECX = (ECX << 8) | EAX + 101 # return + 102 # + 103 # . prolog + 104 55/push-EBP + 105 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 106 # . save registers + 107 $convert-next-hex-byte:end: + 108 # . restore registers + 109 # . epilog + 110 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 111 5d/pop-to-EBP + 112 c3/return + 113 + 114 # read whitespace until a hex byte, and return it + 115 # return 0xffffffff if file ends without finding a hex byte + 116 # on '#' skip all bytes until newline + 117 # abort on any other byte + 118 scan-next-byte: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-eof/EAX + 119 # pseudocode: + 120 # repeatedly + 121 # EAX = read-byte(in) + 122 # if EAX == 0xffffffff return EAX + 123 # if is-hex-lowercase-byte?(EAX) return EAX + 124 # if EAX == 0x20 continue + 125 # if EAX == '#' skip-until-newline(in) + 126 # else error-byte(ed, err, "unexpected byte: " EAX) + 127 # + 128 # . prolog + 129 55/push-EBP + 130 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 131 # . save registers + 132 $scan-next-byte:loop: + 133 # EAX = read-byte(in) + 134 # . . push args + 135 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + 136 # . . call + 137 e8/call read-byte/disp32 + 138 # . . discard args + 139 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 140 # if (EAX == 0xffffffff) return EAX + 141 3d/compare-with-EAX 0xffffffff/imm32 + 142 74/jump-if-equal $scan-next-byte:end/disp8 + 143 # if is-hex-lowercase-byte?(EAX) return EAX + 144 # . save EAX for now + 145 50/push-EAX + 146 # . is-hex-lowercase-byte?(EAX) + 147 # . . push args + 148 50/push-EAX + 149 # . . call + 150 e8/call is-hex-lowercase-byte?/disp32 + 151 # . . discard args + 152 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 153 # . compare with 'false' + 154 3d/compare-with-EAX 0/imm32 + 155 # . restore EAX (does not affect flags) + 156 58/pop-to-EAX + 157 # . check whether to return + 158 75/jump-if-not-equal $scan-next-byte:end/disp8 + 159 $scan-next-byte:check1: + 160 # if EAX == ' ' continue + 161 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x20/imm32 # compare EAX + 162 74/jump-if-equal $scan-next-byte:loop/disp8 + 163 # if EAX == '\t' continue + 164 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x9/imm32 # compare EAX + 165 74/jump-if-equal $scan-next-byte:loop/disp8 + 166 # if EAX == '\n' continue + 167 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX + 168 74/jump-if-equal $scan-next-byte:loop/disp8 + 169 $scan-next-byte:check2: + 170 # if EAX == '#' skip-until-newline(in) + 171 3d/compare-with-EAX 0x23/imm32 + 172 75/jump-if-not-equal $scan-next-byte:check3/disp8 + 173 # . skip-until-newline(in) + 174 # . . push args + 175 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + 176 # . . call + 177 e8/call skip-until-newline/disp32 + 178 # . . discard args + 179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 180 eb/jump $scan-next-byte:loop/disp8 + 181 $scan-next-byte:check3: + 182 # otherwise error-byte(ed, err, msg, EAX) + 183 # . . push args + 184 50/push-EAX + 185 68/push "scan-next-byte: invalid byte"/imm32 + 186 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + 187 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) + 188 # . . call + 189 e8/call error-byte/disp32 # never returns + 190 $scan-next-byte:end: + 191 # . restore registers + 192 # . epilog + 193 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 194 5d/pop-to-EBP + 195 c3/return + 196 + 197 test-scan-next-byte: + 198 # - check that the first byte of the input is returned + 199 # This test uses exit-descriptors. Use EBP for setting up local variables. + 200 55/push-EBP + 201 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 202 # clear all streams + 203 # . clear-stream(_test-stream) + 204 # . . push args + 205 68/push _test-stream/imm32 + 206 # . . call + 207 e8/call clear-stream/disp32 + 208 # . . discard args + 209 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 210 # . clear-stream(_test-buffered-file+4) + 211 # . . push args + 212 b8/copy-to-EAX _test-buffered-file/imm32 + 213 05/add-to-EAX 4/imm32 + 214 50/push-EAX + 215 # . . call + 216 e8/call clear-stream/disp32 + 217 # . . discard args + 218 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 219 # . clear-stream(_test-error-stream) + 220 # . . push args + 221 68/push _test-error-stream/imm32 + 222 # . . call + 223 e8/call clear-stream/disp32 + 224 # . . discard args + 225 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 226 # initialize '_test-stream' to "abc" + 227 # . write(_test-stream, "abc") + 228 # . . push args + 229 68/push "abc"/imm32 + 230 68/push _test-stream/imm32 + 231 # . . call + 232 e8/call write/disp32 + 233 # . . discard args + 234 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 235 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 236 # . var ed/ECX : exit-descriptor + 237 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 238 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 239 # . tailor-exit-descriptor(ed, 12) + 240 # . . push args + 241 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 242 51/push-ECX/ed + 243 # . . call + 244 e8/call tailor-exit-descriptor/disp32 + 245 # . . discard args + 246 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 247 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 248 # . . push args + 249 51/push-ECX/ed + 250 68/push _test-error-stream/imm32 + 251 68/push _test-buffered-file/imm32 + 252 # . . call + 253 e8/call scan-next-byte/disp32 + 254 # registers except ESP may be clobbered at this point + 255 # pop args to scan-next-bytes + 256 # . . discard first 2 args + 257 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 258 # . . restore ed + 259 59/pop-to-ECX + 260 # check that scan-next-byte didn't abort + 261 # . check-ints-equal(ed->value, 0, msg) + 262 # . . push args + 263 68/push "F - test-scan-next-byte: unexpected abort"/imm32 + 264 68/push 0/imm32 + 265 # . . push ed->value + 266 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 267 # . . call + 268 e8/call check-ints-equal/disp32 + 269 # . . discard args + 270 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 271 # return if abort + 272 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 273 75/jump-if-not-equal $test-scan-next-byte:end/disp8 + 274 # check-ints-equal(EAX, 0x61/a, msg) + 275 # . . push args + 276 68/push "F - test-scan-next-byte"/imm32 + 277 68/push 0x61/imm32/a + 278 50/push-EAX + 279 # . . call + 280 e8/call check-ints-equal/disp32 + 281 # . . discard args + 282 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 283 $test-scan-next-byte:end: + 284 # . epilog + 285 # don't restore ESP from EBP; manually reclaim locals + 286 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 287 5d/pop-to-EBP + 288 c3/return + 289 + 290 test-scan-next-byte-skips-whitespace: + 291 # - check that the first byte after whitespace is returned + 292 # This test uses exit-descriptors. Use EBP for setting up local variables. + 293 55/push-EBP + 294 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 295 # clear all streams + 296 # . clear-stream(_test-stream) + 297 # . . push args + 298 68/push _test-stream/imm32 + 299 # . . call + 300 e8/call clear-stream/disp32 + 301 # . . discard args + 302 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 303 # . clear-stream(_test-buffered-file+4) + 304 # . . push args + 305 b8/copy-to-EAX _test-buffered-file/imm32 + 306 05/add-to-EAX 4/imm32 + 307 50/push-EAX + 308 # . . call + 309 e8/call clear-stream/disp32 + 310 # . . discard args + 311 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 312 # . clear-stream(_test-error-stream) + 313 # . . push args + 314 68/push _test-error-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 # initialize '_test-stream' to input with leading whitespace + 320 # . write(_test-stream, text) + 321 # . . push args + 322 68/push " abc"/imm32 + 323 68/push _test-stream/imm32 + 324 # . . call + 325 e8/call write/disp32 + 326 # . . discard args + 327 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 328 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 329 # . var ed/ECX : exit-descriptor + 330 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 331 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 332 # . tailor-exit-descriptor(ed, 12) + 333 # . . push args + 334 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 335 51/push-ECX/ed + 336 # . . call + 337 e8/call tailor-exit-descriptor/disp32 + 338 # . . discard args + 339 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 340 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 341 # . . push args + 342 51/push-ECX/ed + 343 68/push _test-error-stream/imm32 + 344 68/push _test-buffered-file/imm32 + 345 # . . call + 346 e8/call scan-next-byte/disp32 + 347 # registers except ESP may be clobbered at this point + 348 # pop args to scan-next-bytes + 349 # . . discard first 2 args + 350 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 351 # . . restore ed + 352 59/pop-to-ECX + 353 # check that scan-next-byte didn't abort + 354 # . check-ints-equal(ed->value, 0, msg) + 355 # . . push args + 356 68/push "F - test-scan-next-byte-skips-whitespace: unexpected abort"/imm32 + 357 68/push 0/imm32 + 358 # . . push ed->value + 359 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 360 # . . call + 361 e8/call check-ints-equal/disp32 + 362 # . . discard args + 363 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 364 # return if abort + 365 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 366 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace:end/disp8 + 367 # check-ints-equal(EAX, 0x61/a, msg) + 368 # . . push args + 369 68/push "F - test-scan-next-byte-skips-whitespace"/imm32 + 370 68/push 0x61/imm32/a + 371 50/push-EAX + 372 # . . call + 373 e8/call check-ints-equal/disp32 + 374 # . . discard args + 375 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 376 $test-scan-next-byte-skips-whitespace:end: + 377 # . epilog + 378 # don't restore ESP from EBP; manually reclaim locals + 379 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 380 5d/pop-to-EBP + 381 c3/return + 382 + 383 test-scan-next-byte-skips-comment: + 384 # - check that the first byte after a comment (and newline) is returned + 385 # This test uses exit-descriptors. Use EBP for setting up local variables. + 386 55/push-EBP + 387 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 388 # clear all streams + 389 # . clear-stream(_test-stream) + 390 # . . push args + 391 68/push _test-stream/imm32 + 392 # . . call + 393 e8/call clear-stream/disp32 + 394 # . . discard args + 395 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 396 # . clear-stream(_test-buffered-file+4) + 397 # . . push args + 398 b8/copy-to-EAX _test-buffered-file/imm32 + 399 05/add-to-EAX 4/imm32 + 400 50/push-EAX + 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-error-stream) + 406 # . . push args + 407 68/push _test-error-stream/imm32 + 408 # . . call + 409 e8/call clear-stream/disp32 + 410 # . . discard args + 411 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 412 # initialize '_test-stream' to input with leading comment + 413 # . write(_test-stream, comment) + 414 # . . push args + 415 68/push "#x"/imm32 + 416 68/push _test-stream/imm32 + 417 # . . call + 418 e8/call write/disp32 + 419 # . . discard args + 420 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 421 # . write(_test-stream, Newline) + 422 # . . push args + 423 68/push Newline/imm32 + 424 68/push _test-stream/imm32 + 425 # . . call + 426 e8/call write/disp32 + 427 # . . discard args + 428 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 429 # . write(_test-stream, real text) + 430 # . . push args + 431 68/push "ab"/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 'scan-next-byte' below + 438 # . var ed/ECX : 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 . 1/r32/ECX . . # copy ESP to ECX + 441 # . tailor-exit-descriptor(ed, 12) + 442 # . . push args + 443 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 444 51/push-ECX/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 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 450 # . . push args + 451 51/push-ECX/ed + 452 68/push _test-error-stream/imm32 + 453 68/push _test-buffered-file/imm32 + 454 # . . call + 455 e8/call scan-next-byte/disp32 + 456 # registers except ESP may be clobbered at this point + 457 # pop args to scan-next-bytes + 458 # . . discard first 2 args + 459 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 460 # . . restore ed + 461 59/pop-to-ECX + 462 # check that scan-next-byte didn't abort + 463 # . check-ints-equal(ed->value, 0, msg) + 464 # . . push args + 465 68/push "F - test-scan-next-byte-skips-comment: unexpected abort"/imm32 + 466 68/push 0/imm32 + 467 # . . push ed->value + 468 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 # return if abort + 474 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 475 75/jump-if-not-equal $test-scan-next-byte-skips-comment:end/disp8 + 476 # check-ints-equal(EAX, 0x61/a, msg) + 477 # . . push args + 478 68/push "F - test-scan-next-byte-skips-comment"/imm32 + 479 68/push 0x61/imm32/a + 480 50/push-EAX + 481 # . . call + 482 e8/call check-ints-equal/disp32 + 483 # . . discard args + 484 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 485 $test-scan-next-byte-skips-comment:end: + 486 # . epilog + 487 # don't restore ESP from EBP; manually reclaim locals + 488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 489 5d/pop-to-EBP + 490 c3/return + 491 + 492 test-scan-next-byte-skips-comment-and-whitespace: + 493 # - check that the first byte after a comment and any further whitespace is returned + 494 # This test uses exit-descriptors. Use EBP for setting up local variables. + 495 55/push-EBP + 496 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 497 # clear all streams + 498 # . clear-stream(_test-stream) + 499 # . . push args + 500 68/push _test-stream/imm32 + 501 # . . call + 502 e8/call clear-stream/disp32 + 503 # . . discard args + 504 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 505 # . clear-stream(_test-buffered-file+4) + 506 # . . push args + 507 b8/copy-to-EAX _test-buffered-file/imm32 + 508 05/add-to-EAX 4/imm32 + 509 50/push-EAX + 510 # . . call + 511 e8/call clear-stream/disp32 + 512 # . . discard args + 513 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 514 # . clear-stream(_test-error-stream) + 515 # . . push args + 516 68/push _test-error-stream/imm32 + 517 # . . call + 518 e8/call clear-stream/disp32 + 519 # . . discard args + 520 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 521 # initialize '_test-stream' to input with leading comment and more whitespace after newline + 522 # . write(_test-stream, comment) + 523 # . . push args + 524 68/push "#x"/imm32 + 525 68/push _test-stream/imm32 + 526 # . . call + 527 e8/call write/disp32 + 528 # . . discard args + 529 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 530 # . write(_test-stream, Newline) + 531 # . . push args + 532 68/push Newline/imm32 + 533 68/push _test-stream/imm32 + 534 # . . call + 535 e8/call write/disp32 + 536 # . . discard args + 537 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 538 # . write(_test-stream, real text) + 539 # . . push args + 540 68/push " ab"/imm32 + 541 68/push _test-stream/imm32 + 542 # . . call + 543 e8/call write/disp32 + 544 # . . discard args + 545 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 546 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 547 # . var ed/ECX : exit-descriptor + 548 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 549 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 550 # . tailor-exit-descriptor(ed, 12) + 551 # . . push args + 552 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 553 51/push-ECX/ed + 554 # . . call + 555 e8/call tailor-exit-descriptor/disp32 + 556 # . . discard args + 557 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 558 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 559 # . . push args + 560 51/push-ECX/ed + 561 68/push _test-error-stream/imm32 + 562 68/push _test-buffered-file/imm32 + 563 # . . call + 564 e8/call scan-next-byte/disp32 + 565 # registers except ESP may be clobbered at this point + 566 # pop args to scan-next-bytes + 567 # . . discard first 2 args + 568 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 569 # . . restore ed + 570 59/pop-to-ECX + 571 # check that scan-next-byte didn't abort + 572 # . check-ints-equal(ed->value, 0, msg) + 573 # . . push args + 574 68/push "F - test-scan-next-byte-skips-comment-and-whitespace: unexpected abort"/imm32 + 575 68/push 0/imm32 + 576 # . . push ed->value + 577 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 578 # . . call + 579 e8/call check-ints-equal/disp32 + 580 # . . discard args + 581 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 582 # return if abort + 583 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 584 75/jump-if-not-equal $test-scan-next-byte-skips-comment-and-whitespace:end/disp8 + 585 # check-ints-equal(EAX, 0x61/a, msg) + 586 # . . push args + 587 68/push "F - test-scan-next-byte-skips-comment-and-whitespace"/imm32 + 588 68/push 0x61/imm32/a + 589 50/push-EAX + 590 # . . call + 591 e8/call check-ints-equal/disp32 + 592 # . . discard args + 593 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 594 $test-scan-next-byte-skips-comment-and-whitespace:end: + 595 # . epilog + 596 # don't restore ESP from EBP; manually reclaim locals + 597 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 598 5d/pop-to-EBP + 599 c3/return + 600 + 601 test-scan-next-byte-skips-whitespace-and-comment: + 602 # - check that the first byte after any whitespace and comments is returned + 603 # This test uses exit-descriptors. Use EBP for setting up local variables. + 604 55/push-EBP + 605 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 606 # clear all streams + 607 # . clear-stream(_test-stream) + 608 # . . push args + 609 68/push _test-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 # . clear-stream(_test-buffered-file+4) + 615 # . . push args + 616 b8/copy-to-EAX _test-buffered-file/imm32 + 617 05/add-to-EAX 4/imm32 + 618 50/push-EAX + 619 # . . call + 620 e8/call clear-stream/disp32 + 621 # . . discard args + 622 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 623 # . clear-stream(_test-error-stream) + 624 # . . push args + 625 68/push _test-error-stream/imm32 + 626 # . . call + 627 e8/call clear-stream/disp32 + 628 # . . discard args + 629 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 630 # initialize '_test-stream' to input with leading whitespace and comment + 631 # . write(_test-stream, comment) + 632 # . . push args + 633 68/push " #x"/imm32 + 634 68/push _test-stream/imm32 + 635 # . . call + 636 e8/call write/disp32 + 637 # . . discard args + 638 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 639 # . write(_test-stream, Newline) + 640 # . . push args + 641 68/push Newline/imm32 + 642 68/push _test-stream/imm32 + 643 # . . call + 644 e8/call write/disp32 + 645 # . . discard args + 646 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 647 # . write(_test-stream, real text) + 648 # . . push args + 649 68/push "ab"/imm32 + 650 68/push _test-stream/imm32 + 651 # . . call + 652 e8/call write/disp32 + 653 # . . discard args + 654 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 655 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 656 # . var ed/ECX : exit-descriptor + 657 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 658 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 659 # . tailor-exit-descriptor(ed, 12) + 660 # . . push args + 661 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 662 51/push-ECX/ed + 663 # . . call + 664 e8/call tailor-exit-descriptor/disp32 + 665 # . . discard args + 666 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 667 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 668 # . . push args + 669 51/push-ECX/ed + 670 68/push _test-error-stream/imm32 + 671 68/push _test-buffered-file/imm32 + 672 # . . call + 673 e8/call scan-next-byte/disp32 + 674 # registers except ESP may be clobbered at this point + 675 # pop args to scan-next-bytes + 676 # . . discard first 2 args + 677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 678 # . . restore ed + 679 59/pop-to-ECX + 680 # check that scan-next-byte didn't abort + 681 # . check-ints-equal(ed->value, 0, msg) + 682 # . . push args + 683 68/push "F - test-scan-next-byte-skips-whitespace-and-comment: unexpected abort"/imm32 + 684 68/push 0/imm32 + 685 # . . push ed->value + 686 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 687 # . . call + 688 e8/call check-ints-equal/disp32 + 689 # . . discard args + 690 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 691 # return if abort + 692 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 693 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace-and-comment:end/disp8 + 694 # check-ints-equal(EAX, 0x61/a, msg) + 695 # . . push args + 696 68/push "F - test-scan-next-byte-skips-whitespace-and-comment"/imm32 + 697 68/push 0x61/imm32/a + 698 50/push-EAX + 699 # . . call + 700 e8/call check-ints-equal/disp32 + 701 # . . discard args + 702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 703 $test-scan-next-byte-skips-whitespace-and-comment:end: + 704 # . epilog + 705 # don't restore ESP from EBP; manually reclaim locals + 706 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 707 5d/pop-to-EBP + 708 c3/return + 709 + 710 test-scan-next-byte-reads-final-byte: + 711 # - check that the final byte in input is returned + 712 # This test uses exit-descriptors. Use EBP for setting up local variables. + 713 55/push-EBP + 714 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 715 # clear all streams + 716 # . clear-stream(_test-stream) + 717 # . . push args + 718 68/push _test-stream/imm32 + 719 # . . call + 720 e8/call clear-stream/disp32 + 721 # . . discard args + 722 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 723 # . clear-stream(_test-buffered-file+4) + 724 # . . push args + 725 b8/copy-to-EAX _test-buffered-file/imm32 + 726 05/add-to-EAX 4/imm32 + 727 50/push-EAX + 728 # . . call + 729 e8/call clear-stream/disp32 + 730 # . . discard args + 731 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 732 # . clear-stream(_test-error-stream) + 733 # . . push args + 734 68/push _test-error-stream/imm32 + 735 # . . call + 736 e8/call clear-stream/disp32 + 737 # . . discard args + 738 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 739 # initialize '_test-stream' to input with single character + 740 # . write(_test-stream, character) + 741 # . . push args + 742 68/push "a"/imm32 + 743 68/push _test-stream/imm32 + 744 # . . call + 745 e8/call write/disp32 + 746 # . . discard args + 747 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 748 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 749 # . var ed/ECX : exit-descriptor + 750 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 751 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 752 # . tailor-exit-descriptor(ed, 12) + 753 # . . push args + 754 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 755 51/push-ECX/ed + 756 # . . call + 757 e8/call tailor-exit-descriptor/disp32 + 758 # . . discard args + 759 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 760 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 761 # . . push args + 762 51/push-ECX/ed + 763 68/push _test-error-stream/imm32 + 764 68/push _test-buffered-file/imm32 + 765 # . . call + 766 e8/call scan-next-byte/disp32 + 767 # registers except ESP may be clobbered at this point + 768 # pop args to scan-next-bytes + 769 # . . discard first 2 args + 770 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 771 # . . restore ed + 772 59/pop-to-ECX + 773 # check that scan-next-byte didn't abort + 774 # . check-ints-equal(ed->value, 0, msg) + 775 # . . push args + 776 68/push "F - test-scan-next-byte-reads-final-byte: unexpected abort"/imm32 + 777 68/push 0/imm32 + 778 # . . push ed->value + 779 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 780 # . . call + 781 e8/call check-ints-equal/disp32 + 782 # . . discard args + 783 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 784 # return if abort + 785 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 786 75/jump-if-not-equal $test-scan-next-byte-reads-final-byte:end/disp8 + 787 # check-ints-equal(EAX, 0x61/a, msg) + 788 # . . push args + 789 68/push "F - test-scan-next-byte-reads-final-byte"/imm32 + 790 68/push 0x61/imm32/a + 791 50/push-EAX + 792 # . . call + 793 e8/call check-ints-equal/disp32 + 794 # . . discard args + 795 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 796 $test-scan-next-byte-reads-final-byte:end: + 797 # . epilog + 798 # don't restore ESP from EBP; manually reclaim locals + 799 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 800 5d/pop-to-EBP + 801 c3/return + 802 + 803 test-scan-next-byte-handles-eof: + 804 # - check that the right sentinel value is returned when there's no data remaining to be read + 805 # This test uses exit-descriptors. Use EBP for setting up local variables. + 806 55/push-EBP + 807 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 808 # clear all streams + 809 # . clear-stream(_test-stream) + 810 # . . push args + 811 68/push _test-stream/imm32 + 812 # . . call + 813 e8/call clear-stream/disp32 + 814 # . . discard args + 815 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 816 # . clear-stream(_test-buffered-file+4) + 817 # . . push args + 818 b8/copy-to-EAX _test-buffered-file/imm32 + 819 05/add-to-EAX 4/imm32 + 820 50/push-EAX + 821 # . . call + 822 e8/call clear-stream/disp32 + 823 # . . discard args + 824 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 825 # . clear-stream(_test-error-stream) + 826 # . . push args + 827 68/push _test-error-stream/imm32 + 828 # . . call + 829 e8/call clear-stream/disp32 + 830 # . . discard args + 831 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 832 # leave '_test-stream' empty + 833 # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below + 834 # . var ed/ECX : exit-descriptor + 835 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 836 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + 837 # . tailor-exit-descriptor(ed, 12) + 838 # . . push args + 839 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte + 840 51/push-ECX/ed + 841 # . . call + 842 e8/call tailor-exit-descriptor/disp32 + 843 # . . discard args + 844 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 845 # EAX = scan-next-byte(_test-buffered-file, _test-error-stream, ed) + 846 # . . push args + 847 51/push-ECX/ed + 848 68/push _test-error-stream/imm32 + 849 68/push _test-buffered-file/imm32 + 850 # . . call + 851 e8/call scan-next-byte/disp32 + 852 # registers except ESP may be clobbered at this point + 853 # pop args to scan-next-bytes + 854 # . . discard first 2 args + 855 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 856 # . . restore ed + 857 59/pop-to-ECX + 858 # check that scan-next-byte didn't abort + 859 # . check-ints-equal(ed->value, 0, msg) + 860 # . . push args + 861 68/push "F - test-scan-next-byte-handles-eof: unexpected abort"/imm32 + 862 68/push 0/imm32 + 863 # . . push ed->value + 864 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + 865 # . . call + 866 e8/call check-ints-equal/disp32 + 867 # . . discard args + 868 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 869 # return if abort + 870 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 871 75/jump-if-not-equal $test-scan-next-byte-handles-eof:end/disp8 + 872 # check-ints-equal(EAX, 0xffffffff/eof, msg) + 873 # . . push args + 874 68/push "F - test-scan-next-byte-handles-eof"/imm32 + 875 68/push 0xffffffff/imm32/eof + 876 50/push-EAX + 877 # . . call + 878 e8/call check-ints-equal/disp32 + 879 # . . discard args + 880 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 881 $test-scan-next-byte-handles-eof:end: + 882 # . epilog + 883 # don't restore ESP from EBP; manually reclaim locals + 884 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 885 5d/pop-to-EBP + 886 c3/return + 887 + 888 is-hex-lowercase-byte?: # c : byte -> bool/EAX + 889 # . prolog + 890 55/push-EBP + 891 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 892 # . save registers + 893 51/push-ECX + 894 # ECX = c + 895 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX + 896 # return false if c < '0' + 897 b8/copy-to-EAX 0/imm32/false + 898 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x30/imm32 # compare ECX + 899 7c/jump-if-lesser $is-hex-lowercase-byte?:end/disp8 + 900 # return false if c > 'f' + 901 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x66/imm32 # compare ECX + 902 7f/jump-if-greater $is-hex-lowercase-byte?:end/disp8 + 903 # return true if c <= '9' + 904 b8/copy-to-EAX 1/imm32/true + 905 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x39/imm32 # compare ECX + 906 7e/jump-if-lesser-or-equal $is-hex-lowercase-byte?:end/disp8 + 907 # return true if c >= 'a' + 908 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x61/imm32 # compare ECX + 909 7d/jump-if-greater-or-equal $is-hex-lowercase-byte?:end/disp8 + 910 # otherwise return false + 911 b8/copy-to-EAX 0/imm32/false + 912 $is-hex-lowercase-byte?:end: + 913 # . restore registers + 914 59/pop-to-ECX + 915 # . epilog + 916 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 917 5d/pop-to-EBP + 918 c3/return + 919 + 920 test-hex-below-0: + 921 # is-hex-lowercase-byte?(0x2f) 922 # . . push args - 923 68/push 0x66/imm32 + 923 68/push 0x2f/imm32 924 # . . call 925 e8/call is-hex-lowercase-byte?/disp32 926 # . . discard args 927 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 928 # check-ints-equal(EAX, 1, msg) + 928 # check-ints-equal(EAX, 0, msg) 929 # . . push args - 930 68/push "F - test-hex-at-f"/imm32 - 931 68/push 1/imm32/true + 930 68/push "F - test-hex-below-0"/imm32 + 931 68/push 0/imm32/false 932 50/push-EAX 933 # . . call 934 e8/call check-ints-equal/disp32 @@ -1002,148 +1002,237 @@ if ('onhashchange' in window) { 936 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 937 c3/return 938 - 939 test-hex-above-f: - 940 # is-hex-lowercase-byte?(0x67) + 939 test-hex-0-to-9: + 940 # is-hex-lowercase-byte?(0x30) 941 # . . push args - 942 68/push 0x67/imm32 + 942 68/push 0x30/imm32 943 # . . call 944 e8/call is-hex-lowercase-byte?/disp32 945 # . . discard args 946 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 947 # check-ints-equal(EAX, 0, msg) + 947 # check-ints-equal(EAX, 1, msg) 948 # . . push args - 949 68/push "F - test-hex-above-f"/imm32 - 950 68/push 0/imm32/false + 949 68/push "F - test-hex-at-0"/imm32 + 950 68/push 1/imm32/true 951 50/push-EAX 952 # . . call 953 e8/call check-ints-equal/disp32 954 # . . discard args 955 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 956 c3/return - 957 - 958 skip-until-newline: # in : (address buffered-file) -> <void> - 959 # pseudocode: - 960 # push EAX - 961 # repeatedly: - 962 # EAX = read-byte(in) - 963 # if EAX == 0xffffffff break - 964 # if EAX == 0x0a break - 965 # pop EAX - 966 # . prolog - 967 55/push-EBP - 968 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 969 # . save registers - 970 50/push-EAX - 971 $skip-until-newline:loop: - 972 # . EAX = read-byte(in) - 973 # . . push args - 974 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 975 # . . call - 976 e8/call read-byte/disp32 - 977 # . . discard args - 978 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 979 # . if EAX == 0xffffffff break - 980 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX - 981 74/jump-if-equal $skip-until-newline:end/disp8 - 982 $aa: - 983 # . if EAX != 0xa/newline loop - 984 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX - 985 75/jump-if-not-equal $skip-until-newline:loop/disp8 - 986 $skip-until-newline:end: - 987 # . restore registers - 988 58/pop-to-EAX - 989 # . epilog - 990 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 991 5d/pop-to-EBP - 992 c3/return - 993 - 994 test-skip-until-newline: - 995 # - check that the read pointer points after the newline - 996 # setup - 997 # . clear-stream(_test-stream) - 998 # . . push args - 999 68/push _test-stream/imm32 -1000 # . . call -1001 e8/call clear-stream/disp32 -1002 # . . discard args -1003 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1004 # . clear-stream(_test-buffered-file+4) -1005 # . . push args -1006 b8/copy-to-EAX _test-buffered-file/imm32 -1007 05/add-to-EAX 4/imm32 -1008 50/push-EAX -1009 # . . call -1010 e8/call clear-stream/disp32 -1011 # . . discard args -1012 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1013 # initialize '_test-stream' to "abc\nde" -1014 # . write(_test-stream, "abc") -1015 # . . push args -1016 68/push "abc"/imm32 -1017 68/push _test-stream/imm32 -1018 # . . call -1019 e8/call write/disp32 -1020 # . . discard args -1021 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1022 # . write(_test-stream, Newline) -1023 # . . push args -1024 68/push Newline/imm32 -1025 68/push _test-stream/imm32 -1026 # . . call -1027 e8/call write/disp32 -1028 # . . discard args -1029 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1030 # . write(_test-stream, "de") -1031 # . . push args -1032 68/push "de"/imm32 -1033 68/push _test-stream/imm32 -1034 # . . call -1035 e8/call write/disp32 -1036 # . . discard args -1037 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1038 # skip-until-newline(_test-buffered-file) -1039 # . . push args -1040 68/push _test-buffered-file/imm32 + 956 # is-hex-lowercase-byte?(0x39) + 957 # . . push args + 958 68/push 0x39/imm32 + 959 # . . call + 960 e8/call is-hex-lowercase-byte?/disp32 + 961 # . . discard args + 962 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 963 # check-ints-equal(EAX, 1, msg) + 964 # . . push args + 965 68/push "F - test-hex-at-9"/imm32 + 966 68/push 1/imm32/true + 967 50/push-EAX + 968 # . . call + 969 e8/call check-ints-equal/disp32 + 970 # . . discard args + 971 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 972 c3/return + 973 + 974 test-hex-above-9-to-a: + 975 # is-hex-lowercase-byte?(0x3a) + 976 # . . push args + 977 68/push 0x3a/imm32 + 978 # . . call + 979 e8/call is-hex-lowercase-byte?/disp32 + 980 # . . discard args + 981 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 982 # check-ints-equal(EAX, 0, msg) + 983 # . . push args + 984 68/push "F - test-hex-above-9-to-a"/imm32 + 985 68/push 0/imm32/false + 986 50/push-EAX + 987 # . . call + 988 e8/call check-ints-equal/disp32 + 989 # . . discard args + 990 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 991 c3/return + 992 + 993 test-hex-a-to-f: + 994 # is-hex-lowercase-byte?(0x61) + 995 # . . push args + 996 68/push 0x61/imm32 + 997 # . . call + 998 e8/call is-hex-lowercase-byte?/disp32 + 999 # . . discard args +1000 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1001 # check-ints-equal(EAX, 1, msg) +1002 # . . push args +1003 68/push "F - test-hex-at-a"/imm32 +1004 68/push 1/imm32/true +1005 50/push-EAX +1006 # . . call +1007 e8/call check-ints-equal/disp32 +1008 # . . discard args +1009 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1010 # is-hex-lowercase-byte?(0x66) +1011 # . . push args +1012 68/push 0x66/imm32 +1013 # . . call +1014 e8/call is-hex-lowercase-byte?/disp32 +1015 # . . discard args +1016 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1017 # check-ints-equal(EAX, 1, msg) +1018 # . . push args +1019 68/push "F - test-hex-at-f"/imm32 +1020 68/push 1/imm32/true +1021 50/push-EAX +1022 # . . call +1023 e8/call check-ints-equal/disp32 +1024 # . . discard args +1025 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1026 c3/return +1027 +1028 test-hex-above-f: +1029 # is-hex-lowercase-byte?(0x67) +1030 # . . push args +1031 68/push 0x67/imm32 +1032 # . . call +1033 e8/call is-hex-lowercase-byte?/disp32 +1034 # . . discard args +1035 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1036 # check-ints-equal(EAX, 0, msg) +1037 # . . push args +1038 68/push "F - test-hex-above-f"/imm32 +1039 68/push 0/imm32/false +1040 50/push-EAX 1041 # . . call -1042 e8/call skip-until-newline/disp32 +1042 e8/call check-ints-equal/disp32 1043 # . . discard args -1044 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1045 # check-ints-equal(_test-buffered-file->read, 4, msg) -1046 # . . push args -1047 68/push "F - test-skip-until-newline"/imm32 -1048 68/push 4/imm32 -1049 b8/copy-to-EAX _test-buffered-file/imm32 -1050 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) -1051 # . . call -1052 e8/call check-ints-equal/disp32 -1053 # . . discard args -1054 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1055 # . end -1056 c3/return -1057 -1058 == data -1059 -1060 _test-output-stream: -1061 # current write index -1062 00 00 00 00 -1063 # current read index -1064 00 00 00 00 -1065 # length (= 8) -1066 08 00 00 00 -1067 # data -1068 00 00 00 00 00 00 00 00 # 8 bytes -1069 -1070 _test-error-stream: -1071 # current write index -1072 00 00 00 00 -1073 # current read index -1074 00 00 00 00 -1075 # length (= 8) -1076 08 00 00 00 -1077 # data -1078 00 00 00 00 00 00 00 00 # 8 bytes -1079 -1080 # . . vim:nowrap:textwidth=0 +1044 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1045 c3/return +1046 +1047 skip-until-newline: # in : (address buffered-file) -> <void> +1048 # pseudocode: +1049 # push EAX +1050 # repeatedly: +1051 # EAX = read-byte(in) +1052 # if EAX == 0xffffffff break +1053 # if EAX == 0x0a break +1054 # pop EAX +1055 # . prolog +1056 55/push-EBP +1057 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1058 # . save registers +1059 50/push-EAX +1060 $skip-until-newline:loop: +1061 # . EAX = read-byte(in) +1062 # . . push args +1063 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) +1064 # . . call +1065 e8/call read-byte/disp32 +1066 # . . discard args +1067 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1068 # . if EAX == 0xffffffff break +1069 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX +1070 74/jump-if-equal $skip-until-newline:end/disp8 +1071 $aa: +1072 # . if EAX != 0xa/newline loop +1073 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX +1074 75/jump-if-not-equal $skip-until-newline:loop/disp8 +1075 $skip-until-newline:end: +1076 # . restore registers +1077 58/pop-to-EAX +1078 # . epilog +1079 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1080 5d/pop-to-EBP +1081 c3/return +1082 +1083 test-skip-until-newline: +1084 # - check that the read pointer points after the newline +1085 # setup +1086 # . clear-stream(_test-stream) +1087 # . . push args +1088 68/push _test-stream/imm32 +1089 # . . call +1090 e8/call clear-stream/disp32 +1091 # . . discard args +1092 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1093 # . clear-stream(_test-buffered-file+4) +1094 # . . push args +1095 b8/copy-to-EAX _test-buffered-file/imm32 +1096 05/add-to-EAX 4/imm32 +1097 50/push-EAX +1098 # . . call +1099 e8/call clear-stream/disp32 +1100 # . . discard args +1101 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1102 # initialize '_test-stream' to "abc\nde" +1103 # . write(_test-stream, "abc") +1104 # . . push args +1105 68/push "abc"/imm32 +1106 68/push _test-stream/imm32 +1107 # . . call +1108 e8/call write/disp32 +1109 # . . discard args +1110 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1111 # . write(_test-stream, Newline) +1112 # . . push args +1113 68/push Newline/imm32 +1114 68/push _test-stream/imm32 +1115 # . . call +1116 e8/call write/disp32 +1117 # . . discard args +1118 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1119 # . write(_test-stream, "de") +1120 # . . push args +1121 68/push "de"/imm32 +1122 68/push _test-stream/imm32 +1123 # . . call +1124 e8/call write/disp32 +1125 # . . discard args +1126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1127 # skip-until-newline(_test-buffered-file) +1128 # . . push args +1129 68/push _test-buffered-file/imm32 +1130 # . . call +1131 e8/call skip-until-newline/disp32 +1132 # . . discard args +1133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1134 # check-ints-equal(_test-buffered-file->read, 4, msg) +1135 # . . push args +1136 68/push "F - test-skip-until-newline"/imm32 +1137 68/push 4/imm32 +1138 b8/copy-to-EAX _test-buffered-file/imm32 +1139 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) +1140 # . . call +1141 e8/call check-ints-equal/disp32 +1142 # . . discard args +1143 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1144 # . end +1145 c3/return +1146 +1147 == data +1148 +1149 _test-output-stream: +1150 # current write index +1151 00 00 00 00 +1152 # current read index +1153 00 00 00 00 +1154 # length (= 8) +1155 08 00 00 00 +1156 # data +1157 00 00 00 00 00 00 00 00 # 8 bytes +1158 +1159 _test-error-stream: +1160 # current write index +1161 00 00 00 00 +1162 # current read index +1163 00 00 00 00 +1164 # length (= 8) +1165 08 00 00 00 +1166 # data +1167 00 00 00 00 00 00 00 00 # 8 bytes +1168 +1169 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0