From 52daf0722f7f4ad9d3f29e3cbbbaddde066f49f3 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 20 May 2019 01:44:06 -0700 Subject: 5211 Update syntax-highlighted renderings after a _long_ time. --- html/subx/apps/assort.subx.html | 2314 +++++++++++++++++++-------------------- 1 file changed, 1153 insertions(+), 1161 deletions(-) (limited to 'html/subx/apps/assort.subx.html') diff --git a/html/subx/apps/assort.subx.html b/html/subx/apps/assort.subx.html index 0dfd5fa9..62fd3896 100644 --- a/html/subx/apps/assort.subx.html +++ b/html/subx/apps/assort.subx.html @@ -87,1168 +87,1160 @@ if ('onhashchange' in window) { 23 # . op subop mod rm32 base index scale r32 24 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 25 - 26 Entry: # run tests if necessary, convert stdin if not - 27 - 28 # for debugging: run a single test - 29 #? e8/call test-convert/disp32 - 30 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 31 #? eb/jump $main:end/disp8 - 32 - 33 # . prolog - 34 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 35 # - if argc > 1 and argv[1] == "test", then return run_tests() - 36 # . argc > 1 - 37 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP - 38 7e/jump-if-lesser-or-equal $run-main/disp8 - 39 # . argv[1] == "test" - 40 # . . push args - 41 68/push "test"/imm32 - 42 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 43 # . . call - 44 e8/call kernel-string-equal?/disp32 - 45 # . . discard args - 46 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 47 # . check result - 48 3d/compare-EAX-and 1/imm32 - 49 75/jump-if-not-equal $run-main/disp8 - 50 # . run-tests() - 51 e8/call run-tests/disp32 - 52 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 53 eb/jump $main:end/disp8 - 54 $run-main: - 55 # - otherwise convert stdin - 56 # var ed/EAX : exit-descriptor - 57 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 58 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - 59 # configure ed to really exit() - 60 # . ed->target = 0 - 61 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - 62 # return convert(Stdin, 1/stdout, 2/stderr, ed) - 63 # . . push args - 64 50/push-EAX/ed - 65 68/push Stderr/imm32 - 66 68/push Stdout/imm32 - 67 68/push Stdin/imm32 - 68 # . . call - 69 e8/call convert/disp32 - 70 # . . discard args - 71 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - 72 # . syscall(exit, 0) - 73 bb/copy-to-EBX 0/imm32 - 74 $main:end: - 75 b8/copy-to-EAX 1/imm32/exit - 76 cd/syscall 0x80/imm8 - 77 - 78 # data structure: - 79 # row: pair of (address array byte) and (address stream byte) - 80 # table: (address stream row) - 81 - 82 convert: # in : (address buffered-file), out : (address buffered-file) -> <void> - 83 # pseudocode: - 84 # var table : (address stream) = new-stream(10 rows, 8 bytes each) - 85 # read-segments(in, table) - 86 # write-segments(out, table) - 87 # - 88 # . prolog - 89 55/push-EBP - 90 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 91 # . save registers - 92 51/push-ECX - 93 # var table/ECX : (address stream byte) = stream(10 * 8) - 94 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x50/imm32 # subtract from ESP - 95 68/push 0x50/imm32/length - 96 68/push 0/imm32/read - 97 68/push 0/imm32/write - 98 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 99 # clear-stream(table) - 100 # . . push args - 101 51/push-ECX - 102 # . . call - 103 e8/call clear-stream/disp32 - 104 # . . discard args - 105 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 106 $convert:read: - 107 # read-segments(in, table) - 108 # . . push args - 109 51/push-ECX - 110 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 111 # . . call - 112 e8/call read-segments/disp32 - 113 # . . discard args - 114 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 115 $convert:write: - 116 # write-segments(out, table) - 117 # . . push args - 118 51/push-ECX - 119 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 120 # . . call - 121 e8/call write-segments/disp32 - 122 # . . discard args - 123 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 124 $convert:end: - 125 # . reclaim locals - 126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x5c/imm32 # add to ESP - 127 # . restore registers - 128 59/pop-to-ECX - 129 # . epilog - 130 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 131 5d/pop-to-EBP - 132 c3/return - 133 - 134 test-convert: - 135 # . prolog - 136 55/push-EBP - 137 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 138 # setup - 139 # . clear-stream(_test-input-stream) - 140 # . . push args - 141 68/push _test-input-stream/imm32 - 142 # . . call - 143 e8/call clear-stream/disp32 - 144 # . . discard args - 145 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 146 # . clear-stream(_test-input-buffered-file+4) - 147 # . . push args - 148 b8/copy-to-EAX _test-input-buffered-file/imm32 - 149 05/add-to-EAX 4/imm32 - 150 50/push-EAX - 151 # . . call - 152 e8/call clear-stream/disp32 - 153 # . . discard args - 154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 155 # . clear-stream(_test-output-stream) - 156 # . . push args - 157 68/push _test-output-stream/imm32 - 158 # . . call - 159 e8/call clear-stream/disp32 - 160 # . . discard args - 161 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 162 # . clear-stream(_test-output-buffered-file+4) - 163 # . . push args - 164 b8/copy-to-EAX _test-output-buffered-file/imm32 - 165 05/add-to-EAX 4/imm32 - 166 50/push-EAX - 167 # . . call - 168 e8/call clear-stream/disp32 - 169 # . . discard args - 170 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 171 # initialize input (meta comments in parens) - 172 # # comment 1 - 173 # # comment 2 indented - 174 # == code (new segment) - 175 # # comment 3 inside a segment - 176 # 1 - 177 # (empty line) - 178 # 2 3 # comment 4 inline with other contents - 179 # == data (new segment) - 180 # 4 5/imm32 - 181 # == code (existing segment but non-contiguous with previous iteration) - 182 # 6 7 - 183 # 8 9 (multiple lines) - 184 # == code (existing segment contiguous with previous iteration) - 185 # 10 11 - 186 # . write(_test-input-stream, "# comment 1\n") - 187 # . . push args - 188 68/push "# comment 1\n"/imm32 - 189 68/push _test-input-stream/imm32 - 190 # . . call - 191 e8/call write/disp32 - 192 # . . discard args - 193 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 194 # . write(_test-input-stream, " # comment 2 indented\n") - 195 # . . push args - 196 68/push " # comment 2 indented\n"/imm32 - 197 68/push _test-input-stream/imm32 - 198 # . . call - 199 e8/call write/disp32 - 200 # . . discard args - 201 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 202 # . write(_test-input-stream, "== code\n") - 203 # . . push args - 204 68/push "== code\n"/imm32 - 205 68/push _test-input-stream/imm32 - 206 # . . call - 207 e8/call write/disp32 - 208 # . . discard args - 209 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 210 # . write(_test-input-stream, "# comment 3 inside a segment\n") - 211 # . . push args - 212 68/push "# comment 3 inside a segment\n"/imm32 - 213 68/push _test-input-stream/imm32 - 214 # . . call - 215 e8/call write/disp32 - 216 # . . discard args - 217 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 218 # . write(_test-input-stream, "1\n") - 219 # . . push args - 220 68/push "1\n"/imm32 - 221 68/push _test-input-stream/imm32 - 222 # . . call - 223 e8/call write/disp32 - 224 # . . discard args - 225 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 226 # . write(_test-input-stream, "\n") # empty line - 227 # . . push args - 228 68/push "\n"/imm32 - 229 68/push _test-input-stream/imm32 - 230 # . . call - 231 e8/call write/disp32 - 232 # . . discard args - 233 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 234 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") - 235 # . . push args - 236 68/push "2 3 # comment 4 inline with other contents\n"/imm32 - 237 68/push _test-input-stream/imm32 - 238 # . . call - 239 e8/call write/disp32 - 240 # . . discard args - 241 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 242 # . write(_test-input-stream, "== data\n") - 243 # . . push args - 244 68/push "== data\n"/imm32 - 245 68/push _test-input-stream/imm32 - 246 # . . call - 247 e8/call write/disp32 - 248 # . . discard args - 249 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 250 # . write(_test-input-stream, "4 5/imm32\n") - 251 # . . push args - 252 68/push "4 5/imm32\n"/imm32 - 253 68/push _test-input-stream/imm32 - 254 # . . call - 255 e8/call write/disp32 - 256 # . . discard args - 257 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 258 # . write(_test-input-stream, "== code\n") - 259 # . . push args - 260 68/push "== code\n"/imm32 - 261 68/push _test-input-stream/imm32 - 262 # . . call - 263 e8/call write/disp32 - 264 # . . discard args - 265 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 266 # . write(_test-input-stream, "6 7\n") - 267 # . . push args - 268 68/push "6 7\n"/imm32 - 269 68/push _test-input-stream/imm32 - 270 # . . call - 271 e8/call write/disp32 - 272 # . . discard args - 273 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 274 # . write(_test-input-stream, "8 9\n") - 275 # . . push args - 276 68/push "8 9\n"/imm32 - 277 68/push _test-input-stream/imm32 - 278 # . . call - 279 e8/call write/disp32 - 280 # . . discard args - 281 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 282 # . write(_test-input-stream, "== code\n") - 283 # . . push args - 284 68/push "== code\n"/imm32 - 285 68/push _test-input-stream/imm32 - 286 # . . call - 287 e8/call write/disp32 - 288 # . . discard args - 289 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 290 # . write(_test-input-stream, "10 11\n") - 291 # . . push args - 292 68/push "10 11\n"/imm32 - 293 68/push _test-input-stream/imm32 - 294 # . . call - 295 e8/call write/disp32 - 296 # . . discard args - 297 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 298 # convert(_test-input-buffered-file, _test-output-buffered-file) - 299 # . . push args - 300 68/push _test-output-buffered-file/imm32 - 301 68/push _test-input-buffered-file/imm32 - 302 # . . call - 303 e8/call convert/disp32 - 304 # . . discard args - 305 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 306 # check output - 307 # == code - 308 # 1 - 309 # 2 3 # comment 4 inline with other contents - 310 # 6 7 - 311 # 8 9 - 312 # 10 11 - 313 # == data - 314 # 4 5/imm32 - 315 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- - 341 # . flush(_test-output-buffered-file) - 342 # . . push args - 343 68/push _test-output-buffered-file/imm32 - 344 # . . call - 345 e8/call flush/disp32 - 346 # . . discard args - 347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 348 # . check-next-stream-line-equal(_test-output-stream, "== code", msg) - 349 # . . push args - 350 68/push "F - test-convert/0"/imm32 - 351 68/push "== code"/imm32 - 352 68/push _test-output-stream/imm32 - 353 # . . call - 354 e8/call check-next-stream-line-equal/disp32 - 355 # . . discard args - 356 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 357 # . check-next-stream-line-equal(_test-output-stream, "1", msg) - 358 # . . push args - 359 68/push "F - test-convert/1"/imm32 - 360 68/push "1"/imm32 - 361 68/push _test-output-stream/imm32 - 362 # . . call - 363 e8/call check-next-stream-line-equal/disp32 - 364 # . . discard args - 365 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 366 # . check-next-stream-line-equal(_test-output-stream, "2 3 # comment 4 inline with other contents", msg) - 367 # . . push args - 368 68/push "F - test-convert/2"/imm32 - 369 68/push "2 3 # comment 4 inline with other contents"/imm32 - 370 68/push _test-output-stream/imm32 - 371 # . . call - 372 e8/call check-next-stream-line-equal/disp32 - 373 # . . discard args - 374 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 375 # . check-next-stream-line-equal(_test-output-stream, "6 7", msg) - 376 # . . push args - 377 68/push "F - test-convert/3"/imm32 - 378 68/push "6 7"/imm32 - 379 68/push _test-output-stream/imm32 - 380 # . . call - 381 e8/call check-next-stream-line-equal/disp32 - 382 # . . discard args - 383 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 384 # . check-next-stream-line-equal(_test-output-stream, "8 9", msg) - 385 # . . push args - 386 68/push "F - test-convert/4"/imm32 - 387 68/push "8 9"/imm32 - 388 68/push _test-output-stream/imm32 - 389 # . . call - 390 e8/call check-next-stream-line-equal/disp32 - 391 # . . discard args - 392 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 393 # . check-next-stream-line-equal(_test-output-stream, "10 11", msg) - 394 # . . push args - 395 68/push "F - test-convert/5"/imm32 - 396 68/push "10 11"/imm32 - 397 68/push _test-output-stream/imm32 - 398 # . . call - 399 e8/call check-next-stream-line-equal/disp32 - 400 # . . discard args - 401 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 402 # . check-next-stream-line-equal(_test-output-stream, "== data", msg) - 403 # . . push args - 404 68/push "F - test-convert/6"/imm32 - 405 68/push "== data"/imm32 - 406 68/push _test-output-stream/imm32 - 407 # . . call - 408 e8/call check-next-stream-line-equal/disp32 - 409 # . . discard args - 410 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 411 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32", msg) - 412 # . . push args - 413 68/push "F - test-convert/7"/imm32 - 414 68/push "4 5/imm32"/imm32 - 415 68/push _test-output-stream/imm32 - 416 # . . call - 417 e8/call check-next-stream-line-equal/disp32 - 418 # . . discard args - 419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 420 # . epilog - 421 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 422 5d/pop-to-EBP - 423 c3/return - 424 - 425 read-segments: # in : (address buffered-file), table : (address stream row) - 426 # pseudocode: - 427 # var curr-segment = null - 428 # var line = new-stream(512, 1) - 429 # while true - 430 # clear-stream(line) - 431 # read-line(in, line) - 432 # if (line->write == 0) break # end of file - 433 # var word-slice = next-word(line) - 434 # if slice-empty?(word-slice) # whitespace - 435 # continue - 436 # if slice-starts-with?(word-slice, "#") # comment - 437 # continue - 438 # if slice-equal?(word-slice, "==") - 439 # var segment-name = next-word(line) - 440 # curr-segment = get-or-insert-segment(table, segment-name, Segment-size) - 441 # else - 442 # rewind-stream(line) - 443 # write-stream(curr-segment, line) # abort if curr-segment overflows - 444 # - 445 # word-slice and segment-name are both slices with disjoint lifetimes, so - 446 # we'll use the same address for them. - 447 # - 448 # registers: - 449 # line: ECX - 450 # word-slice and segment-name: EDX - 451 # segment-name and curr-segment: EBX - 452 # word-slice->start: ESI - 453 # temporary: EAX - 454 # - 455 # . prolog - 456 55/push-EBP - 457 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 458 # . save registers - 459 50/push-EAX - 460 51/push-ECX - 461 52/push-EDX - 462 53/push-EBX - 463 56/push-ESI - 464 # var line/ECX : (address stream byte) = stream(512) - 465 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 466 68/push 0x200/imm32/length - 467 68/push 0/imm32/read - 468 68/push 0/imm32/write - 469 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 470 # var word-slice/EDX = {0, 0} - 471 68/push 0/imm32/end - 472 68/push 0/imm32/curr - 473 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 474 $read-segments:loop: - 475 # clear-stream(line) - 476 # . . push args - 477 51/push-ECX - 478 # . . call - 479 e8/call clear-stream/disp32 - 480 # . . discard args - 481 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 482 # read-line(in, line) - 483 # . . push args - 484 51/push-ECX - 485 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 486 # . . call - 487 e8/call read-line/disp32 - 488 # . . discard args - 489 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 490 $read-segments:check0: - 491 # if (line->write == 0) break - 492 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 493 0f 84/jump-if-equal $read-segments:break/disp32 - 494 +-- 26 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- - 520 # next-word(line, word-slice) - 521 # . . push args - 522 52/push-EDX - 523 51/push-ECX - 524 # . . call - 525 e8/call next-word/disp32 - 526 # . . discard args - 527 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 528 $read-segments:check1: - 529 # if (slice-empty?(word-slice)) continue - 530 # . EAX = slice-empty?(word-slice) - 531 # . . push args - 532 52/push-EDX - 533 # . . call - 534 e8/call slice-empty?/disp32 - 535 # . . discard args - 536 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 537 # . if (EAX != 0) continue - 538 3d/compare-EAX-and 0/imm32 - 539 0f 85/jump-if-not-equal $read-segments:loop/disp32 - 540 $read-segments:check-for-comment: - 541 # if (slice-starts-with?(word-slice, "#")) continue - 542 # . start/ESI = word-slice->start - 543 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *ECX to ESI - 544 # . c/EAX = *start - 545 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 546 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL - 547 # . if (EAX == '#') continue - 548 3d/compare-EAX-and 0x23/imm32/hash - 549 0f 84/jump-if-equal $read-segments:loop/disp32 - 550 $read-segments:check-for-segment-header: - 551 +-- 42 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- - 593 # if slice-equal?(word-slice, "==") - 594 # segment-name = next-word(line) - 595 # curr-segment = get-or-insert(table, segment-name) - 596 # . EAX = slice-equal?(word-slice, "==") - 597 # . . push args - 598 68/push "=="/imm32 - 599 52/push-EDX - 600 # . . call - 601 e8/call slice-equal?/disp32 - 602 # . . discard args - 603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 604 # . if (EAX == 0) goto check3 - 605 3d/compare-EAX-and 0/imm32 - 606 0f 84/jump-if-equal $read-segments:regular-line/disp32 - 607 # . next-word(line, segment-name) - 608 # . . push args - 609 52/push-EDX - 610 51/push-ECX - 611 # . . call - 612 e8/call next-word/disp32 - 613 # . . discard args - 614 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 615 +-- 42 lines: #? # dump segment name --------------------------------------------------------------------------------------------------------------------- - 657 # . EAX = get-or-insert-segment(table, segment-name, Segment-size) - 658 # . . push args - 659 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size - 660 52/push-EDX - 661 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 662 # . . call - 663 e8/call get-or-insert-segment/disp32 - 664 # . . discard args - 665 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 666 # . curr-segment = EAX - 667 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - 668 # . continue - 669 e9/jump $read-segments:loop/disp32 - 670 $read-segments:regular-line: - 671 # rewind-stream(line) - 672 # . . push args - 673 51/push-ECX - 674 # . . call - 675 e8/call rewind-stream/disp32 - 676 # . . discard args - 677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 678 # write-stream(curr-segment, line) + 26 Entry: + 27 # initialize heap + 28 # . Heap = new-segment(64KB) + 29 # . . push args + 30 68/push Heap/imm32 + 31 68/push 0x10000/imm32/64KB + 32 # . . call + 33 e8/call new-segment/disp32 + 34 # . . discard args + 35 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 36 + 37 # for debugging: run a single test + 38 #? e8/call test-convert/disp32 + 39 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 40 #? eb/jump $main:end/disp8 + 41 + 42 # run tests if necessary, convert stdin if not + 43 # . prolog + 44 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 45 # - if argc > 1 and argv[1] == "test", then return run_tests() + 46 # . argc > 1 + 47 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP + 48 7e/jump-if-lesser-or-equal $run-main/disp8 + 49 # . argv[1] == "test" + 50 # . . push args + 51 68/push "test"/imm32 + 52 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 53 # . . call + 54 e8/call kernel-string-equal?/disp32 + 55 # . . discard args + 56 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 57 # . check result + 58 3d/compare-EAX-and 1/imm32 + 59 75/jump-if-not-equal $run-main/disp8 + 60 # . run-tests() + 61 e8/call run-tests/disp32 + 62 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 63 eb/jump $main:end/disp8 + 64 $run-main: + 65 # - otherwise convert stdin + 66 # var ed/EAX : exit-descriptor + 67 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 68 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX + 69 # configure ed to really exit() + 70 # . ed->target = 0 + 71 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX + 72 # return convert(Stdin, 1/stdout, 2/stderr, ed) + 73 # . . push args + 74 50/push-EAX/ed + 75 68/push Stderr/imm32 + 76 68/push Stdout/imm32 + 77 68/push Stdin/imm32 + 78 # . . call + 79 e8/call convert/disp32 + 80 # . . discard args + 81 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 82 # . syscall(exit, 0) + 83 bb/copy-to-EBX 0/imm32 + 84 $main:end: + 85 b8/copy-to-EAX 1/imm32/exit + 86 cd/syscall 0x80/imm8 + 87 + 88 # data structure: + 89 # row: pair of (address array byte) and (address stream byte) + 90 # table: (address stream row) + 91 + 92 convert: # in : (address buffered-file), out : (address buffered-file) -> <void> + 93 # pseudocode: + 94 # var table : (address stream) = new-stream(10 rows, 8 bytes each) + 95 # read-segments(in, table) + 96 # write-segments(out, table) + 97 # + 98 # . prolog + 99 55/push-EBP + 100 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 101 # . save registers + 102 51/push-ECX + 103 # var table/ECX : (address stream byte) = stream(10 * 8) + 104 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x50/imm32 # subtract from ESP + 105 68/push 0x50/imm32/length + 106 68/push 0/imm32/read + 107 68/push 0/imm32/write + 108 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 109 # clear-stream(table) + 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 $convert:read: + 117 # read-segments(in, table) + 118 # . . push args + 119 51/push-ECX + 120 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 121 # . . call + 122 e8/call read-segments/disp32 + 123 # . . discard args + 124 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 125 $convert:write: + 126 # write-segments(out, table) + 127 # . . push args + 128 51/push-ECX + 129 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 130 # . . call + 131 e8/call write-segments/disp32 + 132 # . . discard args + 133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 134 $convert:end: + 135 # . reclaim locals + 136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x5c/imm32 # add to ESP + 137 # . restore registers + 138 59/pop-to-ECX + 139 # . epilog + 140 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 141 5d/pop-to-EBP + 142 c3/return + 143 + 144 test-convert: + 145 # . prolog + 146 55/push-EBP + 147 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 148 # setup + 149 # . clear-stream(_test-input-stream) + 150 # . . push args + 151 68/push _test-input-stream/imm32 + 152 # . . call + 153 e8/call clear-stream/disp32 + 154 # . . discard args + 155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 156 # . clear-stream(_test-input-buffered-file+4) + 157 # . . push args + 158 b8/copy-to-EAX _test-input-buffered-file/imm32 + 159 05/add-to-EAX 4/imm32 + 160 50/push-EAX + 161 # . . call + 162 e8/call clear-stream/disp32 + 163 # . . discard args + 164 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 165 # . clear-stream(_test-output-stream) + 166 # . . push args + 167 68/push _test-output-stream/imm32 + 168 # . . call + 169 e8/call clear-stream/disp32 + 170 # . . discard args + 171 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 172 # . clear-stream(_test-output-buffered-file+4) + 173 # . . push args + 174 b8/copy-to-EAX _test-output-buffered-file/imm32 + 175 05/add-to-EAX 4/imm32 + 176 50/push-EAX + 177 # . . call + 178 e8/call clear-stream/disp32 + 179 # . . discard args + 180 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 181 # initialize input (meta comments in parens) + 182 # # comment 1 + 183 # # comment 2 indented + 184 # == code 0x09000000 (new segment) + 185 # # comment 3 inside a segment + 186 # 1 + 187 # (empty line) + 188 # 2 3 # comment 4 inline with other contents + 189 # == data 0x0a000000 (new segment) + 190 # 4 5/imm32 + 191 # == code (existing segment but non-contiguous with previous iteration) + 192 # 6 7 + 193 # 8 9 (multiple lines) + 194 # == code (existing segment contiguous with previous iteration) + 195 # 10 11 + 196 # . write(_test-input-stream, "# comment 1\n") + 197 # . . push args + 198 68/push "# comment 1\n"/imm32 + 199 68/push _test-input-stream/imm32 + 200 # . . call + 201 e8/call write/disp32 + 202 # . . discard args + 203 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 204 # . write(_test-input-stream, " # comment 2 indented\n") + 205 # . . push args + 206 68/push " # comment 2 indented\n"/imm32 + 207 68/push _test-input-stream/imm32 + 208 # . . call + 209 e8/call write/disp32 + 210 # . . discard args + 211 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 212 # . write(_test-input-stream, "== code 0x09000000\n") + 213 # . . push args + 214 68/push "== code 0x09000000\n"/imm32 + 215 68/push _test-input-stream/imm32 + 216 # . . call + 217 e8/call write/disp32 + 218 # . . discard args + 219 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 220 # . write(_test-input-stream, "# comment 3 inside a segment\n") + 221 # . . push args + 222 68/push "# comment 3 inside a segment\n"/imm32 + 223 68/push _test-input-stream/imm32 + 224 # . . call + 225 e8/call write/disp32 + 226 # . . discard args + 227 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 228 # . write(_test-input-stream, "1\n") + 229 # . . push args + 230 68/push "1\n"/imm32 + 231 68/push _test-input-stream/imm32 + 232 # . . call + 233 e8/call write/disp32 + 234 # . . discard args + 235 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 236 # . write(_test-input-stream, "\n") # empty line + 237 # . . push args + 238 68/push "\n"/imm32 + 239 68/push _test-input-stream/imm32 + 240 # . . call + 241 e8/call write/disp32 + 242 # . . discard args + 243 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 244 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") + 245 # . . push args + 246 68/push "2 3 # comment 4 inline with other contents\n"/imm32 + 247 68/push _test-input-stream/imm32 + 248 # . . call + 249 e8/call write/disp32 + 250 # . . discard args + 251 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 252 # . write(_test-input-stream, "== data 0x0a000000\n") + 253 # . . push args + 254 68/push "== data 0x0a000000\n"/imm32 + 255 68/push _test-input-stream/imm32 + 256 # . . call + 257 e8/call write/disp32 + 258 # . . discard args + 259 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 260 # . write(_test-input-stream, "4 5/imm32\n") + 261 # . . push args + 262 68/push "4 5/imm32\n"/imm32 + 263 68/push _test-input-stream/imm32 + 264 # . . call + 265 e8/call write/disp32 + 266 # . . discard args + 267 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 268 # . write(_test-input-stream, "== code\n") + 269 # . . push args + 270 68/push "== code\n"/imm32 + 271 68/push _test-input-stream/imm32 + 272 # . . call + 273 e8/call write/disp32 + 274 # . . discard args + 275 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 276 # . write(_test-input-stream, "6 7\n") + 277 # . . push args + 278 68/push "6 7\n"/imm32 + 279 68/push _test-input-stream/imm32 + 280 # . . call + 281 e8/call write/disp32 + 282 # . . discard args + 283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 284 # . write(_test-input-stream, "8 9\n") + 285 # . . push args + 286 68/push "8 9\n"/imm32 + 287 68/push _test-input-stream/imm32 + 288 # . . call + 289 e8/call write/disp32 + 290 # . . discard args + 291 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 292 # . write(_test-input-stream, "== code\n") + 293 # . . push args + 294 68/push "== code\n"/imm32 + 295 68/push _test-input-stream/imm32 + 296 # . . call + 297 e8/call write/disp32 + 298 # . . discard args + 299 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 300 # . write(_test-input-stream, "10 11\n") + 301 # . . push args + 302 68/push "10 11\n"/imm32 + 303 68/push _test-input-stream/imm32 + 304 # . . call + 305 e8/call write/disp32 + 306 # . . discard args + 307 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 308 # convert(_test-input-buffered-file, _test-output-buffered-file) + 309 # . . push args + 310 68/push _test-output-buffered-file/imm32 + 311 68/push _test-input-buffered-file/imm32 + 312 # . . call + 313 e8/call convert/disp32 + 314 # . . discard args + 315 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 316 # . flush(_test-output-buffered-file) + 317 # . . push args + 318 68/push _test-output-buffered-file/imm32 + 319 # . . call + 320 e8/call flush/disp32 + 321 # . . discard args + 322 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 323 # check output + 324 # == code 0x09000000 + 325 # 1 + 326 # 2 3 # comment 4 inline with other contents + 327 # 6 7 + 328 # 8 9 + 329 # 10 11 + 330 # == data 0x0a000000 + 331 # 4 5/imm32 + 332 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- + 365 # . check-next-stream-line-equal(_test-output-stream, "== code 0x09000000", msg) + 366 # . . push args + 367 68/push "F - test-convert/0"/imm32 + 368 68/push "== code 0x09000000"/imm32 + 369 68/push _test-output-stream/imm32 + 370 # . . call + 371 e8/call check-next-stream-line-equal/disp32 + 372 # . . discard args + 373 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 374 # . check-next-stream-line-equal(_test-output-stream, "1", msg) + 375 # . . push args + 376 68/push "F - test-convert/1"/imm32 + 377 68/push "1"/imm32 + 378 68/push _test-output-stream/imm32 + 379 # . . call + 380 e8/call check-next-stream-line-equal/disp32 + 381 # . . discard args + 382 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 383 # . check-next-stream-line-equal(_test-output-stream, "2 3 # comment 4 inline with other contents", msg) + 384 # . . push args + 385 68/push "F - test-convert/2"/imm32 + 386 68/push "2 3 # comment 4 inline with other contents"/imm32 + 387 68/push _test-output-stream/imm32 + 388 # . . call + 389 e8/call check-next-stream-line-equal/disp32 + 390 # . . discard args + 391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 392 # . check-next-stream-line-equal(_test-output-stream, "6 7", msg) + 393 # . . push args + 394 68/push "F - test-convert/3"/imm32 + 395 68/push "6 7"/imm32 + 396 68/push _test-output-stream/imm32 + 397 # . . call + 398 e8/call check-next-stream-line-equal/disp32 + 399 # . . discard args + 400 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 401 # . check-next-stream-line-equal(_test-output-stream, "8 9", msg) + 402 # . . push args + 403 68/push "F - test-convert/4"/imm32 + 404 68/push "8 9"/imm32 + 405 68/push _test-output-stream/imm32 + 406 # . . call + 407 e8/call check-next-stream-line-equal/disp32 + 408 # . . discard args + 409 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 410 # . check-next-stream-line-equal(_test-output-stream, "10 11", msg) + 411 # . . push args + 412 68/push "F - test-convert/5"/imm32 + 413 68/push "10 11"/imm32 + 414 68/push _test-output-stream/imm32 + 415 # . . call + 416 e8/call check-next-stream-line-equal/disp32 + 417 # . . discard args + 418 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 419 # . check-next-stream-line-equal(_test-output-stream, "== data 0x0a000000", msg) + 420 # . . push args + 421 68/push "F - test-convert/6"/imm32 + 422 68/push "== data 0x0a000000"/imm32 + 423 68/push _test-output-stream/imm32 + 424 # . . call + 425 e8/call check-next-stream-line-equal/disp32 + 426 # . . discard args + 427 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 428 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32", msg) + 429 # . . push args + 430 68/push "F - test-convert/7"/imm32 + 431 68/push "4 5/imm32"/imm32 + 432 68/push _test-output-stream/imm32 + 433 # . . call + 434 e8/call check-next-stream-line-equal/disp32 + 435 # . . discard args + 436 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 437 # . epilog + 438 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 439 5d/pop-to-EBP + 440 c3/return + 441 + 442 read-segments: # in : (address buffered-file), table : (address stream row) + 443 # pseudocode: + 444 # var curr-segment = null + 445 # var line = new-stream(512, 1) + 446 # while true + 447 # clear-stream(line) + 448 # read-line-buffered(in, line) + 449 # if (line->write == 0) break # end of file + 450 # var word-slice = next-word(line) + 451 # if slice-empty?(word-slice) # whitespace + 452 # continue + 453 # if slice-starts-with?(word-slice, "#") # comment + 454 # continue + 455 # if slice-equal?(word-slice, "==") + 456 # var segment-name = next-word(line) + 457 # curr-segment = get-or-insert-segment(table, segment-name, Segment-size) + 458 # if curr-segment->write == 0 + 459 # rewind-stream(line) + 460 # write-stream(curr-segment, line) + 461 # else + 462 # rewind-stream(line) + 463 # write-stream(curr-segment, line) # abort if curr-segment overflows + 464 # + 465 # word-slice and segment-name are both slices with disjoint lifetimes, so + 466 # we'll use the same address for them. + 467 # + 468 # registers: + 469 # line: ECX + 470 # word-slice and segment-name: EDX + 471 # segment-name and curr-segment: EBX + 472 # word-slice->start: ESI + 473 # temporary: EAX + 474 # + 475 # . prolog + 476 55/push-EBP + 477 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 478 # . save registers + 479 50/push-EAX + 480 51/push-ECX + 481 52/push-EDX + 482 53/push-EBX + 483 56/push-ESI + 484 # var line/ECX : (address stream byte) = stream(512) + 485 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP + 486 68/push 0x200/imm32/length + 487 68/push 0/imm32/read + 488 68/push 0/imm32/write + 489 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 490 # var word-slice/EDX = {0, 0} + 491 68/push 0/imm32/end + 492 68/push 0/imm32/curr + 493 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX + 494 $read-segments:loop: + 495 # clear-stream(line) + 496 # . . push args + 497 51/push-ECX + 498 # . . call + 499 e8/call clear-stream/disp32 + 500 # . . discard args + 501 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 502 # read-line-buffered(in, line) + 503 # . . push args + 504 51/push-ECX + 505 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 506 # . . call + 507 e8/call read-line-buffered/disp32 + 508 # . . discard args + 509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 510 $read-segments:check0: + 511 # if (line->write == 0) break + 512 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX + 513 0f 84/jump-if-equal $read-segments:break/disp32 + 514 +-- 26 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- + 540 # next-word(line, word-slice) + 541 # . . push args + 542 52/push-EDX + 543 51/push-ECX + 544 # . . call + 545 e8/call next-word/disp32 + 546 # . . discard args + 547 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 548 $read-segments:check1: + 549 # if (slice-empty?(word-slice)) continue + 550 # . EAX = slice-empty?(word-slice) + 551 # . . push args + 552 52/push-EDX + 553 # . . call + 554 e8/call slice-empty?/disp32 + 555 # . . discard args + 556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 557 # . if (EAX != 0) continue + 558 3d/compare-EAX-and 0/imm32 + 559 0f 85/jump-if-not-equal $read-segments:loop/disp32 + 560 $read-segments:check-for-comment: + 561 # if (slice-starts-with?(word-slice, "#")) continue + 562 # . start/ESI = word-slice->start + 563 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *ECX to ESI + 564 # . c/EAX = *start + 565 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 566 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL + 567 # . if (EAX == '#') continue + 568 3d/compare-EAX-and 0x23/imm32/hash + 569 0f 84/jump-if-equal $read-segments:loop/disp32 + 570 $read-segments:check-for-segment-header: + 571 +-- 42 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- + 613 # if slice-equal?(word-slice, "==") + 614 # segment-name = next-word(line) + 615 # curr-segment = get-or-insert(table, segment-name) + 616 # if (curr-segment->write > 0) continue + 617 # . EAX = slice-equal?(word-slice, "==") + 618 # . . push args + 619 68/push "=="/imm32 + 620 52/push-EDX + 621 # . . call + 622 e8/call slice-equal?/disp32 + 623 # . . discard args + 624 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 625 # . if (EAX == 0) goto check3 + 626 3d/compare-EAX-and 0/imm32 + 627 0f 84/jump-if-equal $read-segments:regular-line/disp32 + 628 # . next-word(line, segment-name) + 629 # . . push args + 630 52/push-EDX + 631 51/push-ECX + 632 # . . call + 633 e8/call next-word/disp32 + 634 # . . discard args + 635 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 636 +-- 42 lines: #? # dump segment name --------------------------------------------------------------------------------------------------------------------- + 678 # . EAX = get-or-insert-segment(table, segment-name, Segment-size) 679 # . . push args - 680 51/push-ECX - 681 53/push-EBX - 682 # . . call - 683 e8/call write-stream/disp32 - 684 # . . discard args - 685 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 686 # loop - 687 e9/jump $read-segments:loop/disp32 - 688 $read-segments:break: - 689 $read-segments:end: - 690 # . reclaim locals - 691 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - 692 # . restore registers - 693 5e/pop-to-ESI - 694 5b/pop-to-EBX - 695 5a/pop-to-EDX - 696 59/pop-to-ECX - 697 58/pop-to-EAX - 698 # . epilog - 699 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 700 5d/pop-to-EBP - 701 c3/return - 702 - 703 write-segments: # out : (address buffered-file), table : (address stream row) - 704 # pseudocode: - 705 # var curr = table->data - 706 # var max = table->data + table->write - 707 # while curr < max - 708 # name = table[i].name - 709 # print out, "== $name\n" - 710 # stream = table[i].stream - 711 # write-stream-data(out, stream) - 712 # curr += 8 - 713 # flush(out) - 714 # - 715 # . prolog - 716 55/push-EBP - 717 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 718 # . save registers - 719 50/push-EAX - 720 52/push-EDX - 721 56/push-ESI - 722 # ESI = table - 723 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - 724 # write/EDX = table->write - 725 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 726 # curr/ESI = table->data - 727 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 0xc/imm32 # add to EAX - 728 # max/EDX = curr + write - 729 01/add 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # add ESI to EDX - 730 $write-segments:loop: - 731 # if (curr >= max) break - 732 39/compare 3/mod/direct 6/rm32/ESI . . . 2/r32/EDX . . # compare ESI with EDX - 733 7d/jump-if-greater-or-equal $write-segments:break/disp8 - 734 # name/EAX = table[i].name - 735 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX - 736 # print out, "== $name\n" - 737 # . write-buffered(out, "== ") - 738 # . . push args - 739 68/push "== "/imm32 - 740 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 741 # . . call - 742 e8/call write-buffered/disp32 - 743 # . . discard args - 744 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 745 # . write-buffered(out, name) - 746 # . . push args - 747 50/push-EAX - 748 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 749 # . . call - 750 e8/call write-buffered/disp32 - 751 # . . discard args - 752 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 753 # . write-buffered(out, "\n") - 754 # . . push args - 755 68/push Newline/imm32 - 756 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 757 # . . call - 758 e8/call write-buffered/disp32 - 759 # . . discard args - 760 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 761 # stream/EAX = table[i].stream - 762 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - 763 # write-stream-data(out, stream) - 764 # . . push args - 765 50/push-EAX - 766 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 767 # . . call - 768 e8/call write-stream-data/disp32 - 769 # . . discard args - 770 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 771 $write-segments:continue: - 772 # curr += 8 - 773 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 8/imm32 # add to ESI - 774 eb/jump $write-segments:loop/disp8 - 775 $write-segments:break: - 776 # flush(out) - 777 # . . push args - 778 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 779 # . . call - 780 e8/call flush/disp32 - 781 # . . discard args - 782 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 783 $write-segments:end: - 784 # . restore registers - 785 5e/pop-to-ESI - 786 5a/pop-to-EDX - 787 58/pop-to-EAX - 788 # . epilog - 789 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 790 5d/pop-to-EBP - 791 c3/return - 792 - 793 ## helpers - 794 - 795 # TODO: pass in an allocation descriptor - 796 get-or-insert-segment: # table : (address stream row), s : (address slice), n : int -> EAX : (address stream) - 797 # pseudocode: - 798 # curr = table->data - 799 # max = &table->data[table->write] - 800 # while curr < max - 801 # if slice-equal?(s, *curr) - 802 # return *(curr+4) - 803 # curr += 8 - 804 # if table->write < table->length - 805 # *max = slice-to-string(Heap, s) - 806 # result = new-stream(Heap, n, 1) - 807 # *(max+4) = result - 808 # table->write += 8 - 809 # return result - 810 # return 0 - 811 # - 812 # . prolog - 813 55/push-EBP - 814 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 815 # . save registers - 816 51/push-ECX - 817 52/push-EDX - 818 56/push-ESI - 819 # ESI = table - 820 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 821 # curr/ECX = table->data - 822 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - 823 # max/EDX = table->data + table->write - 824 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 825 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX - 826 $get-or-insert-segment:search-loop: - 827 # if (curr >= max) break - 828 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 829 7d/jump-if-greater-or-equal $get-or-insert-segment:not-found/disp8 - 830 # if (slice-equal?(s, *curr)) return *(curr+4) - 831 # . EAX = slice-equal?(s, *curr) - 832 # . . push args - 833 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 834 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 835 # . . call - 836 e8/call slice-equal?/disp32 - 837 # . . discard args - 838 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 839 # . if (EAX != 0) return EAX = *(curr+4) - 840 3d/compare-EAX-and 0/imm32 - 841 74/jump-if-equal $get-or-insert-segment:mismatch/disp8 - 842 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 843 eb/jump $get-or-insert-segment:end/disp8 - 844 $get-or-insert-segment:mismatch: - 845 # curr += 8 - 846 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 8/imm32 # add to ECX - 847 # loop - 848 eb/jump $get-or-insert-segment:search-loop/disp8 - 849 $get-or-insert-segment:not-found: - 850 # result/EAX = 0 - 851 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 852 # if (table->write >= table->length) abort - 853 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 854 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) - 855 7d/jump-if-greater-or-equal $get-or-insert-segment:abort/disp8 - 856 # *max = slice-to-string(Heap, s) - 857 # . EAX = slice-to-string(Heap, s) - 858 # . . push args - 859 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 860 68/push Heap/imm32 - 861 # . . call - 862 e8/call slice-to-string/disp32 - 863 # . . discard args - 864 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 865 # . *max = EAX - 866 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX - 867 # result/EAX = new-stream(Heap, n, 1) - 868 # . . push args - 869 68/push 1/imm32 - 870 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 871 68/push Heap/imm32 - 872 # . . call - 873 e8/call new-stream/disp32 - 874 # . . discard args - 875 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 876 # *(max+4) = result - 877 89/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDX+4) - 878 # table->write += 8 - 879 81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 8/imm32 # add to *ESI - 880 $get-or-insert-segment:end: - 881 # . restore registers - 882 5e/pop-to-ESI - 883 5a/pop-to-EDX - 884 59/pop-to-ECX - 885 # . epilog - 886 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 887 5d/pop-to-EBP - 888 c3/return - 889 - 890 $get-or-insert-segment:abort: - 891 # . _write(2/stderr, error) - 892 # . . push args - 893 68/push "get-or-insert-segment: too many segments"/imm32 - 894 68/push 2/imm32/stderr - 895 # . . call - 896 e8/call _write/disp32 - 897 # . . discard args - 898 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 899 # . syscall(exit, 1) - 900 bb/copy-to-EBX 1/imm32 - 901 b8/copy-to-EAX 1/imm32/exit - 902 cd/syscall 0x80/imm8 - 903 # never gets here - 904 - 905 test-get-or-insert-segment: - 906 # . prolog - 907 55/push-EBP - 908 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 909 # var table/ECX : (address stream byte) = stream(2 * 8) - 910 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 911 68/push 0x10/imm32/length - 912 68/push 0/imm32/read - 913 68/push 0/imm32/write - 914 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 915 # EDX : (address slice) = "code" - 916 68/push _test-code-segment-end/imm32/end - 917 68/push _test-code-segment/imm32/start - 918 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 919 $test-get-or-insert-segment:first-call: - 920 # - start with an empty table, insert one segment, verify that it was inserted - 921 # segment/EAX = get-or-insert-segment(table, "code" slice, 10) - 922 # . . push args - 923 68/push 0xa/imm32/segment-length - 924 52/push-EDX - 925 51/push-ECX - 926 # . . call - 927 e8/call get-or-insert-segment/disp32 - 928 # . . discard args - 929 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 930 # save segment - 931 50/push-EAX - 932 # if (segment != 0) goto next check - 933 3d/compare-EAX-and 0/imm32 - 934 75/jump-if-not-equal $test-get-or-insert-segment:check1/disp8 - 935 # fail test - 936 # . _write(2/stderr, msg) - 937 # . . push args - 938 68/push "F - test-get-or-insert-segment/0\n"/imm32 - 939 68/push 2/imm32/stderr - 940 # . . call - 941 e8/call _write/disp32 - 942 # . . discard args - 943 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 944 # . increment Num-test-failures - 945 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Num-test-failures/disp32 # increment *Num-test-failures - 946 e9/jump $test-get-or-insert-segment:end/disp32 - 947 $test-get-or-insert-segment:check1: - 948 # check-ints-equal(segment->length, 10, msg) - 949 # . . push args - 950 68/push "F - test-get-or-insert-segment/1"/imm32 - 951 68/push 0xa/imm32/segment-length - 952 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) - 953 # . . call - 954 e8/call check-ints-equal/disp32 - 955 # . . discard args - 956 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 957 $test-get-or-insert-segment:check2: - 958 # check-ints-equal(table->write, rowsize = 8, msg) - 959 # . . push args - 960 68/push "F - test-get-or-insert-segment/2"/imm32 - 961 68/push 8/imm32/row-size - 962 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 963 # . . call - 964 e8/call check-ints-equal/disp32 - 965 # . . discard args - 966 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 967 # EAX = string-equal?(*table->data, "code") - 968 # . . push args - 969 68/push "code"/imm32 - 970 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - 971 # . . call - 972 e8/call string-equal?/disp32 - 973 # . . discard args - 974 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 975 # check-ints-equal(EAX, 1, msg) - 976 # . . push args - 977 68/push "F - test-get-or-insert-segment/3"/imm32 - 978 68/push 1/imm32 - 979 50/push-EAX - 980 # . . call - 981 e8/call check-ints-equal/disp32 - 982 # . . discard args - 983 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 984 $test-get-or-insert-segment:check3: - 985 # stream/EAX = *(table->data+4) - 986 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 0x10/disp8 . # copy *(ECX+16) to EAX - 987 # check-ints-equal(stream->length, 10, msg) - 988 # . . push args - 989 68/push "F - test-get-or-insert-segment/4"/imm32 - 990 68/push 0xa/imm32/segment-size - 991 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) - 992 # . . call - 993 e8/call check-ints-equal/disp32 - 994 # . . discard args - 995 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 996 $test-get-or-insert-segment:second-call: - 997 # - insert the same segment name again, verify that it was reused - 998 # segment2/EAX = get-or-insert-segment(table, "code" slice, 8) - 999 # . . push args -1000 68/push 8/imm32/segment-length -1001 52/push-EDX -1002 51/push-ECX -1003 # . . call -1004 e8/call get-or-insert-segment/disp32 -1005 # . . discard args -1006 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1007 # restore old segment1 -1008 5a/pop-to-EDX -1009 # check-ints-equal(segment2/EAX, segment1/EDX, msg) -1010 # . . push args -1011 68/push "F - test-get-or-insert-segment/5"/imm32 -1012 52/push-EDX -1013 50/push-EAX -1014 # . . call -1015 e8/call check-ints-equal/disp32 -1016 # . . discard args -1017 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1018 # no change to table size -1019 # . check-ints-equal(table->write, rowsize = 8, msg) -1020 # . . push args -1021 68/push "F - test-get-or-insert-segment/6"/imm32 -1022 68/push 8/imm32/row-size -1023 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX -1024 # . . call -1025 e8/call check-ints-equal/disp32 -1026 # . . discard args -1027 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1028 $test-get-or-insert-segment:third-call: -1029 # - insert a new segment name, verify that it was inserted -1030 # EDX : (address slice) = "data" -1031 c7 0/subop/copy 0/mod/indirect 2/rm32/EDX . . . . . _test-data-segment/imm32 # copy to *EDX -1032 c7 0/subop/copy 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 _test-data-segment-end/imm32 # copy to *(EDX+4) -1033 # segment2/EAX = get-or-insert-segment(table, "data" slice, 8) -1034 # . . push args -1035 68/push 8/imm32/segment-length -1036 52/push-EDX -1037 51/push-ECX -1038 # . . call -1039 e8/call get-or-insert-segment/disp32 -1040 # . . discard args -1041 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1042 # table gets a new row -1043 # . check-ints-equal(table->write, 2 rows = 16, msg) -1044 # . . push args -1045 68/push "F - test-get-or-insert-segment/7"/imm32 -1046 68/push 0x10/imm32/two-rows -1047 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX -1048 # . . call -1049 e8/call check-ints-equal/disp32 -1050 # . . discard args -1051 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1052 $test-get-or-insert-segment:end: -1053 # . epilog -1054 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1055 5d/pop-to-EBP -1056 c3/return -1057 -1058 # (re)compute the bounds of the next word in the line -1059 # return empty string on reaching end of file -1060 next-word: # line : (address stream byte), out : (address slice) -1061 # . prolog -1062 55/push-EBP -1063 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1064 # . save registers -1065 50/push-EAX -1066 51/push-ECX -1067 56/push-ESI -1068 57/push-EDI -1069 # ESI = line -1070 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -1071 # EDI = out -1072 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI -1073 # skip-chars-matching(line, ' ') -1074 # . . push args -1075 68/push 0x20/imm32/space -1076 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1077 # . . call -1078 e8/call skip-chars-matching/disp32 -1079 # . . discard args -1080 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1081 $next-word:check0: -1082 # if (line->read >= line->write) clear out and return -1083 # . EAX = line->read -1084 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -1085 # . if (EAX < line->write) goto next check -1086 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI -1087 7c/jump-if-lesser $next-word:check-for-comment/disp8 -1088 # . return out = {0, 0} -1089 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI -1090 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) -1091 eb/jump $next-word:end/disp8 -1092 $next-word:check-for-comment: -1093 # out->start = &line->data[line->read] -1094 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -1095 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX -1096 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI -1097 # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return -1098 # . EAX = line->data[line->read] -1099 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -1100 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL -1101 # . compare -1102 3d/compare-EAX-and 0x23/imm32/pound -1103 75/jump-if-not-equal $next-word:regular-word/disp8 -1104 $next-word:comment: -1105 # . out->end = &line->data[line->write] -1106 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -1107 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX -1108 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -1109 # . line->read = line->write -1110 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) -1111 # . return -1112 eb/jump $next-word:end/disp8 -1113 $next-word:regular-word: -1114 # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline -1115 # . . push args -1116 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1117 # . . call -1118 e8/call skip-chars-not-matching-whitespace/disp32 -1119 # . . discard args -1120 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1121 # out->end = &line->data[line->read] -1122 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -1123 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX -1124 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -1125 $next-word:end: -1126 # . restore registers -1127 5f/pop-to-EDI -1128 5e/pop-to-ESI -1129 59/pop-to-ECX -1130 58/pop-to-EAX -1131 # . epilog -1132 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1133 5d/pop-to-EBP -1134 c3/return -1135 -1136 test-next-word: -1137 # . prolog -1138 55/push-EBP -1139 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1140 # setup -1141 # . clear-stream(_test-stream) -1142 # . . push args -1143 68/push _test-stream/imm32 -1144 # . . call -1145 e8/call clear-stream/disp32 -1146 # . . discard args -1147 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1148 # var slice/ECX = {0, 0} -1149 68/push 0/imm32/end -1150 68/push 0/imm32/start -1151 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1152 # write(_test-stream, " ab") -1153 # . . push args -1154 68/push " ab"/imm32 -1155 68/push _test-stream/imm32 -1156 # . . call -1157 e8/call write/disp32 -1158 # . . discard args -1159 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1160 # next-word(_test-stream, slice) -1161 # . . push args -1162 51/push-ECX -1163 68/push _test-stream/imm32 -1164 # . . call -1165 e8/call next-word/disp32 -1166 # . . discard args -1167 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1168 # check-ints-equal(slice->start - _test-stream->data, 2, msg) -1169 # . check-ints-equal(slice->start - _test-stream, 14, msg) -1170 # . . push args -1171 68/push "F - test-next-word: start"/imm32 -1172 68/push 0xe/imm32 -1173 # . . push slice->start - _test-stream -1174 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1175 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1176 50/push-EAX -1177 # . . call -1178 e8/call check-ints-equal/disp32 -1179 # . . discard args -1180 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1181 # check-ints-equal(slice->end - _test-stream->data, 4, msg) -1182 # . check-ints-equal(slice->end - _test-stream, 16, msg) -1183 # . . push args -1184 68/push "F - test-next-word: end"/imm32 -1185 68/push 0x10/imm32 -1186 # . . push slice->end - _test-stream -1187 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1188 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1189 50/push-EAX -1190 # . . call -1191 e8/call check-ints-equal/disp32 -1192 # . . discard args -1193 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1194 # . epilog -1195 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1196 5d/pop-to-EBP -1197 c3/return -1198 -1199 test-next-word-returns-whole-comment: -1200 # . prolog -1201 55/push-EBP -1202 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1203 # setup -1204 # . clear-stream(_test-stream) -1205 # . . push args -1206 68/push _test-stream/imm32 -1207 # . . call -1208 e8/call clear-stream/disp32 -1209 # . . discard args -1210 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1211 # var slice/ECX = {0, 0} -1212 68/push 0/imm32/end -1213 68/push 0/imm32/start -1214 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1215 # write(_test-stream, " # a") -1216 # . . push args -1217 68/push " # a"/imm32 -1218 68/push _test-stream/imm32 -1219 # . . call -1220 e8/call write/disp32 -1221 # . . discard args -1222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1223 # next-word(_test-stream, slice) -1224 # . . push args -1225 51/push-ECX -1226 68/push _test-stream/imm32 -1227 # . . call -1228 e8/call next-word/disp32 -1229 # . . discard args -1230 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1231 # check-ints-equal(slice->start - _test-stream->data, 2, msg) -1232 # . check-ints-equal(slice->start - _test-stream, 14, msg) -1233 # . . push args -1234 68/push "F - test-next-word-returns-whole-comment: start"/imm32 -1235 68/push 0xe/imm32 -1236 # . . push slice->start - _test-stream -1237 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1238 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1239 50/push-EAX -1240 # . . call -1241 e8/call check-ints-equal/disp32 -1242 # . . discard args -1243 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1244 # check-ints-equal(slice->end - _test-stream->data, 5, msg) -1245 # . check-ints-equal(slice->end - _test-stream, 17, msg) -1246 # . . push args -1247 68/push "F - test-next-word-returns-whole-comment: end"/imm32 -1248 68/push 0x11/imm32 -1249 # . . push slice->end - _test-stream -1250 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1251 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1252 50/push-EAX -1253 # . . call -1254 e8/call check-ints-equal/disp32 -1255 # . . discard args -1256 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1257 # . epilog -1258 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1259 5d/pop-to-EBP -1260 c3/return -1261 -1262 test-next-word-returns-empty-string-on-eof: -1263 # . prolog -1264 55/push-EBP -1265 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1266 # setup -1267 # . clear-stream(_test-stream) -1268 # . . push args -1269 68/push _test-stream/imm32 -1270 # . . call -1271 e8/call clear-stream/disp32 -1272 # . . discard args -1273 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1274 # var slice/ECX = {0, 0} -1275 68/push 0/imm32/end -1276 68/push 0/imm32/start -1277 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1278 # write nothing to _test-stream -1279 # next-word(_test-stream, slice) -1280 # . . push args -1281 51/push-ECX -1282 68/push _test-stream/imm32 -1283 # . . call -1284 e8/call next-word/disp32 -1285 # . . discard args -1286 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1287 # check-ints-equal(slice->end - slice->start, 0, msg) -1288 # . . push args -1289 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 -1290 68/push 0/imm32 -1291 # . . push slice->end - slice->start -1292 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1293 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX -1294 50/push-EAX -1295 # . . call -1296 e8/call check-ints-equal/disp32 -1297 # . . discard args -1298 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1299 # . epilog -1300 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1301 5d/pop-to-EBP -1302 c3/return -1303 -1304 == data -1305 -1306 _test-code-segment: -1307 63/c 6f/o 64/d 65/e -1308 _test-code-segment-end: -1309 -1310 _test-data-segment: -1311 64/d 61/a 74/t 61/a -1312 _test-data-segment-end: -1313 -1314 Segment-size: -1315 # TODO: there's currently a tight size limit on segments because we aren't growing the heap -1316 0x100/imm32 -1317 #? 0x1000/imm32/4KB -1318 -1319 # . . vim:nowrap:textwidth=0 + 680 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size + 681 52/push-EDX + 682 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 683 # . . call + 684 e8/call get-or-insert-segment/disp32 + 685 # . . discard args + 686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 687 # . curr-segment = EAX + 688 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX + 689 # . if (curr-segment->write > 0) continue + 690 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX + 691 3d/compare-EAX-and 0/imm32 + 692 0f 8f/jump-if-greater $read-segments:loop/disp32 + 693 # fall through + 694 $read-segments:regular-line: + 695 # rewind-stream(line) + 696 # . . push args + 697 51/push-ECX + 698 # . . call + 699 e8/call rewind-stream/disp32 + 700 # . . discard args + 701 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 702 # write-stream(curr-segment, line) + 703 # . . push args + 704 51/push-ECX + 705 53/push-EBX + 706 # . . call + 707 e8/call write-stream/disp32 + 708 # . . discard args + 709 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 710 # loop + 711 e9/jump $read-segments:loop/disp32 + 712 $read-segments:break: + 713 $read-segments:end: + 714 # . reclaim locals + 715 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP + 716 # . restore registers + 717 5e/pop-to-ESI + 718 5b/pop-to-EBX + 719 5a/pop-to-EDX + 720 59/pop-to-ECX + 721 58/pop-to-EAX + 722 # . epilog + 723 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 724 5d/pop-to-EBP + 725 c3/return + 726 + 727 write-segments: # out : (address buffered-file), table : (address stream row) + 728 # pseudocode: + 729 # var curr = table->data + 730 # var max = table->data + table->write + 731 # while curr < max + 732 # stream = table[i].stream + 733 # write-stream-data(out, stream) + 734 # curr += 8 + 735 # flush(out) + 736 # + 737 # . prolog + 738 55/push-EBP + 739 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 740 # . save registers + 741 50/push-EAX + 742 52/push-EDX + 743 56/push-ESI + 744 # ESI = table + 745 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI + 746 # write/EDX = table->write + 747 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX + 748 # curr/ESI = table->data + 749 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 0xc/imm32 # add to EAX + 750 # max/EDX = curr + write + 751 01/add 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # add ESI to EDX + 752 $write-segments:loop: + 753 # if (curr >= max) break + 754 39/compare 3/mod/direct 6/rm32/ESI . . . 2/r32/EDX . . # compare ESI with EDX + 755 7d/jump-if-greater-or-equal $write-segments:break/disp8 + 756 # stream/EAX = table[i].stream + 757 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX + 758 # write-stream-data(out, stream) + 759 # . . push args + 760 50/push-EAX + 761 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 762 # . . call + 763 e8/call write-stream-data/disp32 + 764 # . . discard args + 765 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 766 $write-segments:continue: + 767 # curr += 8 + 768 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 8/imm32 # add to ESI + 769 eb/jump $write-segments:loop/disp8 + 770 $write-segments:break: + 771 # flush(out) + 772 # . . push args + 773 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 774 # . . call + 775 e8/call flush/disp32 + 776 # . . discard args + 777 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 778 $write-segments:end: + 779 # . restore registers + 780 5e/pop-to-ESI + 781 5a/pop-to-EDX + 782 58/pop-to-EAX + 783 # . epilog + 784 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 785 5d/pop-to-EBP + 786 c3/return + 787 + 788 ## helpers + 789 + 790 # TODO: pass in an allocation descriptor + 791 get-or-insert-segment: # table : (address stream row), s : (address slice), n : int -> EAX : (address stream) + 792 # pseudocode: + 793 # curr = table->data + 794 # max = &table->data[table->write] + 795 # while curr < max + 796 # if slice-equal?(s, *curr) + 797 # return *(curr+4) + 798 # curr += 8 + 799 # if table->write < table->length + 800 # *max = slice-to-string(Heap, s) + 801 # result = new-stream(Heap, n, 1) + 802 # *(max+4) = result + 803 # table->write += 8 + 804 # return result + 805 # return 0 + 806 # + 807 # . prolog + 808 55/push-EBP + 809 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 810 # . save registers + 811 51/push-ECX + 812 52/push-EDX + 813 56/push-ESI + 814 # ESI = table + 815 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + 816 # curr/ECX = table->data + 817 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX + 818 # max/EDX = table->data + table->write + 819 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX + 820 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX + 821 $get-or-insert-segment:search-loop: + 822 # if (curr >= max) break + 823 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX + 824 7d/jump-if-greater-or-equal $get-or-insert-segment:not-found/disp8 + 825 # if (slice-equal?(s, *curr)) return *(curr+4) + 826 # . EAX = slice-equal?(s, *curr) + 827 # . . push args + 828 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX + 829 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 830 # . . call + 831 e8/call slice-equal?/disp32 + 832 # . . discard args + 833 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 834 # . if (EAX != 0) return EAX = *(curr+4) + 835 3d/compare-EAX-and 0/imm32 + 836 74/jump-if-equal $get-or-insert-segment:mismatch/disp8 + 837 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX + 838 eb/jump $get-or-insert-segment:end/disp8 + 839 $get-or-insert-segment:mismatch: + 840 # curr += 8 + 841 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 8/imm32 # add to ECX + 842 # loop + 843 eb/jump $get-or-insert-segment:search-loop/disp8 + 844 $get-or-insert-segment:not-found: + 845 # result/EAX = 0 + 846 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 847 # if (table->write >= table->length) abort + 848 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX + 849 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) + 850 7d/jump-if-greater-or-equal $get-or-insert-segment:abort/disp8 + 851 # *max = slice-to-string(Heap, s) + 852 # . EAX = slice-to-string(Heap, s) + 853 # . . push args + 854 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 855 68/push Heap/imm32 + 856 # . . call + 857 e8/call slice-to-string/disp32 + 858 # . . discard args + 859 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 860 # . *max = EAX + 861 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX + 862 # result/EAX = new-stream(Heap, n, 1) + 863 # . . push args + 864 68/push 1/imm32 + 865 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 866 68/push Heap/imm32 + 867 # . . call + 868 e8/call new-stream/disp32 + 869 # . . discard args + 870 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 871 # *(max+4) = result + 872 89/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDX+4) + 873 # table->write += 8 + 874 81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 8/imm32 # add to *ESI + 875 $get-or-insert-segment:end: + 876 # . restore registers + 877 5e/pop-to-ESI + 878 5a/pop-to-EDX + 879 59/pop-to-ECX + 880 # . epilog + 881 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 882 5d/pop-to-EBP + 883 c3/return + 884 + 885 $get-or-insert-segment:abort: + 886 # . _write(2/stderr, error) + 887 # . . push args + 888 68/push "get-or-insert-segment: too many segments"/imm32 + 889 68/push 2/imm32/stderr + 890 # . . call + 891 e8/call _write/disp32 + 892 # . . discard args + 893 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 894 # . syscall(exit, 1) + 895 bb/copy-to-EBX 1/imm32 + 896 b8/copy-to-EAX 1/imm32/exit + 897 cd/syscall 0x80/imm8 + 898 # never gets here + 899 + 900 test-get-or-insert-segment: + 901 # . prolog + 902 55/push-EBP + 903 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 904 # var table/ECX : (address stream byte) = stream(2 * 8) + 905 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP + 906 68/push 0x10/imm32/length + 907 68/push 0/imm32/read + 908 68/push 0/imm32/write + 909 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 910 # EDX : (address slice) = "code" + 911 68/push _test-code-segment-end/imm32/end + 912 68/push _test-code-segment/imm32/start + 913 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX + 914 $test-get-or-insert-segment:first-call: + 915 # - start with an empty table, insert one segment, verify that it was inserted + 916 # segment/EAX = get-or-insert-segment(table, "code" slice, 10) + 917 # . . push args + 918 68/push 0xa/imm32/segment-length + 919 52/push-EDX + 920 51/push-ECX + 921 # . . call + 922 e8/call get-or-insert-segment/disp32 + 923 # . . discard args + 924 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 925 # save segment + 926 50/push-EAX + 927 # if (segment != 0) goto next check + 928 3d/compare-EAX-and 0/imm32 + 929 75/jump-if-not-equal $test-get-or-insert-segment:check1/disp8 + 930 # fail test + 931 # . _write(2/stderr, msg) + 932 # . . push args + 933 68/push "F - test-get-or-insert-segment/0\n"/imm32 + 934 68/push 2/imm32/stderr + 935 # . . call + 936 e8/call _write/disp32 + 937 # . . discard args + 938 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 939 # . increment Num-test-failures + 940 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Num-test-failures/disp32 # increment *Num-test-failures + 941 e9/jump $test-get-or-insert-segment:end/disp32 + 942 $test-get-or-insert-segment:check1: + 943 # check-ints-equal(segment->length, 10, msg) + 944 # . . push args + 945 68/push "F - test-get-or-insert-segment/1"/imm32 + 946 68/push 0xa/imm32/segment-length + 947 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) + 948 # . . call + 949 e8/call check-ints-equal/disp32 + 950 # . . discard args + 951 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 952 $test-get-or-insert-segment:check2: + 953 # check-ints-equal(table->write, rowsize = 8, msg) + 954 # . . push args + 955 68/push "F - test-get-or-insert-segment/2"/imm32 + 956 68/push 8/imm32/row-size + 957 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX + 958 # . . call + 959 e8/call check-ints-equal/disp32 + 960 # . . discard args + 961 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 962 # EAX = string-equal?(*table->data, "code") + 963 # . . push args + 964 68/push "code"/imm32 + 965 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) + 966 # . . call + 967 e8/call string-equal?/disp32 + 968 # . . discard args + 969 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 970 # check-ints-equal(EAX, 1, msg) + 971 # . . push args + 972 68/push "F - test-get-or-insert-segment/3"/imm32 + 973 68/push 1/imm32 + 974 50/push-EAX + 975 # . . call + 976 e8/call check-ints-equal/disp32 + 977 # . . discard args + 978 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 979 $test-get-or-insert-segment:check3: + 980 # stream/EAX = *(table->data+4) + 981 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 0x10/disp8 . # copy *(ECX+16) to EAX + 982 # check-ints-equal(stream->length, 10, msg) + 983 # . . push args + 984 68/push "F - test-get-or-insert-segment/4"/imm32 + 985 68/push 0xa/imm32/segment-size + 986 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) + 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 $test-get-or-insert-segment:second-call: + 992 # - insert the same segment name again, verify that it was reused + 993 # segment2/EAX = get-or-insert-segment(table, "code" slice, 8) + 994 # . . push args + 995 68/push 8/imm32/segment-length + 996 52/push-EDX + 997 51/push-ECX + 998 # . . call + 999 e8/call get-or-insert-segment/disp32 +1000 # . . discard args +1001 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1002 # restore old segment1 +1003 5a/pop-to-EDX +1004 # check-ints-equal(segment2/EAX, segment1/EDX, msg) +1005 # . . push args +1006 68/push "F - test-get-or-insert-segment/5"/imm32 +1007 52/push-EDX +1008 50/push-EAX +1009 # . . call +1010 e8/call check-ints-equal/disp32 +1011 # . . discard args +1012 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1013 # no change to table size +1014 # . check-ints-equal(table->write, rowsize = 8, msg) +1015 # . . push args +1016 68/push "F - test-get-or-insert-segment/6"/imm32 +1017 68/push 8/imm32/row-size +1018 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX +1019 # . . call +1020 e8/call check-ints-equal/disp32 +1021 # . . discard args +1022 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1023 $test-get-or-insert-segment:third-call: +1024 # - insert a new segment name, verify that it was inserted +1025 # EDX : (address slice) = "data" +1026 c7 0/subop/copy 0/mod/indirect 2/rm32/EDX . . . . . _test-data-segment/imm32 # copy to *EDX +1027 c7 0/subop/copy 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 _test-data-segment-end/imm32 # copy to *(EDX+4) +1028 # segment2/EAX = get-or-insert-segment(table, "data" slice, 8) +1029 # . . push args +1030 68/push 8/imm32/segment-length +1031 52/push-EDX +1032 51/push-ECX +1033 # . . call +1034 e8/call get-or-insert-segment/disp32 +1035 # . . discard args +1036 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1037 # table gets a new row +1038 # . check-ints-equal(table->write, 2 rows = 16, msg) +1039 # . . push args +1040 68/push "F - test-get-or-insert-segment/7"/imm32 +1041 68/push 0x10/imm32/two-rows +1042 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX +1043 # . . call +1044 e8/call check-ints-equal/disp32 +1045 # . . discard args +1046 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1047 $test-get-or-insert-segment:end: +1048 # . epilog +1049 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1050 5d/pop-to-EBP +1051 c3/return +1052 +1053 # (re)compute the bounds of the next word in the line +1054 # return empty string on reaching end of file +1055 next-word: # line : (address stream byte), out : (address slice) +1056 # . prolog +1057 55/push-EBP +1058 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1059 # . save registers +1060 50/push-EAX +1061 51/push-ECX +1062 56/push-ESI +1063 57/push-EDI +1064 # ESI = line +1065 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +1066 # EDI = out +1067 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI +1068 # skip-chars-matching(line, ' ') +1069 # . . push args +1070 68/push 0x20/imm32/space +1071 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1072 # . . call +1073 e8/call skip-chars-matching/disp32 +1074 # . . discard args +1075 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1076 $next-word:check0: +1077 # if (line->read >= line->write) clear out and return +1078 # . EAX = line->read +1079 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +1080 # . if (EAX < line->write) goto next check +1081 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI +1082 7c/jump-if-lesser $next-word:check-for-comment/disp8 +1083 # . return out = {0, 0} +1084 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI +1085 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) +1086 eb/jump $next-word:end/disp8 +1087 $next-word:check-for-comment: +1088 # out->start = &line->data[line->read] +1089 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +1090 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX +1091 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI +1092 # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return +1093 # . EAX = line->data[line->read] +1094 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +1095 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL +1096 # . compare +1097 3d/compare-EAX-and 0x23/imm32/pound +1098 75/jump-if-not-equal $next-word:regular-word/disp8 +1099 $next-word:comment: +1100 # . out->end = &line->data[line->write] +1101 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX +1102 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX +1103 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) +1104 # . line->read = line->write +1105 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) +1106 # . return +1107 eb/jump $next-word:end/disp8 +1108 $next-word:regular-word: +1109 # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline +1110 # . . push args +1111 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1112 # . . call +1113 e8/call skip-chars-not-matching-whitespace/disp32 +1114 # . . discard args +1115 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1116 # out->end = &line->data[line->read] +1117 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +1118 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX +1119 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) +1120 $next-word:end: +1121 # . restore registers +1122 5f/pop-to-EDI +1123 5e/pop-to-ESI +1124 59/pop-to-ECX +1125 58/pop-to-EAX +1126 # . epilog +1127 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1128 5d/pop-to-EBP +1129 c3/return +1130 +1131 test-next-word: +1132 # . prolog +1133 55/push-EBP +1134 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1135 # setup +1136 # . clear-stream(_test-stream) +1137 # . . push args +1138 68/push _test-stream/imm32 +1139 # . . call +1140 e8/call clear-stream/disp32 +1141 # . . discard args +1142 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1143 # var slice/ECX = {0, 0} +1144 68/push 0/imm32/end +1145 68/push 0/imm32/start +1146 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1147 # write(_test-stream, " ab") +1148 # . . push args +1149 68/push " ab"/imm32 +1150 68/push _test-stream/imm32 +1151 # . . call +1152 e8/call write/disp32 +1153 # . . discard args +1154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1155 # next-word(_test-stream, slice) +1156 # . . push args +1157 51/push-ECX +1158 68/push _test-stream/imm32 +1159 # . . call +1160 e8/call next-word/disp32 +1161 # . . discard args +1162 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1163 # check-ints-equal(slice->start - _test-stream->data, 2, msg) +1164 # . check-ints-equal(slice->start - _test-stream, 14, msg) +1165 # . . push args +1166 68/push "F - test-next-word: start"/imm32 +1167 68/push 0xe/imm32 +1168 # . . push slice->start - _test-stream +1169 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +1170 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +1171 50/push-EAX +1172 # . . call +1173 e8/call check-ints-equal/disp32 +1174 # . . discard args +1175 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1176 # check-ints-equal(slice->end - _test-stream->data, 4, msg) +1177 # . check-ints-equal(slice->end - _test-stream, 16, msg) +1178 # . . push args +1179 68/push "F - test-next-word: end"/imm32 +1180 68/push 0x10/imm32 +1181 # . . push slice->end - _test-stream +1182 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +1183 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +1184 50/push-EAX +1185 # . . call +1186 e8/call check-ints-equal/disp32 +1187 # . . discard args +1188 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1189 # . epilog +1190 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1191 5d/pop-to-EBP +1192 c3/return +1193 +1194 test-next-word-returns-whole-comment: +1195 # . prolog +1196 55/push-EBP +1197 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1198 # setup +1199 # . clear-stream(_test-stream) +1200 # . . push args +1201 68/push _test-stream/imm32 +1202 # . . call +1203 e8/call clear-stream/disp32 +1204 # . . discard args +1205 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1206 # var slice/ECX = {0, 0} +1207 68/push 0/imm32/end +1208 68/push 0/imm32/start +1209 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1210 # write(_test-stream, " # a") +1211 # . . push args +1212 68/push " # a"/imm32 +1213 68/push _test-stream/imm32 +1214 # . . call +1215 e8/call write/disp32 +1216 # . . discard args +1217 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1218 # next-word(_test-stream, slice) +1219 # . . push args +1220 51/push-ECX +1221 68/push _test-stream/imm32 +1222 # . . call +1223 e8/call next-word/disp32 +1224 # . . discard args +1225 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1226 # check-ints-equal(slice->start - _test-stream->data, 2, msg) +1227 # . check-ints-equal(slice->start - _test-stream, 14, msg) +1228 # . . push args +1229 68/push "F - test-next-word-returns-whole-comment: start"/imm32 +1230 68/push 0xe/imm32 +1231 # . . push slice->start - _test-stream +1232 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +1233 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +1234 50/push-EAX +1235 # . . call +1236 e8/call check-ints-equal/disp32 +1237 # . . discard args +1238 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1239 # check-ints-equal(slice->end - _test-stream->data, 5, msg) +1240 # . check-ints-equal(slice->end - _test-stream, 17, msg) +1241 # . . push args +1242 68/push "F - test-next-word-returns-whole-comment: end"/imm32 +1243 68/push 0x11/imm32 +1244 # . . push slice->end - _test-stream +1245 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +1246 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +1247 50/push-EAX +1248 # . . call +1249 e8/call check-ints-equal/disp32 +1250 # . . discard args +1251 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1252 # . epilog +1253 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1254 5d/pop-to-EBP +1255 c3/return +1256 +1257 test-next-word-returns-empty-string-on-eof: +1258 # . prolog +1259 55/push-EBP +1260 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1261 # setup +1262 # . clear-stream(_test-stream) +1263 # . . push args +1264 68/push _test-stream/imm32 +1265 # . . call +1266 e8/call clear-stream/disp32 +1267 # . . discard args +1268 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1269 # var slice/ECX = {0, 0} +1270 68/push 0/imm32/end +1271 68/push 0/imm32/start +1272 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1273 # write nothing to _test-stream +1274 # next-word(_test-stream, slice) +1275 # . . push args +1276 51/push-ECX +1277 68/push _test-stream/imm32 +1278 # . . call +1279 e8/call next-word/disp32 +1280 # . . discard args +1281 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1282 # check-ints-equal(slice->end - slice->start, 0, msg) +1283 # . . push args +1284 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 +1285 68/push 0/imm32 +1286 # . . push slice->end - slice->start +1287 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +1288 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX +1289 50/push-EAX +1290 # . . call +1291 e8/call check-ints-equal/disp32 +1292 # . . discard args +1293 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1294 # . epilog +1295 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1296 5d/pop-to-EBP +1297 c3/return +1298 +1299 == data +1300 +1301 _test-code-segment: +1302 63/c 6f/o 64/d 65/e +1303 _test-code-segment-end: +1304 +1305 _test-data-segment: +1306 64/d 61/a 74/t 61/a +1307 _test-data-segment-end: +1308 +1309 Segment-size: +1310 0x1000/imm32/4KB +1311 +1312 Heap: +1313 # curr +1314 0/imm32 +1315 # limit +1316 0/imm32 +1317 +1318 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0