es: Mon, 29 Jan 2035 03:59:39 GMT ETag: "47bf4f0d086d6b75cd2003c2408a8b8149d4cfbb"
1 # Read a series of segments from stdin and concatenate segments with the same 2 # name on stdout. 3 # 4 # Segments are emitted in order of first encounter. 5 # 6 # Drop lines that are all comments. They could get misleading after assortment 7 # because we don't know if they refer to the line above or the line below. 8 # 9 # To run: 10 # $ ./bootstrap translate init.linux 0*.subx apps/subx-params.subx apps/assort.subx -o apps/assort 11 # $ cat x 12 # == code 13 # abc 14 # == code 15 # def 16 # $ cat x |./bootstrap run apps/assort 17 # == code 18 # abc 19 # def 20 21 == code 22 # instruction effective address register displacement immediate 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 # . prologue 28 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 29 30 # initialize heap 31 # . Heap = new-segment(Heap-size) 32 # . . push args 33 68/push Heap/imm32 34 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size 35 # . . call 36 e8/call new-segment/disp32 37 # . . discard args 38 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 39 40 # - if argc > 1 and argv[1] == "test", then return run_tests() 41 # if (argc <= 1) goto interactive 42 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp 43 7e/jump-if-<= $subx-assort-main:interactive/disp8 44 # if (!kernel-string-equal?(argv[1], "test")) goto interactive 45 # . eax = kernel-string-equal?(argv[1], "test") 46 # . . push args 47 68/push "test"/imm32 48 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 49 # . . call 50 e8/call kernel-string-equal?/disp32 51 # . . discard args 52 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 53 # . if (eax == false) goto interactive 54 3d/compare-eax-and 0/imm32/false 55 74/jump-if-= $subx-assort-main:interactive/disp8 56 # run-tests() 57 e8/call run-tests/disp32 58 # syscall(exit, *Num-test-failures) 59 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx 60 eb/jump $subx-assort-main:end/disp8 61 $subx-assort-main:interactive: 62 # - otherwise convert stdin 63 # var ed/eax: exit-descriptor 64 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # subtract from esp 65 89/copy 3/mod/direct 0/rm32/eax . . . 4/r32/esp . . # copy esp to eax 66 # configure ed to really exit() 67 # . ed->target = 0 68 c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax 69 # subx-assort(Stdin, Stdout, Stderr, ed) 70 # . . push args 71 50/push-eax/ed 72 68/push Stderr/imm32 73 68/push Stdout/imm32 74 68/push Stdin/imm32 75 # . . call 76 e8/call subx-assort/disp32 77 # . . discard args 78 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 79 # syscall(exit, 0) 80 bb/copy-to-ebx 0/imm32 81 $subx-assort-main:end: 82 e8/call syscall_exit/disp32 83 84 # data structure: 85 # table: (addr stream {(handle array byte), (handle stream byte)}) (16 bytes/row) 86 # inefficient; uses sequential search for looking up segments by name 87 88 subx-assort: # in: (addr buffered-file), out: (addr buffered-file) 89 # pseudocode: 90 # var table: (addr stream {(handle array byte), (handle stream byte)} 10 rows) 91 # read-segments(in, table) 92 # write-segments(out, table) 93 # 94 # . prologue 95 55/push-ebp 96 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 97 # . save registers 98 51/push-ecx 99 # var table/ecx: (stream {string, (handle stream byte)} 160) # 10 rows * 16 bytes/row 100 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xa0/imm32 # subtract from esp 101 68/push 0xa0/imm32/length 102 68/push 0/imm32/read 103 68/push 0/imm32/write 104 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 105 # clear-stream(table) 106 # . . push args 107 51/push-ecx 108 # . . call 109 e8/call clear-stream/disp32 110 # . . discard args 111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 112 $subx-assort:read: 113 +-- 9 lines: #? # print("read\n") -------------------------------------------------------------------------------------------------------------------------------------------------- 122 # read-segments(in, table) 123 # . . push args 124 51/push-ecx 125 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 126 # . . call 127 e8/call read-segments/disp32 128 # . . discard args 129 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 130 $subx-assort:write: 131 +-- 9 lines: #? # print("write\n") ------------------------------------------------------------------------------------------------------------------------------------------------- 140 # write-segments(out, table) 141 # . . push args 142 51/push-ecx 143 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 144 # . . call 145 e8/call write-segments/disp32 146 # . . discard args 147 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 148 $subx-assort:end: 149 # . reclaim locals 150 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xac/imm32 # add to esp 151 # . restore registers 152 59/pop-to-ecx 153 # . epilogue 154 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 155 5d/pop-to-ebp 156 c3/return 157 158 test-subx-assort: 159 # . prologue 160 55/push-ebp 161 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 162 # setup 163 # . clear-stream(_test-input-stream) 164 # . . push args 165 68/push _test-input-stream/imm32 166 # . . call 167 e8/call clear-stream/disp32 168 # . . discard args 169 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 170 # . clear-stream($_test-input-buffered-file->buffer) 171 # . . push args 172 68/push $_test-input-buffered-file->buffer/imm32 173 # . . call 174 e8/call clear-stream/disp32 175 # . . discard args 176 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 177 # . clear-stream(_test-output-stream) 178 # . . push args 179 68/push _test-output-stream/imm32 180 # . . call 181 e8/call clear-stream/disp32 182 # . . discard args 183 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 184 # . clear-stream($_test-output-buffered-file->buffer) 185 # . . push args 186 68/push $_test-output-buffered-file->buffer/imm32 187 # . . call 188 e8/call clear-stream/disp32 189 # . . discard args 190 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 191 # initialize input (meta comments in parens) 192 # # comment 1 193 # # comment 2 indented 194 # == code 0x09000000 (new segment) 195 # # comment 3 inside a segment 196 # 1 197 # (empty line) 198 # 2 3 # comment 4 inline with other contents 199 # == data 0x0a000000 (new segment) 200 # 4 5/imm32 201 # == code (existing segment but non-contiguous with previous iteration) 202 # 6 7 203 # 8 9 (multiple lines) 204 # == code (existing segment contiguous with previous iteration) 205 # 10 11 206 # . write(_test-input-stream, "# comment 1\n") 207 # . . push args 208 68/push "# comment 1\n"/imm32 209 68/push _test-input-stream/imm32 210 # . . call 211 e8/call write/disp32 212 # . . discard args 213 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 214 # . write(_test-input-stream, " # comment 2 indented\n") 215 # . . push args 216 68/push " # comment 2 indented\n"/imm32 217 68/push _test-input-stream/imm32 218 # . . call 219 e8/call write/disp32 220 # . . discard args 221 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 222 # . write(_test-input-stream, "== code 0x09000000\n") 223 # . . push args 224 68/push "== code 0x09000000\n"/imm32 225 68/push _test-input-stream/imm32 226 # . . call 227 e8/call write/disp32 228 # . . discard args 229 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 230 # . write(_test-input-stream, "# comment 3 inside a segment\n") 231 # . . push args 232 68/push "# comment 3 inside a segment\n"/imm32 233 68/push _test-input-stream/imm32 234 # . . call 235 e8/call write/disp32 236 # . . discard args 237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 238 # . write(_test-input-stream, "1\n") 239 # . . push args 240 68/push "1\n"/imm32 241 68/push _test-input-stream/imm32 242 # . . call 243 e8/call write/disp32 244 # . . discard args 245 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 246 # . write(_test-input-stream, "\n") # empty line 247 # . . push args 248 68/push Newline/imm32 249 68/push _test-input-stream/imm32 250 # . . call 251 e8/call write/disp32 252 # . . discard args 253 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 254 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") 255 # . . push args 256 68/push "2 3 # comment 4 inline with other contents\n"/imm32 257 68/push _test-input-stream/imm32 258 # . . call 259 e8/call write/disp32 260 # . . discard args 261 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 262 # . write(_test-input-stream, "== data 0x0a000000\n") 263 # . . push args 264 68/push "== data 0x0a000000\n"/imm32 265 68/push _test-input-stream/imm32 266 # . . call 267 e8/call write/disp32 268 # . . discard args 269 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 270 # . write(_test-input-stream, "4 5/imm32\n") 271 # . . push args 272 68/push "4 5/imm32\n"/imm32 273 68/push _test-input-stream/imm32 274 # . . call 275 e8/call write/disp32 276 # . . discard args 277 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 278 # . write(_test-input-stream, "== code\n") 279 # . . push args 280 68/push "== code\n"/imm32 281 68/push _test-input-stream/imm32 282 # . . call 283 e8/call write/disp32 284 # . . discard args 285 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 286 # . write(_test-input-stream, "6 7\n") 287 # . . push args 288 68/push "6 7\n"/imm32 289 68/push _test-input-stream/imm32 290 # . . call 291 e8/call write/disp32 292 # . . discard args 293 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 294 # . write(_test-input-stream, "8 9\n") 295 # . . push args 296 68/push "8 9\n"/imm32 297 68/push _test-input-stream/imm32 298 # . . call 299 e8/call write/disp32 300 # . . discard args 301 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 302 # . write(_test-input-stream, "== code\n") 303 # . . push args 304 68/push "== code\n"/imm32 305 68/push _test-input-stream/imm32 306 # . . call 307 e8/call write/disp32 308 # . . discard args 309 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 310 # . write(_test-input-stream, "10 11\n") 311 # . . push args 312 68/push "10 11\n"/imm32 313 68/push _test-input-stream/imm32 314 # . . call 315 e8/call write/disp32 316 # . . discard args 317 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 318 # subx-assort(_test-input-buffered-file, _test-output-buffered-file) 319 # . . push args 320 68/push _test-output-buffered-file/imm32 321 68/push _test-input-buffered-file/imm32 322 # . . call 323 e8/call subx-assort/disp32 324 # . . discard args 325 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 326 # . flush(_test-output-buffered-file) 327 # . . push args 328 68/push _test-output-buffered-file/imm32 329 # . . call 330 e8/call flush/disp32 331 # . . discard args 332 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 333 # check output 334 # == code 0x09000000 335 # 1 336 # 2 3 # comment 4 inline with other contents 337 # 6 7 338 # 8 9 339 # 10 11 340 # == data 0x0a000000 341 # 4 5/imm32 342 +-- 33 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 375 # . check-next-stream-line-equal(_test-output-stream, "== code 0x09000000", msg) 376 # . . push args 377 68/push "F - test-subx-assort/0"/imm32 378 68/push "== code 0x09000000"/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, "1", msg) 385 # . . push args 386 68/push "F - test-subx-assort/1"/imm32 387 68/push "1"/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, "2 3 # comment 4 inline with other contents", msg) 394 # . . push args 395 68/push "F - test-subx-assort/2"/imm32 396 68/push "2 3 # comment 4 inline with other contents"/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, "6 7", msg) 403 # . . push args 404 68/push "F - test-subx-assort/3"/imm32 405 68/push "6 7"/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, "8 9", msg) 412 # . . push args 413 68/push "F - test-subx-assort/4"/imm32 414 68/push "8 9"/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 # . check-next-stream-line-equal(_test-output-stream, "10 11", msg) 421 # . . push args 422 68/push "F - test-subx-assort/5"/imm32 423 68/push "10 11"/imm32 424 68/push _test-output-stream/imm32 425 # . . call 426 e8/call check-next-stream-line-equal/disp32 427 # . . discard args 428 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 429 # . check-next-stream-line-equal(_test-output-stream, "== data 0x0a000000", msg) 430 # . . push args 431 68/push "F - test-subx-assort/6"/imm32 432 68/push "== data 0x0a000000"/imm32 433 68/push _test-output-stream/imm32 434 # . . call 435 e8/call check-next-stream-line-equal/disp32 436 # . . discard args 437 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 438 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32", msg) 439 # . . push args 440 68/push "F - test-subx-assort/7"/imm32 441 68/push "4 5/imm32"/imm32 442 68/push _test-output-stream/imm32 443 # . . call 444 e8/call check-next-stream-line-equal/disp32 445 # . . discard args 446 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 447 # . epilogue 448 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 449 5d/pop-to-ebp 450 c3/return 451 452 read-segments: # in: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)}) 453 # pseudocode: 454 # var curr-segment: (addr stream byte) = 0 455 # var line: (stream byte 512) 456 # while true 457 # clear-stream(line) 458 # read-line-buffered(in, line) 459 # if (line->write == 0) break # end of file 460 # var word-slice = next-word-or-string(line) 461 # if slice-empty?(word-slice) # whitespace 462 # continue 463 # if slice-starts-with?(word-slice, "#") # comment 464 # continue 465 # if slice-equal?(word-slice, "==") 466 # var segment-name = next-word-or-string(line) 467 # var segment-slot: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16) 468 # if *segment-slot != 0 469 # curr-segment = lookup(*segment-slot) 470 # continue 471 # new-stream(Heap, Segment-size, 1, segment-slot) 472 # curr-segment = lookup(*segment-slot) 473 # rewind-stream(line) 474 # write-stream(curr-segment, line) # abort if curr-segment overflows 475 # 476 # word-slice and segment-name are both slices with disjoint lifetimes, so 477 # we'll use the same address for them. 478 # 479 # registers: 480 # line: ecx 481 # word-slice and segment-name: edx 482 # segment-name and curr-segment: ebx 483 # word-slice->start: esi 484 # temporary: eax 485 # 486 # . prologue 487 55/push-ebp 488 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 489 # . save registers 490 50/push-eax 491 51/push-ecx 492 52/push-edx 493 53/push-ebx 494 56/push-esi 495 57/push-edi 496 # var line/ecx: (stream byte 512) 497 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp 498 68/push 0x200/imm32/length 499 68/push 0/imm32/read 500 68/push 0/imm32/write 501 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 502 # var word-slice/edx: slice 503 68/push 0/imm32/end 504 68/push 0/imm32/start 505 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 506 $read-segments:loop: 507 # clear-stream(line) 508 # . . push args 509 51/push-ecx 510 # . . call 511 e8/call clear-stream/disp32 512 # . . discard args 513 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 514 # read-line-buffered(in, line) 515 # . . push args 516 51/push-ecx 517 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 518 # . . call 519 e8/call read-line-buffered/disp32 520 # . . discard args 521 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 522 $read-segments:check0: 523 # if (line->write == 0) break 524 81 7/subop/compare 0/mod/indirect 1/rm32/ecx . . . . . 0/imm32 # compare *ecx 525 0f 84/jump-if-= $read-segments:break/disp32 526 +-- 33 lines: #? # dump line -------------------------------------------------------------------------------------------------------------------------------------------------------- 559 # next-word-or-string(line, word-slice) 560 # . . push args 561 52/push-edx 562 51/push-ecx 563 # . . call 564 e8/call next-word-or-string/disp32 565 # . . discard args 566 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 567 $read-segments:check1: 568 +-- 9 lines: #? # print("check1\n") ------------------------------------------------------------------------------------------------------------------------------------------------ 577 # if (slice-empty?(word-slice)) continue 578 # . eax = slice-empty?(word-slice) 579 # . . push args 580 52/push-edx 581 # . . call 582 e8/call slice-empty?/disp32 583 # . . discard args 584 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 585 # . if (eax != false) continue 586 3d/compare-eax-and 0/imm32/false 587 0f 85/jump-if-!= $read-segments:loop/disp32 588 $read-segments:check-for-comment: 589 +-- 9 lines: #? # print("check for comment\n") ------------------------------------------------------------------------------------------------------------------------------------- 598 # if (slice-starts-with?(word-slice, "#")) continue 599 # . var start/esi: (addr byte) = word-slice->start 600 8b/copy 0/mod/indirect 2/rm32/edx . . . 6/r32/esi . . # copy *ecx to esi 601 # . var c/eax: byte = *start 602 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 603 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL 604 # . if (c == '#') continue 605 3d/compare-eax-and 0x23/imm32/hash 606 0f 84/jump-if-= $read-segments:loop/disp32 607 $read-segments:check-for-segment-header: 608 +-- 9 lines: #? # print("check for segment header\n") ------------------------------------------------------------------------------------------------------------------------------ 617 +-- 40 lines: #? # dump word-slice -------------------------------------------------------------------------------------------------------------------------------------------------- 657 # if !slice-equal?(word-slice, "==") goto next check 658 # . eax = slice-equal?(word-slice, "==") 659 # . . push args 660 68/push "=="/imm32 661 52/push-edx 662 # . . call 663 e8/call slice-equal?/disp32 664 # . . discard args 665 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 666 # . if (eax == false) goto next check 667 3d/compare-eax-and 0/imm32/false 668 0f 84/jump-if-= $read-segments:regular-line/disp32 669 # segment-name = next-word-or-string(line) 670 # . . push args 671 52/push-edx 672 51/push-ecx 673 # . . call 674 e8/call next-word-or-string/disp32 675 # . . discard args 676 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 677 +-- 40 lines: #? # dump segment name ------------------------------------------------------------------------------------------------------------------------------------------------ 717 # var segment-slot/edi: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16, Heap) 718 # . eax = get-or-insert-slice(table, segment-name, row-size=16, Heap) 719 # . . push args 720 68/push Heap/imm32 721 68/push 0x10/imm32/row-size 722 52/push-edx 723 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 724 # . . call 725 e8/call get-or-insert-slice/disp32 726 # . . discard args 727 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 728 # . edi = eax 729 89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi 730 +-- 33 lines: #? # print("slot: " segment-slot "\n") -------------------------------------------------------------------------------------------------------------------------------- 763 # if (*segment-slot != 0) update curr-segment and continue 764 81 7/subop/compare 0/mod/indirect 7/rm32/edi . . . . . 0/imm32 # compare edi 765 0f 84/jump-if-= $read-segments:create-segment/disp32 766 # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot) 767 # . eax = lookup(*segment-slot) 768 # . . push args 769 ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4) 770 ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi 771 # . . call 772 e8/call lookup/disp32 773 # . . discard args 774 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 775 # . ebx = eax 776 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 777 # continue 778 e9/jump $read-segments:loop/disp32 779 $read-segments:create-segment: 780 # new-stream(Heap, Segment-size, 1, segment-slot) 781 # . . push args 782 57/push-edi 783 68/push 1/imm32 784 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size 785 68/push Heap/imm32 786 # . . call 787 e8/call new-stream/disp32 788 # . . discard args 789 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 790 # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot) 791 # . eax = lookup(*segment-slot) 792 # . . push args 793 ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4) 794 ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi 795 # . . call 796 e8/call lookup/disp32 797 # . . discard args 798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 799 # . ebx = eax 800 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 801 # fall through 802 $read-segments:regular-line: 803 +-- 9 lines: #? # print("regular line\n") ------------------------------------------------------------------------------------------------------------------------------------------ 812 +-- 33 lines: #? # dump line -------------------------------------------------------------------------------------------------------------------------------------------------------- 845 +-- 33 lines: #? # print("addr: " curr-segment->write "\n") ------------------------------------------------------------------------------------------------------------------------- 878 +-- 33 lines: #? # print("write: " curr-segment->write "\n") ------------------------------------------------------------------------------------------------------------------------ 911 +-- 33 lines: #? # print("size: " curr-segment->size "\n") -------------------------------------------------------------------------------------------------------------------------- 944 # rewind-stream(line) 945 # . . push args 946 51/push-ecx 947 # . . call 948 e8/call rewind-stream/disp32 949 # . . discard args 950 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 951 +-- 9 lines: #? # print("write stream\n") ------------------------------------------------------------------------------------------------------------------------------------------ 960 # write-stream(curr-segment, line) 961 # . . push args 962 51/push-ecx 963 53/push-ebx 964 # . . call 965 e8/call write-stream/disp32 966 # . . discard args 967 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 968 # loop 969 +-- 9 lines: #? # print("loop\n") -------------------------------------------------------------------------------------------------------------------------------------------------- 978 e9/jump $read-segments:loop/disp32 979 $read-segments:break: 980 $read-segments:end: 981 # . reclaim locals 982 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x214/imm32 # add to esp 983 # . restore registers 984 5f/pop-to-edi 985 5e/pop-to-esi 986 5b/pop-to-ebx 987 5a/pop-to-edx 988 59/pop-to-ecx 989 58/pop-to-eax 990 # . epilogue 991 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 992 5d/pop-to-ebp 993 c3/return 994 995 write-segments: # out: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)}) 996 # pseudocode: 997 # var curr = table->data 998 # var max = &table->data[table->write] 999 # while curr < max 1000 # var stream: (addr stream byte) = lookup(table[i].stream) 1001 # write-stream-data(out, stream) 1002 # curr += 16 1003 # flush(out) 1004 # 1005 # . prologue 1006 55/push-ebp 1007 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1008 # . save registers 1009 50/push-eax 1010 52/push-edx 1011 56/push-esi 1012 # esi = table 1013 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 1014 # var write/edx: int = table->write 1015 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1016 # var curr/esi: (addr byte) = table->data 1017 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0xc/imm32 # add to eax 1018 # var max/edx: (addr byte) = curr + write 1019 01/add 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # add esi to edx 1020 $write-segments:loop: 1021 # if (curr >= max) break 1022 39/compare 3/mod/direct 6/rm32/esi . . . 2/r32/edx . . # compare esi with edx 1023 73/jump-if-addr>= $write-segments:break/disp8 1024 # var stream/eax: (addr stream byte) = lookup(table[i].stream) 1025 # . . push args 1026 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 0xc/disp8 . # push *(esi+12) 1027 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 8/disp8 . # push *(esi+8) 1028 # . . call 1029 e8/call lookup/disp32 1030 # . . discard args 1031 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1032 # write-stream-data(out, stream) 1033 # . . push args 1034 50/push-eax 1035 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1036 # . . call 1037 e8/call write-stream-data/disp32 1038 # . . discard args 1039 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1040 $write-segments:continue: 1041 # curr += 16 1042 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0x10/imm32 # add to esi 1043 eb/jump $write-segments:loop/disp8 1044 $write-segments:break: 1045 # flush(out) 1046 # . . push args 1047 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1048 # . . call 1049 e8/call flush/disp32 1050 # . . discard args 1051 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1052 $write-segments:end: 1053 # . restore registers 1054 5e/pop-to-esi 1055 5a/pop-to-edx 1056 58/pop-to-eax 1057 # . epilogue 1058 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1059 5d/pop-to-ebp 1060 c3/return 1061 1062 # . . vim:nowrap:textwidth=0