https://github.com/akkartik/mu/blob/main/linux/sigils.subx
   1 # Syntax sugar for addressing modes that expand into /rm32 and other related
   2 # arguments.
   3 #
   4 # To run:
   5 #   $ bootstrap/bootstrap translate [012]*.subx subx-params.subx sigils.subx  -o sigils
   6 #
   7 # We currently support the following notations:
   8 #
   9 # 1.
  10 #   $ echo '%eax'  |  bootstrap/bootstrap run sigils
  11 #   3/mod 0/rm32
  12 #
  13 # 2.
  14 #   $ echo '*eax'  |  bootstrap/bootstrap run sigils
  15 #   0/mod 0/rm32
  16 #
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
*~
*.pyc
*.pyo
stuff/*
eNr"> 66 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size 67 # . . call 68 e8/call new-segment/disp32 69 # . . discard args 70 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 71 72 # - if argc > 1 and argv[1] == "test", then return run_tests() 73 # if (argc <= 1) goto interactive 74 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp 75 7e/jump-if-<= $subx-sigils-main:interactive/disp8 76 # if (!kernel-string-equal?(argv[1], "test")) goto interactive 77 # . eax = kernel-string-equal?(argv[1], "test") 78 # . . push args 79 68/push "test"/imm32 80 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 81 # . . call 82 e8/call kernel-string-equal?/disp32 83 # . . discard args 84 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 85 # . if (eax == false) goto interactive 86 3d/compare-eax-and 0/imm32/false 87 74/jump-if-= $subx-sigils-main:interactive/disp8 88 # run-tests() 89 e8/call run-tests/disp32 90 # syscall_exit(*Num-test-failures) 91 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx 92 eb/jump $subx-sigils-main:end/disp8 93 $subx-sigils-main:interactive: 94 # - otherwise convert stdin 95 # subx-sigils(Stdin, Stdout) 96 # . . push args 97 68/push Stdout/imm32 98 68/push Stdin/imm32 99 # . . call 100 e8/call subx-sigils/disp32 101 # . . discard args 102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 103 # syscall_exit(0) 104 bb/copy-to-ebx 0/imm32 105 $subx-sigils-main:end: 106 e8/call syscall_exit/disp32 107 108 # error messages considered: 109 # *x + 34 -> error: base+disp addressing must be within '()' 110 subx-sigils: # in: (addr buffered-file), out: (addr buffered-file) 111 # pseudocode: 112 # var line: (stream byte 512) 113 # while true 114 # clear-stream(line) 115 # read-line-buffered(in, line) 116 # if (line->write == 0) break # end of file 117 # while true 118 # var word-slice = next-word-or-expression(line) 119 # if slice-empty?(word-slice) # end of line 120 # break 121 # if slice-starts-with?(word-slice, "#") # comment 122 # continue 123 # if slice-starts-with?(word-slice, '%') # direct mode 124 # emit-direct-mode(out, word-slice) 125 # else if slice-starts-with?(word-slice, '*') # indirect mode 126 # if disp32-mode?(word-slice) 127 # emit-indirect-disp32(out, word-slice) 128 # else 129 # base, index, scale, disp = parse-effective-address(word-slice) 130 # emit-indirect-mode(out, base, index, scale, disp) 131 # else if slice-starts-with?(word-slice, '+') 132 # abort("'+' only permitted within '*(...)'") 133 # else 134 # write-slice-buffered(out, word-slice) 135 # write(out, " ") 136 # write(out, "\n") 137 # flush(out) 138 # 139 # . prologue 140 55/push-ebp 141 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 142 # . save registers 143 50/push-eax 144 51/push-ecx 145 52/push-edx 146 53/push-ebx 147 # var line/ecx: (stream byte 512) 148 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp 149 68/push 0x200/imm32/length 150 68/push 0/imm32/read 151 68/push 0/imm32/write 152 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 153 # var word-slice/edx: slice 154 68/push 0/imm32/end 155 68/push 0/imm32/start 156 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 157 $subx-sigils:line-loop: 158 # clear-stream(line) 159 # . . push args 160 51/push-ecx 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 # read-line-buffered(in, line) 166 # . . push args 167 51/push-ecx 168 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 169 # . . call 170 e8/call read-line-buffered/disp32 171 # . . discard args 172 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 173 $subx-sigils:check0: 174 # if (line->write == 0) break 175 81 7/subop/compare 0/mod/indirect 1/rm32/ecx . . . . . 0/imm32 # compare *ecx 176 0f 84/jump-if-= $subx-sigils:break/disp32 177 $subx-sigils:word-loop: 178 # next-word-or-expression(line, word-slice) 179 # . . push args 180 52/push-edx 181 51/push-ecx 182 # . . call 183 e8/call next-word-or-expression/disp32 184 # . . discard args 185 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 186 $subx-sigils:check1: 187 # if (slice-empty?(word-slice)) break 188 # . eax = slice-empty?(word-slice) 189 # . . push args 190 52/push-edx 191 # . . call 192 e8/call slice-empty?/disp32 193 # . . discard args 194 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 195 # . if (eax != false) break 196 3d/compare-eax-and 0/imm32/false 197 0f 85/jump-if-!= $subx-sigils:next-line/disp32 198 $subx-sigils:check-for-comment: 199 # if (slice-starts-with?(word-slice, "#")) continue 200 # . start/ebx = word-slice->start 201 8b/copy 0/mod/indirect 2/rm32/edx . . . 3/r32/ebx . . # copy *edx to ebx 202 # . c/eax = *start 203 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 204 8a/copy-byte 0/mod/indirect 3/rm32/ebx . . . 0/r32/AL . . # copy byte at *ebx to AL 205 # . if (eax == '#') continue 206 3d/compare-eax-and 0x23/imm32/hash 207 74/jump-if-= $subx-sigils:word-loop/disp8 208 $subx-sigils:check-for-direct-mode: 209 # if (!slice-starts-with?(word-slice, "%")) goto next check 210 3d/compare-eax-and 0x25/imm32/percent 211 75/jump-if-!= $subx-sigils:check-for-indirect-mode/disp8 212 $subx-sigils:direct-mode: 213 +-- 40 lines: #? # dump word-slice -------------------------------------------------------------------------------------------------------------------------------------------------- 253 # emit-direct-mode(out, word-slice) 254 # . . push args 255 52/push-edx 256 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 257 # . . call 258 e8/call emit-direct-mode/disp32 259 # . . discard args 260 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 261 # continue 262 e9/jump $subx-sigils:next-word/disp32 263 $subx-sigils:check-for-indirect-mode: 264 # if (!slice-starts-with?(word-slice, "*")) goto next check 265 3d/compare-eax-and 0x2a/imm32/asterisk 266 75/jump-if-!= $subx-sigils:check-for-invalid-addition/disp8 267 # if (!disp32-mode?(word-slice)) goto indirect mode 268 # . eax = disp32-mode?(word-slice) 269 # . . push args 270 52/push-edx 271 # . . call 272 e8/call disp32-mode?/disp32 273 # . . discard args 274 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 275 # . if (eax == false) goto indirect mode 276 3d/compare-eax-and 0/imm32/false 277 74/jump-if-= $subx-sigils:indirect-mode/disp8 278 $subx-sigils:disp32-mode: 279 # emit-indirect-mode(out, word-slice) 280 # . . push args 281 52/push-edx 282 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 283 # . . call 284 e8/call emit-indirect-disp32/disp32 285 # . . discard args 286 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 287 # continue 288 e9/jump $subx-sigils:next-word/disp32 289 $subx-sigils:indirect-mode: 290 # spill registers 291 50/push-eax 292 51/push-ecx 293 52/push-edx 294 53/push-ebx 295 # base/eax, index/ecx, scale/edx, disp/ebx = parse-effective-address(word-slice) 296 # . . push args 297 52/push-edx 298 # . . call 299 e8/call parse-effective-address/disp32 300 # . . discard args 301 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 302 # emit-indirect-mode(out, base, index, scale, disp) 303 # . . push args 304 53/push-ebx 305 52/push-edx 306 51/push-ecx 307 50/push-eax 308 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 309 # . . call 310 e8/call emit-indirect-mode/disp32 311 # . . discard args 312 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 313 # restore registers 314 5b/pop-to-ebx 315 5a/pop-to-edx 316 59/pop-to-ecx 317 58/pop-to-eax 318 # continue 319 e9/jump $subx-sigils:next-word/disp32 320 $subx-sigils:check-for-invalid-addition: 321 # if (slice-starts-with?(word-slice, "+")) goto error1 322 3d/compare-eax-and 0x2b/imm32/plus 323 74/jump-if-= $subx-sigils:error1/disp8 324 $subx-sigils:check-for-invalid-left-shift: 325 # if (slice-starts-with?(word-slice, "<")) goto error1 326 3d/compare-eax-and 0x3c/imm32/less-than 327 74/jump-if-= $subx-sigils:error1/disp8 328 $subx-sigils:regular-word: 329 # write-slice-buffered(out, word-slice) 330 # . . push args 331 52/push-edx 332 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 333 # . . call 334 e8/call write-slice-buffered/disp32 335 # . . discard args 336 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 337 # fall through 338 $subx-sigils:next-word: 339 # write-buffered(out, " ") 340 # . . push args 341 68/push Space/imm32 342 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 343 # . . call 344 e8/call write-buffered/disp32 345 # . . discard args 346 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 347 # loop 348 e9/jump $subx-sigils:word-loop/disp32 349 $subx-sigils:next-line: 350 # write-buffered(out, "\n") 351 # . . push args 352 68/push Newline/imm32 353 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 354 # . . call 355 e8/call write-buffered/disp32 356 # . . discard args 357 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 358 # loop 359 e9/jump $subx-sigils:line-loop/disp32 360 $subx-sigils:break: 361 # flush(out) 362 # . . push args 363 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 364 # . . call 365 e8/call flush/disp32 366 # . . discard args 367 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 368 $subx-sigils:end: 369 # . reclaim locals 370 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x214/imm32 # add to esp 371 # . restore registers 372 5b/pop-to-ebx 373 5a/pop-to-edx 374 59/pop-to-ecx 375 58/pop-to-eax 376 # . epilogue 377 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 378 5d/pop-to-ebp 379 c3/return 380 381 $subx-sigils:error1: 382 # print(stderr, "error: '" eax "' only permitted within '*(...)' in '" line "'") 383 # . write-buffered(Stderr, "error: '") 384 # . . push args 385 68/push "error: '"/imm32 386 68/push Stderr/imm32 387 # . . call 388 e8/call write-buffered/disp32 389 # . . discard args 390 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 391 # . write-byte-buffered(Stderr, eax) 392 # . . push args 393 50/push-eax 394 68/push Stderr/imm32 395 # . . call 396 e8/call write-byte-buffered/disp32 397 # . . discard args 398 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 399 # . write-buffered(Stderr, "' only permitted within '*(...)' in '") 400 # . . push args 401 68/push "' only permitted within '*(...)' in '"/imm32 402 68/push Stderr/imm32 403 # . . call 404 e8/call write-buffered/disp32 405 # . . discard args 406 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 407 # . write-stream-data(Stderr, line) 408 # . . push args 409 51/push-ecx 410 68/push Stderr/imm32 411 # . . call 412 e8/call write-stream-data/disp32 413 # . . discard args 414 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 415 # . write-buffered(Stderr, "'") 416 # . . push args 417 68/push "'"/imm32 418 68/push Stderr/imm32 419 # . . call 420 e8/call write-buffered/disp32 421 # . . discard args 422 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 423 # . flush(Stderr) 424 # . . push args 425 68/push Stderr/imm32 426 # . . call 427 e8/call flush/disp32 428 # . . discard args 429 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 430 # . syscall_exit(1) 431 bb/copy-to-ebx 1/imm32 432 e8/call syscall_exit/disp32 433 # never gets here 434 435 test-subx-sigils-passes-most-words-through: 436 # . prologue 437 55/push-ebp 438 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 439 # setup 440 # . clear-stream(_test-input-stream) 441 # . . push args 442 68/push _test-input-stream/imm32 443 # . . call 444 e8/call clear-stream/disp32 445 # . . discard args 446 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 447 # . clear-stream($_test-input-buffered-file->buffer) 448 # . . push args 449 68/push $_test-input-buffered-file->buffer/imm32 450 # . . call 451 e8/call clear-stream/disp32 452 # . . discard args 453 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 454 # . clear-stream(_test-output-stream) 455 # . . push args 456 68/push _test-output-stream/imm32 457 # . . call 458 e8/call clear-stream/disp32 459 # . . discard args 460 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 461 # . clear-stream($_test-output-buffered-file->buffer) 462 # . . push args 463 68/push $_test-output-buffered-file->buffer/imm32 464 # . . call 465 e8/call clear-stream/disp32 466 # . . discard args 467 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 468 # initialize input 469 # . write(_test-input-stream, "== abcd 0x1") 470 # . . push args 471 68/push "== abcd 0x1"/imm32 472 68/push _test-input-stream/imm32 473 # . . call 474 e8/call write/disp32 475 # . . discard args 476 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 477 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 478 # . . push args 479 68/push _test-output-buffered-file/imm32 480 68/push _test-input-buffered-file/imm32 481 # . . call 482 e8/call subx-sigils/disp32 483 # . . discard args 484 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 485 # check that the line just passed through 486 # . flush(_test-output-buffered-file) 487 # . . push args 488 68/push _test-output-buffered-file/imm32 489 # . . call 490 e8/call flush/disp32 491 # . . discard args 492 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 493 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 519 # . check-stream-equal(_test-output-stream, "== abcd 0x1 \n", msg) 520 # . . push args 521 68/push "F - test-subx-sigils-passes-most-words-through"/imm32 522 68/push "== abcd 0x1 \n"/imm32 523 68/push _test-output-stream/imm32 524 # . . call 525 e8/call check-stream-equal/disp32 526 # . . discard args 527 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 528 # . epilogue 529 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 530 5d/pop-to-ebp 531 c3/return 532 533 test-subx-sigils-direct-mode: 534 # . prologue 535 55/push-ebp 536 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 537 # setup 538 # . clear-stream(_test-input-stream) 539 # . . push args 540 68/push _test-input-stream/imm32 541 # . . call 542 e8/call clear-stream/disp32 543 # . . discard args 544 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 545 # . clear-stream($_test-input-buffered-file->buffer) 546 # . . push args 547 68/push $_test-input-buffered-file->buffer/imm32 548 # . . call 549 e8/call clear-stream/disp32 550 # . . discard args 551 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 552 # . clear-stream(_test-output-stream) 553 # . . push args 554 68/push _test-output-stream/imm32 555 # . . call 556 e8/call clear-stream/disp32 557 # . . discard args 558 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 559 # . clear-stream($_test-output-buffered-file->buffer) 560 # . . push args 561 68/push $_test-output-buffered-file->buffer/imm32 562 # . . call 563 e8/call clear-stream/disp32 564 # . . discard args 565 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 566 # initialize input 567 # . write(_test-input-stream, "ab %ecx") 568 # . . push args 569 68/push "ab %ecx"/imm32 570 68/push _test-input-stream/imm32 571 # . . call 572 e8/call write/disp32 573 # . . discard args 574 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 575 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 576 # . . push args 577 68/push _test-output-buffered-file/imm32 578 68/push _test-input-buffered-file/imm32 579 # . . call 580 e8/call subx-sigils/disp32 581 # . . discard args 582 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 583 # check that the line just passed through 584 # . flush(_test-output-buffered-file) 585 # . . push args 586 68/push _test-output-buffered-file/imm32 587 # . . call 588 e8/call flush/disp32 589 # . . discard args 590 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 591 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 617 # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg) 618 # . . push args 619 68/push "F - test-subx-sigils-direct-mode"/imm32 620 68/push "ab 3/mod/direct 0x00000001/rm32 \n"/imm32 621 68/push _test-output-stream/imm32 622 # . . call 623 e8/call check-stream-equal/disp32 624 # . . discard args 625 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 626 # . epilogue 627 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 628 5d/pop-to-ebp 629 c3/return 630 631 test-subx-sigils-direct-mode-with-metadata: 632 # . prologue 633 55/push-ebp 634 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 635 # setup 636 # . clear-stream(_test-input-stream) 637 # . . push args 638 68/push _test-input-stream/imm32 639 # . . call 640 e8/call clear-stream/disp32 641 # . . discard args 642 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 643 # . clear-stream($_test-input-buffered-file->buffer) 644 # . . push args 645 68/push $_test-input-buffered-file->buffer/imm32 646 # . . call 647 e8/call clear-stream/disp32 648 # . . discard args 649 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 650 # . clear-stream(_test-output-stream) 651 # . . push args 652 68/push _test-output-stream/imm32 653 # . . call 654 e8/call clear-stream/disp32 655 # . . discard args 656 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 657 # . clear-stream($_test-output-buffered-file->buffer) 658 # . . push args 659 68/push $_test-output-buffered-file->buffer/imm32 660 # . . call 661 e8/call clear-stream/disp32 662 # . . discard args 663 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 664 # initialize input 665 # . write(_test-input-stream, "ab %ecx/foo") 666 # . . push args 667 68/push "ab %ecx/foo"/imm32 668 68/push _test-input-stream/imm32 669 # . . call 670 e8/call write/disp32 671 # . . discard args 672 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 673 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 674 # . . push args 675 68/push _test-output-buffered-file/imm32 676 68/push _test-input-buffered-file/imm32 677 # . . call 678 e8/call subx-sigils/disp32 679 # . . discard args 680 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 681 # check that the line just passed through 682 # . flush(_test-output-buffered-file) 683 # . . push args 684 68/push _test-output-buffered-file/imm32 685 # . . call 686 e8/call flush/disp32 687 # . . discard args 688 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 689 # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg) 690 # . . push args 691 68/push "F - test-subx-sigils-direct-mode-with-metadata"/imm32 692 68/push "ab 3/mod/direct 0x00000001/rm32 \n"/imm32 693 68/push _test-output-stream/imm32 694 # . . call 695 e8/call check-stream-equal/disp32 696 # . . discard args 697 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 698 # . epilogue 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 test-subx-sigils-register-indirect-mode: 704 # . prologue 705 55/push-ebp 706 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 707 # setup 708 # . clear-stream(_test-input-stream) 709 # . . push args 710 68/push _test-input-stream/imm32 711 # . . call 712 e8/call clear-stream/disp32 713 # . . discard args 714 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 715 # . clear-stream($_test-input-buffered-file->buffer) 716 # . . push args 717 68/push $_test-input-buffered-file->buffer/imm32 718 # . . call 719 e8/call clear-stream/disp32 720 # . . discard args 721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 722 # . clear-stream(_test-output-stream) 723 # . . push args 724 68/push _test-output-stream/imm32 725 # . . call 726 e8/call clear-stream/disp32 727 # . . discard args 728 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 729 # . clear-stream($_test-output-buffered-file->buffer) 730 # . . push args 731 68/push $_test-output-buffered-file->buffer/imm32 732 # . . call 733 e8/call clear-stream/disp32 734 # . . discard args 735 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 736 # initialize input 737 # . write(_test-input-stream, "ab *ecx") 738 # . . push args 739 68/push "ab *ecx"/imm32 740 68/push _test-input-stream/imm32 741 # . . call 742 e8/call write/disp32 743 # . . discard args 744 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 745 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 746 # . . push args 747 68/push _test-output-buffered-file/imm32 748 68/push _test-input-buffered-file/imm32 749 # . . call 750 e8/call subx-sigils/disp32 751 # . . discard args 752 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 753 # check that the line just passed through 754 # . flush(_test-output-buffered-file) 755 # . . push args 756 68/push _test-output-buffered-file/imm32 757 # . . call 758 e8/call flush/disp32 759 # . . discard args 760 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 761 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 787 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg) 788 # . . push args 789 68/push "F - test-subx-sigils-register-indirect-mode"/imm32 790 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32 791 68/push _test-output-stream/imm32 792 # . . call 793 e8/call check-stream-equal/disp32 794 # . . discard args 795 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 796 # . epilogue 797 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 798 5d/pop-to-ebp 799 c3/return 800 801 test-subx-sigils-register-indirect-mode-with-metadata: 802 # . prologue 803 55/push-ebp 804 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 805 # setup 806 # . clear-stream(_test-input-stream) 807 # . . push args 808 68/push _test-input-stream/imm32 809 # . . call 810 e8/call clear-stream/disp32 811 # . . discard args 812 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 813 # . clear-stream($_test-input-buffered-file->buffer) 814 # . . push args 815 68/push $_test-input-buffered-file->buffer/imm32 816 # . . call 817 e8/call clear-stream/disp32 818 # . . discard args 819 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 820 # . clear-stream(_test-output-stream) 821 # . . push args 822 68/push _test-output-stream/imm32 823 # . . call 824 e8/call clear-stream/disp32 825 # . . discard args 826 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 827 # . clear-stream($_test-output-buffered-file->buffer) 828 # . . push args 829 68/push $_test-output-buffered-file->buffer/imm32 830 # . . call 831 e8/call clear-stream/disp32 832 # . . discard args 833 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 834 # initialize input 835 # . write(_test-input-stream, "ab *ecx/foo") 836 # . . push args 837 68/push "ab *ecx/foo"/imm32 838 68/push _test-input-stream/imm32 839 # . . call 840 e8/call write/disp32 841 # . . discard args 842 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 843 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 844 # . . push args 845 68/push _test-output-buffered-file/imm32 846 68/push _test-input-buffered-file/imm32 847 # . . call 848 e8/call subx-sigils/disp32 849 # . . discard args 850 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 851 # check that the line just passed through 852 # . flush(_test-output-buffered-file) 853 # . . push args 854 68/push _test-output-buffered-file/imm32 855 # . . call 856 e8/call flush/disp32 857 # . . discard args 858 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 859 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg) 860 # . . push args 861 68/push "F - test-subx-sigils-register-indirect-mode-with-metadata"/imm32 862 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32 863 68/push _test-output-stream/imm32 864 # . . call 865 e8/call check-stream-equal/disp32 866 # . . discard args 867 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 868 # . epilogue 869 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 870 5d/pop-to-ebp 871 c3/return 872 873 test-subx-sigils-register-indirect-mode-without-displacement: 874 # . prologue 875 55/push-ebp 876 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 877 # setup 878 # . clear-stream(_test-input-stream) 879 # . . push args 880 68/push _test-input-stream/imm32 881 # . . call 882 e8/call clear-stream/disp32 883 # . . discard args 884 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 885 # . clear-stream($_test-input-buffered-file->buffer) 886 # . . push args 887 68/push $_test-input-buffered-file->buffer/imm32 888 # . . call 889 e8/call clear-stream/disp32 890 # . . discard args 891 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 892 # . clear-stream(_test-output-stream) 893 # . . push args 894 68/push _test-output-stream/imm32 895 # . . call 896 e8/call clear-stream/disp32 897 # . . discard args 898 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 899 # . clear-stream($_test-output-buffered-file->buffer) 900 # . . push args 901 68/push $_test-output-buffered-file->buffer/imm32 902 # . . call 903 e8/call clear-stream/disp32 904 # . . discard args 905 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 906 # initialize input 907 # . write(_test-input-stream, "ab *(ecx)") 908 # . . push args 909 68/push "ab *(ecx)"/imm32 910 68/push _test-input-stream/imm32 911 # . . call 912 e8/call write/disp32 913 # . . discard args 914 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 915 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 916 # . . push args 917 68/push _test-output-buffered-file/imm32 918 68/push _test-input-buffered-file/imm32 919 # . . call 920 e8/call subx-sigils/disp32 921 # . . discard args 922 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 923 # check that the line just passed through 924 # . flush(_test-output-buffered-file) 925 # . . push args 926 68/push _test-output-buffered-file/imm32 927 # . . call 928 e8/call flush/disp32 929 # . . discard args 930 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 931 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 957 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 1/rm32 \n", msg) 958 # . . push args 959 68/push "F - test-subx-sigils-register-indirect-mode-without-displacement"/imm32 960 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32 961 68/push _test-output-stream/imm32 962 # . . call 963 e8/call check-stream-equal/disp32 964 # . . discard args 965 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 966 # . epilogue 967 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 968 5d/pop-to-ebp 969 c3/return 970 971 test-subx-sigils-register-indirect-mode-with-displacement: 972 # . prologue 973 55/push-ebp 974 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 975 # setup 976 # . clear-stream(_test-input-stream) 977 # . . push args 978 68/push _test-input-stream/imm32 979 # . . call 980 e8/call clear-stream/disp32 981 # . . discard args 982 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 983 # . clear-stream($_test-input-buffered-file->buffer) 984 # . . push args 985 68/push $_test-input-buffered-file->buffer/imm32 986 # . . call 987 e8/call clear-stream/disp32 988 # . . discard args 989 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 990 # . clear-stream(_test-output-stream) 991 # . . push args 992 68/push _test-output-stream/imm32 993 # . . call 994 e8/call clear-stream/disp32 995 # . . discard args 996 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 997 # . clear-stream($_test-output-buffered-file->buffer) 998 # . . push args 999 68/push $_test-output-buffered-file->buffer/imm32 1000 # . . call 1001 e8/call clear-stream/disp32 1002 # . . discard args 1003 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1004 # initialize input 1005 # . write(_test-input-stream, "ab *(ecx+4)") 1006 # . . push args 1007 68/push "ab *(ecx+4)"/imm32 1008 68/push _test-input-stream/imm32 1009 # . . call 1010 e8/call write/disp32 1011 # . . discard args 1012 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1013 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 1014 # . . push args 1015 68/push _test-output-buffered-file/imm32 1016 68/push _test-input-buffered-file/imm32 1017 # . . call 1018 e8/call subx-sigils/disp32 1019 # . . discard args 1020 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1021 # check that the line just passed through 1022 # . flush(_test-output-buffered-file) 1023 # . . push args 1024 68/push _test-output-buffered-file/imm32 1025 # . . call 1026 e8/call flush/disp32 1027 # . . discard args 1028 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1029 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 1055 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 1/rm32 4/disp32 \n", msg) 1056 # . . push args 1057 68/push "F - test-subx-sigils-register-indirect-mode-with-displacement"/imm32 1058 68/push "ab 2/mod/*+disp32 0x00000001/rm32 0x00000004/disp32 \n"/imm32 1059 68/push _test-output-stream/imm32 1060 # . . call 1061 e8/call check-stream-equal/disp32 1062 # . . discard args 1063 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1064 # . epilogue 1065 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1066 5d/pop-to-ebp 1067 c3/return 1068 1069 # boss level 1070 test-subx-sigils-register-indirect-mode-with-sib-byte: 1071 # . prologue 1072 55/push-ebp 1073 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1074 # setup 1075 # . clear-stream(_test-input-stream) 1076 # . . push args 1077 68/push _test-input-stream/imm32 1078 # . . call 1079 e8/call clear-stream/disp32 1080 # . . discard args 1081 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1082 # . clear-stream($_test-input-buffered-file->buffer) 1083 # . . push args 1084 68/push $_test-input-buffered-file->buffer/imm32 1085 # . . call 1086 e8/call clear-stream/disp32 1087 # . . discard args 1088 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1089 # . clear-stream(_test-output-stream) 1090 # . . push args 1091 68/push _test-output-stream/imm32 1092 # . . call 1093 e8/call clear-stream/disp32 1094 # . . discard args 1095 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1096 # . clear-stream($_test-output-buffered-file->buffer) 1097 # . . push args 1098 68/push $_test-output-buffered-file->buffer/imm32 1099 # . . call 1100 e8/call clear-stream/disp32 1101 # . . discard args 1102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1103 # initialize input 1104 # . write(_test-input-stream, "ab *(ecx + edx<<3 + 4)") 1105 # . . push args 1106 68/push "ab *(ecx + edx<<3 + 4)"/imm32 1107 68/push _test-input-stream/imm32 1108 # . . call 1109 e8/call write/disp32 1110 # . . discard args 1111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1112 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 1113 # . . push args 1114 68/push _test-output-buffered-file/imm32 1115 68/push _test-input-buffered-file/imm32 1116 # . . call 1117 e8/call subx-sigils/disp32 1118 # . . discard args 1119 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1120 # check that the line just passed through 1121 # . flush(_test-output-buffered-file) 1122 # . . push args 1123 68/push _test-output-buffered-file/imm32 1124 # . . call 1125 e8/call flush/disp32 1126 # . . discard args 1127 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1128 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 1154 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale 4/disp32 \n", msg) 1155 # . . push args 1156 68/push "F - test-subx-sigils-register-indirect-mode-with-sib-byte"/imm32 1157 68/push "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0x00000004/disp32 \n"/imm32 1158 68/push _test-output-stream/imm32 1159 # . . call 1160 e8/call check-stream-equal/disp32 1161 # . . discard args 1162 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1163 # . epilogue 1164 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1165 5d/pop-to-ebp 1166 c3/return 1167 1168 test-subx-sigils-register-indirect-mode-with-sib-byte-negative-displacement: 1169 # . prologue 1170 55/push-ebp 1171 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1172 # setup 1173 # . clear-stream(_test-input-stream) 1174 # . . push args 1175 68/push _test-input-stream/imm32 1176 # . . call 1177 e8/call clear-stream/disp32 1178 # . . discard args 1179 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1180 # . clear-stream($_test-input-buffered-file->buffer) 1181 # . . push args 1182 68/push $_test-input-buffered-file->buffer/imm32 1183 # . . call 1184 e8/call clear-stream/disp32 1185 # . . discard args 1186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1187 # . clear-stream(_test-output-stream) 1188 # . . push args 1189 68/push _test-output-stream/imm32 1190 # . . call 1191 e8/call clear-stream/disp32 1192 # . . discard args 1193 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1194 # . clear-stream($_test-output-buffered-file->buffer) 1195 # . . push args 1196 68/push $_test-output-buffered-file->buffer/imm32 1197 # . . call 1198 e8/call clear-stream/disp32 1199 # . . discard args 1200 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1201 # initialize input 1202 # . write(_test-input-stream, "ab *(ecx + edx<<3 - 4)") 1203 # . . push args 1204 68/push "ab *(ecx + edx<<3 - 4)"/imm32 1205 68/push _test-input-stream/imm32 1206 # . . call 1207 e8/call write/disp32 1208 # . . discard args 1209 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1210 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 1211 # . . push args 1212 68/push _test-output-buffered-file/imm32 1213 68/push _test-input-buffered-file/imm32 1214 # . . call 1215 e8/call subx-sigils/disp32 1216 # . . discard args 1217 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1218 # check that the line just passed through 1219 # . flush(_test-output-buffered-file) 1220 # . . push args 1221 68/push _test-output-buffered-file/imm32 1222 # . . call 1223 e8/call flush/disp32 1224 # . . discard args 1225 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1226 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 1252 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale -4/disp32 \n", msg) 1253 # . . push args 1254 68/push "F - test-subx-sigils-register-indirect-mode-with-sib-byte-negative-displacement"/imm32 1255 68/push "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0xfffffffc/disp32 \n"/imm32 1256 68/push _test-output-stream/imm32 1257 # . . call 1258 e8/call check-stream-equal/disp32 1259 # . . discard args 1260 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1261 # . epilogue 1262 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1263 5d/pop-to-ebp 1264 c3/return 1265 1266 test-subx-sigils-indirect-mode-without-register: 1267 # . prologue 1268 55/push-ebp 1269 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1270 # setup 1271 # . clear-stream(_test-input-stream) 1272 # . . push args 1273 68/push _test-input-stream/imm32 1274 # . . call 1275 e8/call clear-stream/disp32 1276 # . . discard args 1277 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1278 # . clear-stream($_test-input-buffered-file->buffer) 1279 # . . push args 1280 68/push $_test-input-buffered-file->buffer/imm32 1281 # . . call 1282 e8/call clear-stream/disp32 1283 # . . discard args 1284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1285 # . clear-stream(_test-output-stream) 1286 # . . push args 1287 68/push _test-output-stream/imm32 1288 # . . call 1289 e8/call clear-stream/disp32 1290 # . . discard args 1291 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1292 # . clear-stream($_test-output-buffered-file->buffer) 1293 # . . push args 1294 68/push $_test-output-buffered-file->buffer/imm32 1295 # . . call 1296 e8/call clear-stream/disp32 1297 # . . discard args 1298 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1299 # initialize input 1300 # . write(_test-input-stream, "ab *Foo") 1301 # . . push args 1302 68/push "ab *Foo"/imm32 1303 68/push _test-input-stream/imm32 1304 # . . call 1305 e8/call write/disp32 1306 # . . discard args 1307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1308 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file) 1309 # . . push args 1310 68/push _test-output-buffered-file/imm32 1311 68/push _test-input-buffered-file/imm32 1312 # . . call 1313 e8/call subx-sigils/disp32 1314 # . . discard args 1315 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1316 # check that the line just passed through 1317 # . flush(_test-output-buffered-file) 1318 # . . push args 1319 68/push _test-output-buffered-file/imm32 1320 # . . call 1321 e8/call flush/disp32 1322 # . . discard args 1323 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1324 +-- 26 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 1350 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 5/rm32/.disp32 Foo/disp32 \n", msg) 1351 # . . push args 1352 68/push "F - test-subx-sigils-indirect-mode-without-register"/imm32 1353 68/push "ab 0/mod/indirect 5/rm32/.disp32 Foo/disp32 \n"/imm32 1354 68/push _test-output-stream/imm32 1355 # . . call 1356 e8/call check-stream-equal/disp32 1357 # . . discard args 1358 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1359 # . epilogue 1360 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1361 5d/pop-to-ebp 1362 c3/return 1363 1364 emit-direct-mode: # out: (addr buffered-file), word-slice: (addr slice) 1365 # . prologue 1366 55/push-ebp 1367 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1368 # . save registers 1369 50/push-eax 1370 # var local-slice/eax: slice = {word-slice->start, word-slice->end} 1371 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax 1372 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) 1373 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax 1374 89/copy 3/mod/direct 0/rm32/eax . . . 4/r32/esp . . # copy esp to eax 1375 # ++local-slice->start to skip '%' 1376 # . ++(*eax) 1377 ff 0/subop/increment 0/mod/indirect 0/rm32/eax . . . . . . # increment *eax 1378 +-- 24 lines: #? # write-slice-buffered(Stderr, word-slice) ------------------------------------------------------------------------------------------------------------------------- 1402 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/") 1403 # . . push args 1404 50/push-eax 1405 68/push 0x2f/imm32/slash 1406 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) 1407 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax 1408 # . . call 1409 e8/call next-token-from-slice/disp32 1410 # . . discard args 1411 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1412 # reg-num/eax = get-slice(Registers, local-slice, row-size=12) 1413 # . . push args 1414 68/push "Registers"/imm32 1415 68/push 0xc/imm32/row-size 1416 50/push-eax 1417 68/push Registers/imm32 1418 # . . call 1419 e8/call get-slice/disp32 1420 # . . discard args 1421 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1422 # write-buffered(out, "3/mod/direct ") 1423 # . . push args 1424 68/push "3/mod/direct "/imm32 1425 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1426 # . . call 1427 e8/call write-buffered/disp32 1428 # . . discard args 1429 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1430 # write-int32-hex-buffered(out, *reg-num) 1431 # . . push args 1432 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax 1433 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1434 # . . call 1435 e8/call write-int32-hex-buffered/disp32 1436 # . . discard args 1437 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1438 # write-buffered(out, "/rm32") 1439 # . . push args 1440 68/push "/rm32"/imm32 1441 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1442 # . . call 1443 e8/call write-buffered/disp32 1444 # . . discard args 1445 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1446 $emit-direct-mode:end: 1447 # . reclaim locals 1448 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1449 # . restore registers 1450 58/pop-to-eax 1451 # . epilogue 1452 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1453 5d/pop-to-ebp 1454 c3/return 1455 1456 test-emit-direct-mode: 1457 # . prologue 1458 55/push-ebp 1459 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1460 # setup 1461 # . clear-stream(_test-output-stream) 1462 # . . push args 1463 68/push _test-output-stream/imm32 1464 # . . call 1465 e8/call clear-stream/disp32 1466 # . . discard args 1467 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1468 # . clear-stream($_test-output-buffered-file->buffer) 1469 # . . push args 1470 68/push $_test-output-buffered-file->buffer/imm32 1471 # . . call 1472 e8/call clear-stream/disp32 1473 # . . discard args 1474 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1475 # var slice/ecx = "%eax" 1476 b8/copy-to-eax "%eax"/imm32 1477 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1478 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1479 05/add-to-eax 4/imm32 1480 # . ecx = {eax, ecx} 1481 51/push-ecx 1482 50/push-eax 1483 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1484 # emit-direct-mode(_test-output-buffered-file, str) 1485 # . . push args 1486 51/push-ecx 1487 68/push _test-output-buffered-file/imm32 1488 # . . call 1489 e8/call emit-direct-mode/disp32 1490 # . . discard args 1491 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1492 # . flush(_test-output-buffered-file) 1493 # . . push args 1494 68/push _test-output-buffered-file/imm32 1495 # . . call 1496 e8/call flush/disp32 1497 # . . discard args 1498 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1499 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 1525 # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg) 1526 # . . push args 1527 68/push "F - test-emit-direct-mode/0"/imm32 1528 68/push "3/mod/direct 0x00000000/rm32"/imm32 1529 68/push _test-output-stream/imm32 1530 # . . call 1531 e8/call check-stream-equal/disp32 1532 # . . discard args 1533 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1534 # . epilogue 1535 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1536 5d/pop-to-ebp 1537 c3/return 1538 1539 test-emit-direct-mode-2: 1540 # . prologue 1541 55/push-ebp 1542 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1543 # setup 1544 # . clear-stream(_test-output-stream) 1545 # . . push args 1546 68/push _test-output-stream/imm32 1547 # . . call 1548 e8/call clear-stream/disp32 1549 # . . discard args 1550 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1551 # . clear-stream($_test-output-buffered-file->buffer) 1552 # . . push args 1553 68/push $_test-output-buffered-file->buffer/imm32 1554 # . . call 1555 e8/call clear-stream/disp32 1556 # . . discard args 1557 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1558 # var slice/ecx = "%edi" 1559 b8/copy-to-eax "%edi"/imm32 1560 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1561 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1562 05/add-to-eax 4/imm32 1563 # . ecx = {eax, ecx} 1564 51/push-ecx 1565 50/push-eax 1566 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1567 # emit-direct-mode(_test-output-buffered-file, str/ecx) 1568 # . . push args 1569 51/push-ecx 1570 68/push _test-output-buffered-file/imm32 1571 # . . call 1572 e8/call emit-direct-mode/disp32 1573 # . . discard args 1574 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1575 # . flush(_test-output-buffered-file) 1576 # . . push args 1577 68/push _test-output-buffered-file/imm32 1578 # . . call 1579 e8/call flush/disp32 1580 # . . discard args 1581 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1582 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 1608 # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg) 1609 # . . push args 1610 68/push "F - test-emit-direct-mode/1"/imm32 1611 68/push "3/mod/direct 0x00000007/rm32"/imm32 1612 68/push _test-output-stream/imm32 1613 # . . call 1614 e8/call check-stream-equal/disp32 1615 # . . discard args 1616 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1617 # . epilogue 1618 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1619 5d/pop-to-ebp 1620 c3/return 1621 1622 # (re)compute the bounds of the next word or parenthetical expression in the line 1623 # return empty string on reaching end of file 1624 # 1625 # error messages considered: 1626 # * ... -> error: no space after '*' 1627 # *(... -> error: *(...) expression must be all on a single line 1628 next-word-or-expression: # line: (addr stream byte), out: (addr slice) 1629 # pseudocode: 1630 # skip-chars-matching(line, ' ') 1631 # if line->read >= line->write # end of line 1632 # out = {0, 0} 1633 # return 1634 # out->start = &line->data[line->read] 1635 # if line->data[line->read] == '#' # comment 1636 # out.end = &line->data[line->write] 1637 # return 1638 # if line->data[line->read] == '"' # string literal 1639 # skip-string(line) 1640 # else if line->data[line->read] == '*' # expression 1641 # if line->data[line->read + 1] == ' ' 1642 # abort 1643 # if line->data[line->read + 1] == '(' 1644 # skip-until-close-paren(line) 1645 # if (line->data[line->read] != ')' 1646 # abort 1647 # ++line->data[line->read] to skip ')' 1648 # skip-chars-not-matching-whitespace(line) 1649 # out->end = &line->data[line->read] 1650 # 1651 # registers: 1652 # ecx: often line->read 1653 # eax: often line->data[line->read] 1654 # 1655 # . prologue 1656 55/push-ebp 1657 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1658 # . save registers 1659 50/push-eax 1660 51/push-ecx 1661 56/push-esi 1662 57/push-edi 1663 # esi = line 1664 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1665 # edi = out 1666 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi 1667 # skip-chars-matching(line, ' ') 1668 # . . push args 1669 68/push 0x20/imm32/space 1670 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1671 # . . call 1672 e8/call skip-chars-matching/disp32 1673 # . . discard args 1674 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1675 $next-word-or-expression:check0: 1676 # if (line->read >= line->write) clear out and return 1677 # . ecx = line->read 1678 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx 1679 # . if (ecx < line->write) goto next check 1680 3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi 1681 7c/jump-if-< $next-word-or-expression:check-for-comment/disp8 1682 # . return out = {0, 0} 1683 c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi 1684 c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4) 1685 e9/jump $next-word-or-expression:end/disp32 1686 $next-word-or-expression:check-for-comment: 1687 # out->start = &line->data[line->read] 1688 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 1689 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi 1690 # if (line->data[line->read] != '#') goto next check 1691 # . eax = line->data[line->read] 1692 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 1693 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 1694 # . if (eax != '#') goto next check 1695 3d/compare-eax-and 0x23/imm32/pound 1696 75/jump-if-!= $next-word-or-expression:check-for-string-literal/disp8 1697 $next-word-or-expression:comment: 1698 # out->end = &line->data[line->write] 1699 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 1700 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 1701 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) 1702 # line->read = line->write # skip rest of line 1703 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 1704 89/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy eax to *(esi+4) 1705 # return 1706 eb/jump $next-word-or-expression:end/disp8 1707 $next-word-or-expression:check-for-string-literal: 1708 # if (line->data[line->read] != '"') goto next check 1709 3d/compare-eax-and 0x22/imm32/dquote 1710 75/jump-if-!= $next-word-or-expression:check-for-expression/disp8 1711 $next-word-or-expression:string-literal: 1712 # skip-string(line) 1713 # . . push args 1714 56/push-esi 1715 # . . call 1716 e8/call skip-string/disp32 1717 # . . discard args 1718 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1719 # skip rest of word 1720 eb/jump $next-word-or-expression:regular-word/disp8 1721 $next-word-or-expression:check-for-expression: 1722 # if (line->data[line->read] != '*') goto next check 1723 3d/compare-eax-and 0x2a/imm32/asterisk 1724 75/jump-if-!= $next-word-or-expression:regular-word/disp8 1725 # if (line->data[line->read + 1] == ' ') goto error1 1726 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xd/disp8 . # copy byte at *(esi+ecx+12+1) to AL 1727 3d/compare-eax-and 0x20/imm32/space 1728 74/jump-if-= $next-word-or-expression:error1/disp8 1729 # if (line->data[line->read + 1] != '(') goto regular word 1730 3d/compare-eax-and 0x28/imm32/open-paren 1731 75/jump-if-!= $next-word-or-expression:regular-word/disp8 1732 $next-word-or-expression:paren: 1733 # skip-until-close-paren(line) 1734 # . . push args 1735 56/push-esi 1736 # . . call 1737 e8/call skip-until-close-paren/disp32 1738 # . . discard args 1739 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1740 # if (line->data[line->read] != ')') goto error2 1741 # . eax = line->data[line->read] 1742 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx 1743 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 1744 # . if (eax != ')') goto error2 1745 3d/compare-eax-and 0x29/imm32/close-paren 1746 75/jump-if-!= $next-word-or-expression:error2/disp8 1747 # skip ')' 1748 ff 0/subop/increment 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # increment *(esi+4) 1749 # fall through 1750 $next-word-or-expression:regular-word: 1751 # skip-chars-not-matching-whitespace(line) # including trailing newline 1752 # . . push args 1753 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1754 # . . call 1755 e8/call skip-chars-not-matching-whitespace/disp32 1756 # . . discard args 1757 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1758 # out->end = &line->data[line->read] 1759 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx 1760 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 1761 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) 1762 $next-word-or-expression:end: 1763 # . restore registers 1764 5f/pop-to-edi 1765 5e/pop-to-esi 1766 59/pop-to-ecx 1767 58/pop-to-eax 1768 # . epilogue 1769 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1770 5d/pop-to-ebp 1771 c3/return 1772 1773 $next-word-or-expression:error1: 1774 # print(stderr, "error: no space allowed after '*' in '" line "'") 1775 # . write-buffered(Stderr, "error: no space allowed after '*' in '") 1776 # . . push args 1777 68/push "error: no space allowed after '*' in '"/imm32 1778 68/push Stderr/imm32 1779 # . . call 1780 e8/call write-buffered/disp32 1781 # . . discard args 1782 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1783 # . write-stream-data(Stderr, line) 1784 # . . push args 1785 56/push-esi 1786 68/push Stderr/imm32 1787 # . . call 1788 e8/call write-stream-data/disp32 1789 # . . discard args 1790 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1791 # . write-buffered(Stderr, "'") 1792 # . . push args 1793 68/push "'"/imm32 1794 68/push Stderr/imm32 1795 # . . call 1796 e8/call write-buffered/disp32 1797 # . . discard args 1798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1799 # . flush(Stderr) 1800 # . . push args 1801 68/push Stderr/imm32 1802 # . . call 1803 e8/call flush/disp32 1804 # . . discard args 1805 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1806 # . syscall_exit(1) 1807 bb/copy-to-ebx 1/imm32 1808 e8/call syscall_exit/disp32 1809 # never gets here 1810 1811 $next-word-or-expression:error2: 1812 # print(stderr, "error: *(...) expression must be all on a single line in '" line "'") 1813 # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '") 1814 # . . push args 1815 68/push "error: *(...) expression must be all on a single line in '"/imm32 1816 68/push Stderr/imm32 1817 # . . call 1818 e8/call write-buffered/disp32 1819 # . . discard args 1820 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1821 # . write-stream-data(Stderr, line) 1822 # . . push args 1823 56/push-esi 1824 68/push Stderr/imm32 1825 # . . call 1826 e8/call write-stream-data/disp32 1827 # . . discard args 1828 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1829 # . write-buffered(Stderr, "'") 1830 # . . push args 1831 68/push "'"/imm32 1832 68/push Stderr/imm32 1833 # . . call 1834 e8/call write-buffered/disp32 1835 # . . discard args 1836 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1837 # . flush(Stderr) 1838 # . . push args 1839 68/push Stderr/imm32 1840 # . . call 1841 e8/call flush/disp32 1842 # . . discard args 1843 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1844 # . syscall_exit(1) 1845 bb/copy-to-ebx 1/imm32 1846 e8/call syscall_exit/disp32 1847 # never gets here 1848 1849 test-next-word-or-expression: 1850 # . prologue 1851 55/push-ebp 1852 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1853 # setup 1854 # . clear-stream(_test-input-stream) 1855 # . . push args 1856 68/push _test-input-stream/imm32 1857 # . . call 1858 e8/call clear-stream/disp32 1859 # . . discard args 1860 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1861 # var slice/ecx: slice 1862 68/push 0/imm32/end 1863 68/push 0/imm32/start 1864 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1865 # write(_test-input-stream, " ab") 1866 # . . push args 1867 68/push " ab"/imm32 1868 68/push _test-input-stream/imm32 1869 # . . call 1870 e8/call write/disp32 1871 # . . discard args 1872 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1873 # next-word-or-expression(_test-input-stream, slice) 1874 # . . push args 1875 51/push-ecx 1876 68/push _test-input-stream/imm32 1877 # . . call 1878 e8/call next-word-or-expression/disp32 1879 # . . discard args 1880 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1881 # check-ints-equal(_test-input-stream->read, 4, msg) 1882 # . . push args 1883 68/push "F - test-next-word-or-expression/updates-stream-read-correctly"/imm32 1884 68/push 4/imm32 1885 b8/copy-to-eax _test-input-stream/imm32 1886 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) 1887 # . . call 1888 e8/call check-ints-equal/disp32 1889 # . . discard args 1890 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1891 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) 1892 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) 1893 # . . push args 1894 68/push "F - test-next-word-or-expression: start"/imm32 1895 68/push 0xe/imm32 1896 # . . push slice->start - _test-input-stream 1897 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 1898 2d/subtract-from-eax _test-input-stream/imm32 1899 50/push-eax 1900 # . . call 1901 e8/call check-ints-equal/disp32 1902 # . . discard args 1903 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1904 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) 1905 # . check-ints-equal(slice->end - _test-input-stream, 16, msg) 1906 # . . push args 1907 68/push "F - test-next-word-or-expression: end"/imm32 1908 68/push 0x10/imm32 1909 # . . push slice->end - _test-input-stream 1910 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 1911 2d/subtract-from-eax _test-input-stream/imm32 1912 50/push-eax 1913 # . . call 1914 e8/call check-ints-equal/disp32 1915 # . . discard args 1916 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1917 # . epilogue 1918 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1919 5d/pop-to-ebp 1920 c3/return 1921 1922 test-next-word-or-expression-returns-whole-comment: 1923 # . prologue 1924 55/push-ebp 1925 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1926 # setup 1927 # . clear-stream(_test-input-stream) 1928 # . . push args 1929 68/push _test-input-stream/imm32 1930 # . . call 1931 e8/call clear-stream/disp32 1932 # . . discard args 1933 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1934 # var slice/ecx: slice 1935 68/push 0/imm32/end 1936 68/push 0/imm32/start 1937 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1938 # write(_test-input-stream, " # a") 1939 # . . push args 1940 68/push " # a"/imm32 1941 68/push _test-input-stream/imm32 1942 # . . call 1943 e8/call write/disp32 1944 # . . discard args 1945 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1946 # next-word-or-expression(_test-input-stream, slice) 1947 # . . push args 1948 51/push-ecx 1949 68/push _test-input-stream/imm32 1950 # . . call 1951 e8/call next-word-or-expression/disp32 1952 # . . discard args 1953 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1954 # check-ints-equal(_test-input-stream->read, 5, msg) 1955 # . . push args 1956 68/push "F - test-next-word-or-expression-returns-whole-comment/updates-stream-read-correctly"/imm32 1957 68/push 5/imm32 1958 b8/copy-to-eax _test-input-stream/imm32 1959 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) 1960 # . . call 1961 e8/call check-ints-equal/disp32 1962 # . . discard args 1963 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1964 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) 1965 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) 1966 # . . push args 1967 68/push "F - test-next-word-or-expression-returns-whole-comment: start"/imm32 1968 68/push 0xe/imm32 1969 # . . push slice->start - _test-input-stream 1970 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 1971 2d/subtract-from-eax _test-input-stream/imm32 1972 50/push-eax 1973 # . . call 1974 e8/call check-ints-equal/disp32 1975 # . . discard args 1976 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1977 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) 1978 # . check-ints-equal(slice->end - _test-input-stream, 17, msg) 1979 # . . push args 1980 68/push "F - test-next-word-or-expression-returns-whole-comment: end"/imm32 1981 68/push 0x11/imm32 1982 # . . push slice->end - _test-input-stream 1983 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 1984 2d/subtract-from-eax _test-input-stream/imm32 1985 50/push-eax 1986 # . . call 1987 e8/call check-ints-equal/disp32 1988 # . . discard args 1989 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1990 # . epilogue 1991 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1992 5d/pop-to-ebp 1993 c3/return 1994 1995 test-next-word-or-expression-returns-empty-slice-on-eof: 1996 # . prologue 1997 55/push-ebp 1998 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1999 # setup 2000 # . clear-stream(_test-input-stream) 2001 # . . push args 2002 68/push _test-input-stream/imm32 2003 # . . call 2004 e8/call clear-stream/disp32 2005 # . . discard args 2006 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2007 # var slice/ecx: slice 2008 68/push 0/imm32/end 2009 68/push 0/imm32/start 2010 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2011 # write nothing to _test-input-stream 2012 # next-word-or-expression(_test-input-stream, slice) 2013 # . . push args 2014 51/push-ecx 2015 68/push _test-input-stream/imm32 2016 # . . call 2017 e8/call next-word-or-expression/disp32 2018 # . . discard args 2019 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2020 # check-ints-equal(slice->end - slice->start, 0, msg) 2021 # . . push args 2022 68/push "F - test-next-word-or-expression-returns-empty-expression-on-eof"/imm32 2023 68/push 0/imm32 2024 # . . push slice->end - slice->start 2025 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 2026 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax 2027 50/push-eax 2028 # . . call 2029 e8/call check-ints-equal/disp32 2030 # . . discard args 2031 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2032 # . epilogue 2033 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2034 5d/pop-to-ebp 2035 c3/return 2036 2037 test-next-word-or-expression-returns-string-literal: 2038 # . prologue 2039 55/push-ebp 2040 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2041 # setup 2042 # . clear-stream(_test-input-stream) 2043 # . . push args 2044 68/push _test-input-stream/imm32 2045 # . . call 2046 e8/call clear-stream/disp32 2047 # . . discard args 2048 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2049 # var slice/ecx: slice 2050 68/push 0/imm32/end 2051 68/push 0/imm32/start 2052 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2053 # write(_test-input-stream, " \"a b\"/imm32 ") 2054 # . . push args 2055 68/push " \"a b\"/imm32 "/imm32 2056 68/push _test-input-stream/imm32 2057 # . . call 2058 e8/call write/disp32 2059 # . . discard args 2060 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2061 # next-word-or-expression(_test-input-stream, slice) 2062 # . . push args 2063 51/push-ecx 2064 68/push _test-input-stream/imm32 2065 # . . call 2066 e8/call next-word-or-expression/disp32 2067 # . . discard args 2068 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2069 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) 2070 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) 2071 # . . push args 2072 68/push "F - test-next-word-or-expression-returns-string-literal: start"/imm32 2073 68/push 0xd/imm32 2074 # . . push slice->start - _test-input-stream 2075 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 2076 2d/subtract-from-eax _test-input-stream/imm32 2077 50/push-eax 2078 # . . call 2079 e8/call check-ints-equal/disp32 2080 # . . discard args 2081 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2082 # check-ints-equal(slice->end - _test-input-stream->data, 12, msg) 2083 # . check-ints-equal(slice->end - _test-input-stream, 24, msg) 2084 # . . push args 2085 68/push "F - test-next-word-or-expression-returns-string-literal: end"/imm32 2086 68/push 0x18/imm32 2087 # . . push slice->end - _test-input-stream 2088 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 2089 2d/subtract-from-eax _test-input-stream/imm32 2090 50/push-eax 2091 # . . call 2092 e8/call check-ints-equal/disp32 2093 # . . discard args 2094 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2095 # . epilogue 2096 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2097 5d/pop-to-ebp 2098 c3/return 2099 2100 test-next-word-or-expression-returns-string-with-escapes: 2101 # . prologue 2102 55/push-ebp 2103 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2104 # setup 2105 # . clear-stream(_test-input-stream) 2106 # . . push args 2107 68/push _test-input-stream/imm32 2108 # . . call 2109 e8/call clear-stream/disp32 2110 # . . discard args 2111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2112 # var slice/ecx: slice 2113 68/push 0/imm32/end 2114 68/push 0/imm32/start 2115 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2116 # write(_test-input-stream, " \"a\\\"b\"/x") 2117 # . . push args 2118 68/push " \"a\\\"b\"/x"/imm32 2119 68/push _test-input-stream/imm32 2120 # . . call 2121 e8/call write/disp32 2122 # . . discard args 2123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2124 # next-word-or-expression(_test-input-stream, slice) 2125 # . . push args 2126 51/push-ecx 2127 68/push _test-input-stream/imm32 2128 # . . call 2129 e8/call next-word-or-expression/disp32 2130 # . . discard args 2131 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2132 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) 2133 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) 2134 # . . push args 2135 68/push "F - test-next-word-or-expression-returns-string-with-escapes: start"/imm32 2136 68/push 0xd/imm32 2137 # . . push slice->start - _test-input-stream 2138 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 2139 2d/subtract-from-eax _test-input-stream/imm32 2140 50/push-eax 2141 # . . call 2142 e8/call check-ints-equal/disp32 2143 # . . discard args 2144 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2145 # check-ints-equal(slice->end - _test-input-stream->data, 9, msg) 2146 # . check-ints-equal(slice->end - _test-input-stream, 21, msg) 2147 # . . push args 2148 68/push "F - test-next-word-or-expression-returns-string-with-escapes: end"/imm32 2149 68/push 0x15/imm32 2150 # . . push slice->end - _test-input-stream 2151 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 2152 2d/subtract-from-eax _test-input-stream/imm32 2153 50/push-eax 2154 # . . call 2155 e8/call check-ints-equal/disp32 2156 # . . discard args 2157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2158 # . epilogue 2159 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2160 5d/pop-to-ebp 2161 c3/return 2162 2163 test-next-word-or-expression-returns-whole-expression: 2164 # . prologue 2165 55/push-ebp 2166 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2167 # setup 2168 # . clear-stream(_test-input-stream) 2169 # . . push args 2170 68/push _test-input-stream/imm32 2171 # . . call 2172 e8/call clear-stream/disp32 2173 # . . discard args 2174 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2175 # var slice/ecx: slice 2176 68/push 0/imm32/end 2177 68/push 0/imm32/start 2178 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2179 # write(_test-input-stream, " *(a b)/imm32 ") 2180 # . . push args 2181 68/push " *(a b)/imm32 "/imm32 2182 68/push _test-input-stream/imm32 2183 # . . call 2184 e8/call write/disp32 2185 # . . discard args 2186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2187 # next-word-or-expression(_test-input-stream, slice) 2188 # . . push args 2189 51/push-ecx 2190 68/push _test-input-stream/imm32 2191 # . . call 2192 e8/call next-word-or-expression/disp32 2193 # . . discard args 2194 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2195 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) 2196 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) 2197 # . . push args 2198 68/push "F - test-next-word-or-expression-returns-whole-expression: start"/imm32 2199 68/push 0xd/imm32 2200 # . . push slice->start - _test-input-stream 2201 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 2202 2d/subtract-from-eax _test-input-stream/imm32 2203 50/push-eax 2204 # . . call 2205 e8/call check-ints-equal/disp32 2206 # . . discard args 2207 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2208 # check-ints-equal(slice->end - _test-input-stream->data, 13, msg) 2209 # . check-ints-equal(slice->end - _test-input-stream, 25, msg) 2210 # . . push args 2211 68/push "F - test-next-word-or-expression-returns-whole-expression: end"/imm32 2212 68/push 0x19/imm32 2213 # . . push slice->end - _test-input-stream 2214 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 2215 2d/subtract-from-eax _test-input-stream/imm32 2216 50/push-eax 2217 # . . call 2218 e8/call check-ints-equal/disp32 2219 # . . discard args 2220 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2221 # . epilogue 2222 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2223 5d/pop-to-ebp 2224 c3/return 2225 2226 # Grammar: 2227 # *reg -> 0/mod reg/rm32 2228 # *(reg) -> 0/mod reg/rm32 2229 # *(reg+disp) -> 2/mod reg/rm32 disp/disp32 2230 # *(reg1+reg2<<s) -> 2/mod 4/rm32 reg1/base reg2/index s/scale 0/disp32 2231 # *(reg1+reg2<<s+disp) -> 2/mod 4/rm32 reg1/base reg2/index s/scale disp/disp32 2232 # Intermediate structure: base, index, scale, disp 2233 # Default values: base: 0, index: 4 (none), scale: 0, disp: 0 2234 parse-effective-address: # word-slice: (addr slice) -> base/eax, index/ecx, scale/edx, disp/ebx 2235 # pseudocode: 2236 # var local-slice = {word-slice->start, word-slice->end} 2237 # ++local-slice->start to skip '*' 2238 # initialize defaults: base=0, index=4, scale=0, disp=0 2239 # if (*local-slice->start != '(') { 2240 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/") 2241 # base = get-slice(Registers, local-slice, row-size=12) 2242 # return 2243 # } 2244 # # compound expressions 2245 # skip whitespace 2246 # read register into base 2247 # skip whitespace 2248 # if (*local-slice->start == ')') goto end 2249 # if (*local-slice->start == '-') goto displacement 2250 # if (*local-slice->start != '+') goto error1 2251 # ++local-slice->start to skip '+' 2252 # skip whitespace 2253 # if next 3 characters don't make a register, goto displacement 2254 # read register into index 2255 # skip whitespace 2256 # if (*local-slice->start == ')') goto end 2257 # if (*local-slice->start == '<') { 2258 # ++local-slice->start to skip '<' 2259 # if (*local-slice->start != '<') goto error2 2260 # ++local-slice->start to skip '<' 2261 # skip whitespace 2262 # read integer into scale 2263 # skip whitespace 2264 # if (*local-slice->start == ')') goto end 2265 # } 2266 # if (*local-slice->start not in '+' '-') goto error3 2267 # displacement: 2268 # read integer into disp 2269 # skip whitespace 2270 # if (*local-slice->start != ')') goto error4 2271 # . prologue 2272 55/push-ebp 2273 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2274 # . save registers 2275 56/push-esi 2276 57/push-edi 2277 # var local-slice/esi: slice = {word-slice->start, word-slice->end} 2278 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 2279 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2280 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2281 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi 2282 # ++local-slice->start to skip '*' 2283 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 2284 # initialize defaults 2285 # base is in edi; we'll move it to eax just before we return 2286 bf/copy-to-edi 0/imm32 2287 b9/copy-to-ecx 4/imm32/no-index 2288 ba/copy-to-edx 0/imm32/.scale 2289 bb/copy-to-ebx 0/imm32/disp 2290 $parse-effective-address:check-for-simple-register: 2291 # if (*local-slice->start == '(') goto compound expression 2292 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 2293 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2294 25/and-eax-with 0xff/imm32 2295 3d/compare-eax-and 0x28/imm32/open-paren 2296 74/jump-if-= $parse-effective-address:compound-expression/disp8 2297 $parse-effective-address:simple-register: 2298 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/") 2299 # . . push args 2300 56/push-esi 2301 68/push 0x2f/imm32/slash 2302 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2303 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2304 # . . call 2305 e8/call next-token-from-slice/disp32 2306 # . . discard args 2307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2308 # base = get-slice(Registers, local-slice, row-size=12) 2309 # . eax = get-slice(Registers, local-slice, row-size=12) 2310 # . . push args 2311 68/push "Registers"/imm32 2312 68/push 0xc/imm32/row-size 2313 56/push-esi 2314 68/push Registers/imm32 2315 # . . call 2316 e8/call get-slice/disp32 2317 # . . discard args 2318 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2319 # . base = *eax 2320 8b/copy 0/mod/indirect 0/rm32/eax . . . 7/r32/edi . . # copy *eax to edi 2321 # return 2322 e9/jump $parse-effective-address:end/disp32 2323 $parse-effective-address:compound-expression: 2324 # ++local-slice->start to skip '(' 2325 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 2326 # skip whitespace 2327 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2328 # . . push args 2329 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2330 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2331 # . . call 2332 e8/call skip-chars-matching-whitespace-in-slice/disp32 2333 # . . discard args 2334 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2335 # . local-slice->start = eax 2336 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2337 # read register into base 2338 # . eax = next-register(local-slice) 2339 # . . push args 2340 56/push-esi 2341 # . . call 2342 e8/call next-register/disp32 2343 # . . discard args 2344 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2345 # . edi = *eax 2346 8b/copy 0/mod/indirect 0/rm32/eax . . . 7/r32/edi . . # copy *eax to edi 2347 # skip whitespace 2348 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2349 # . . push args 2350 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2351 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2352 # . . call 2353 e8/call skip-chars-matching-whitespace-in-slice/disp32 2354 # . . discard args 2355 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2356 # . local-slice->start = eax 2357 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2358 # if (*local-slice->start == ')') goto end 2359 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2360 25/and-eax-with 0xff/imm32 2361 3d/compare-eax-and 0x29/imm32/close-paren 2362 0f 84/jump-if-= $parse-effective-address:end/disp32 2363 # if (*local-slice->start == '-') goto displacement 2364 3d/compare-eax-and 0x2d/imm32/minus 2365 0f 84/jump-if-= $parse-effective-address:displacement/disp32 2366 # if (*local-slice->start != '+') goto error1 2367 3d/compare-eax-and 0x2b/imm32/plus 2368 0f 85/jump-if-!= $parse-effective-address:error1/disp32 2369 $parse-effective-address:check-for-index: 2370 # ++local-slice->start to skip '+' 2371 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 2372 # skip whitespace 2373 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2374 # . . push args 2375 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2376 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2377 # . . call 2378 e8/call skip-chars-matching-whitespace-in-slice/disp32 2379 # . . discard args 2380 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2381 # . local-slice->start = eax 2382 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2383 $parse-effective-address:resolve-ambiguity: 2384 # if next 3 characters don't make a register, goto displacement 2385 # . spill ecx 2386 51/push-ecx 2387 # . var tmp/ecx = {local-slice->start, local-slice->start+3} 2388 # . . ecx = local-slice->start 2389 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx 2390 # . . eax = local-slice->start+3 2391 05/add-to-eax 3/imm32 2392 # . . push 2393 50/push-eax 2394 51/push-ecx 2395 # . . copy esp to ecx 2396 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2397 # . eax = maybe-get-slice(Register, tmp, row-size=12) 2398 # . . push args 2399 68/push 0xc/imm32/row-size 2400 51/push-ecx 2401 68/push Registers/imm32 2402 # . . call 2403 e8/call maybe-get-slice/disp32 2404 # . . discard args 2405 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2406 # . reclaim tmp 2407 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2408 # . restore ecx 2409 59/pop-to-ecx 2410 # . if (eax == 0) goto displacement 2411 3d/compare-eax-and 0/imm32 2412 0f 84/jump-if-= $parse-effective-address:displacement/disp32 2413 $parse-effective-address:index: 2414 # read register into index 2415 # . eax = next-register(local-slice) 2416 # . . push args 2417 56/push-esi 2418 # . . call 2419 e8/call next-register/disp32 2420 # . . discard args 2421 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2422 # . ecx = *eax 2423 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2424 # skip whitespace 2425 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2426 # . . push args 2427 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2428 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2429 # . . call 2430 e8/call skip-chars-matching-whitespace-in-slice/disp32 2431 # . . discard args 2432 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2433 # . local-slice->start = eax 2434 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2435 # if (*local-slice->start == ')') goto end 2436 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2437 25/and-eax-with 0xff/imm32 2438 3d/compare-eax-and 0x29/imm32/close-paren 2439 0f 84/jump-if-= $parse-effective-address:end/disp32 2440 $parse-effective-address:check-for-scale: 2441 # if (*local-slice->start != '<') goto next check 2442 3d/compare-eax-and 0x3c/imm32/less-than 2443 75/jump-if-!= $parse-effective-address:check-for-displacement/disp8 2444 # ++local-slice->start to skip '<' 2445 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 2446 # if (*local-slice->start != '<') goto error2 2447 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 2448 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2449 25/and-eax-with 0xff/imm32 2450 3d/compare-eax-and 0x3c/imm32/less-than 2451 0f 85/jump-if-!= $parse-effective-address:error2/disp32 2452 # ++local-slice->start to skip '<' 2453 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 2454 # skip whitespace 2455 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2456 # . . push args 2457 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2458 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2459 # . . call 2460 e8/call skip-chars-matching-whitespace-in-slice/disp32 2461 # . . discard args 2462 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2463 # . local-slice->start = eax 2464 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2465 $parse-effective-address:scale: 2466 # read positive integer into scale 2467 # . eax = next-positive-hex-int(local-slice) 2468 # . . push args 2469 56/push-esi 2470 # . . call 2471 e8/call next-positive-hex-int/disp32 2472 # . . discard args 2473 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2474 # . edx = eax 2475 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx 2476 # skip whitespace 2477 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2478 # . . push args 2479 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2480 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2481 # . . call 2482 e8/call skip-chars-matching-whitespace-in-slice/disp32 2483 # . . discard args 2484 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2485 # . local-slice->start = eax 2486 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2487 # if (*local-slice->start == ')') goto end 2488 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2489 25/and-eax-with 0xff/imm32 2490 3d/compare-eax-and 0x29/imm32/close-paren 2491 74/jump-if-= $parse-effective-address:end/disp8 2492 $parse-effective-address:check-for-displacement: 2493 # if (*local-slice->start not in '+' '-') goto error3 2494 3d/compare-eax-and 0x2b/imm32/plus 2495 74/jump-if-= $parse-effective-address:displacement/disp8 2496 3d/compare-eax-and 0x2d/imm32/minus 2497 74/jump-if-= $parse-effective-address:displacement/disp8 2498 e9/jump $parse-effective-address:error3/disp32 2499 $parse-effective-address:displacement: 2500 # read integer into disp 2501 # . eax = next-hex-int(local-slice) 2502 # . . push args 2503 56/push-esi 2504 # . . call 2505 e8/call next-hex-int/disp32 2506 # . . discard args 2507 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2508 # . ebx = eax 2509 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 2510 # skip whitespace 2511 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end) 2512 # . . push args 2513 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 2514 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2515 # . . call 2516 e8/call skip-chars-matching-whitespace-in-slice/disp32 2517 # . . discard args 2518 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2519 # . local-slice->start = eax 2520 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi 2521 # if (*local-slice->start != ')') goto error4 2522 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 2523 25/and-eax-with 0xff/imm32 2524 3d/compare-eax-and 0x29/imm32/close-paren 2525 0f 85/jump-if-!= $parse-effective-address:error4/disp32 2526 $parse-effective-address:end: 2527 # return base in eax 2528 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax 2529 # . reclaim locals 2530 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2531 # . restore registers 2532 5f/pop-to-edi 2533 5e/pop-to-esi 2534 # . epilogue 2535 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2536 5d/pop-to-ebp 2537 c3/return 2538 2539 $parse-effective-address:error1: 2540 # print(stderr, "error: unexpected character: " eax "\n") 2541 # . write-buffered(Stderr, "error: unexpected character: ") 2542 # . . push args 2543 68/push "error: unexpected character: "/imm32 2544 68/push Stderr/imm32 2545 # . . call 2546 e8/call write-buffered/disp32 2547 # . . discard args 2548 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2549 # . write-int32-hex-buffered(out, eax) 2550 # . . push args 2551 50/push-eax 2552 68/push Stderr/imm32 2553 # . . call 2554 e8/call write-int32-hex-buffered/disp32 2555 # . . discard args 2556 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2557 # . write-buffered(Stderr, "\n") 2558 # . . push args 2559 68/push Newline/imm32 2560 68/push Stderr/imm32 2561 # . . call 2562 e8/call write-buffered/disp32 2563 # . . discard args 2564 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2565 # . flush(Stderr) 2566 # . . push args 2567 68/push Stderr/imm32 2568 # . . call 2569 e8/call flush/disp32 2570 # . . discard args 2571 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2572 # . syscall_exit(1) 2573 bb/copy-to-ebx 1/imm32 2574 e8/call syscall_exit/disp32 2575 # never gets here 2576 2577 $parse-effective-address:error2: 2578 # print(stderr, "error: '<' can only be followed by '<' but got: " eax "\n") 2579 # . write-buffered(Stderr, "error: '<' can only be followed by '<' but got: ") 2580 # . . push args 2581 68/push "error: '<' can only be followed by '<' but got: "/imm32 2582 68/push Stderr/imm32 2583 # . . call 2584 e8/call write-buffered/disp32 2585 # . . discard args 2586 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2587 # . write-int32-hex-buffered(out, eax) 2588 # . . push args 2589 50/push-eax 2590 68/push Stderr/imm32 2591 # . . call 2592 e8/call write-int32-hex-buffered/disp32 2593 # . . discard args 2594 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2595 # . write-buffered(Stderr, "\n") 2596 # . . push args 2597 68/push Newline/imm32 2598 68/push Stderr/imm32 2599 # . . call 2600 e8/call write-buffered/disp32 2601 # . . discard args 2602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2603 # . flush(Stderr) 2604 # . . push args 2605 68/push Stderr/imm32 2606 # . . call 2607 e8/call flush/disp32 2608 # . . discard args 2609 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2610 # . syscall_exit(1) 2611 bb/copy-to-ebx 1/imm32 2612 e8/call syscall_exit/disp32 2613 # never gets here 2614 2615 $parse-effective-address:error3: 2616 # print(stderr, "error: unexpected character before displacement: " eax "\n") 2617 # . write-buffered(Stderr, "error: unexpected character before displacement: ") 2618 # . . push args 2619 68/push "error: unexpected character before displacement: "/imm32 2620 68/push Stderr/imm32 2621 # . . call 2622 e8/call write-buffered/disp32 2623 # . . discard args 2624 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2625 # . write-int32-hex-buffered(out, eax) 2626 # . . push args 2627 50/push-eax 2628 68/push Stderr/imm32 2629 # . . call 2630 e8/call write-int32-hex-buffered/disp32 2631 # . . discard args 2632 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2633 # . write-buffered(Stderr, "\n") 2634 # . . push args 2635 68/push Newline/imm32 2636 68/push Stderr/imm32 2637 # . . call 2638 e8/call write-buffered/disp32 2639 # . . discard args 2640 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2641 # . flush(Stderr) 2642 # . . push args 2643 68/push Stderr/imm32 2644 # . . call 2645 e8/call flush/disp32 2646 # . . discard args 2647 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2648 # . syscall_exit(1) 2649 bb/copy-to-ebx 1/imm32 2650 e8/call syscall_exit/disp32 2651 # never gets here 2652 2653 $parse-effective-address:error4: 2654 # print(stderr, "error: unexpected character after displacement: " eax "; expected ')' to wrap up\n") 2655 # . write-buffered(Stderr, "error: unexpected character after displacement: ") 2656 # . . push args 2657 68/push "error: unexpected character after displacement: "/imm32 2658 68/push Stderr/imm32 2659 # . . call 2660 e8/call write-buffered/disp32 2661 # . . discard args 2662 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2663 # . write-int32-hex-buffered(out, eax) 2664 # . . push args 2665 50/push-eax 2666 68/push Stderr/imm32 2667 # . . call 2668 e8/call write-int32-hex-buffered/disp32 2669 # . . discard args 2670 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2671 # . write-buffered(Stderr, "; expected ')' to wrap up\n") 2672 # . . push args 2673 68/push "; expected ')' to wrap up\n"/imm32 2674 68/push Stderr/imm32 2675 # . . call 2676 e8/call write-buffered/disp32 2677 # . . discard args 2678 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2679 # . flush(Stderr) 2680 # . . push args 2681 68/push Stderr/imm32 2682 # . . call 2683 e8/call flush/disp32 2684 # . . discard args 2685 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2686 # . syscall_exit(1) 2687 bb/copy-to-ebx 1/imm32 2688 e8/call syscall_exit/disp32 2689 # never gets here 2690 2691 # assumes 'in' starts with a register name, and returns pointer to its code 2692 # side-effect: modifies 'in' to scan past the initial register name 2693 next-register: # in: (addr slice) -> reg/eax: int 2694 # . prologue 2695 55/push-ebp 2696 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2697 # . save registers 2698 51/push-ecx 2699 56/push-esi 2700 # esi = in 2701 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 2702 # var reg-slice/ecx: slice = {in->start, in->start + 3} 2703 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 2704 05/add-to-eax 3/imm32 2705 50/push-eax 2706 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 2707 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2708 # in->start += 3 2709 81 0/subop/add 0/mod/indirect 6/rm32/esi . . . . . 3/imm32 # add to *esi 2710 # eax = get-slice(Registers, reg-slice, row-size=12) 2711 # . . push args 2712 68/push "next-register"/imm32 2713 68/push 0xc/imm32/row-size 2714 51/push-ecx 2715 68/push Registers/imm32 2716 # . . call 2717 e8/call get-slice/disp32 2718 # . . discard args 2719 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2720 $next-register:end: 2721 # . reclaim locals 2722 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2723 # . restore registers 2724 5e/pop-to-esi 2725 59/pop-to-ecx 2726 # . epilogue 2727 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2728 5d/pop-to-ebp 2729 c3/return 2730 2731 test-parse-effective-address-simple: 2732 # . prologue 2733 55/push-ebp 2734 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2735 # var slice/ecx = "*esi" 2736 b8/copy-to-eax "*esi"/imm32 2737 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2738 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 2739 05/add-to-eax 4/imm32 2740 # . ecx = {eax, ecx} 2741 51/push-ecx 2742 50/push-eax 2743 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2744 # eax, ecx, edx, ebx = parse-effective-address(slice) 2745 # . . push args 2746 51/push-ecx 2747 # . . call 2748 e8/call parse-effective-address/disp32 2749 # . . discard args 2750 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2751 # slice clobbered beyond this point 2752 # check-ints-equal(eax, 6, msg) 2753 # . . push args 2754 68/push "F - test-parse-effective-address-simple/base"/imm32 2755 68/push 6/imm32/esi 2756 50/push-eax 2757 # . . call 2758 e8/call check-ints-equal/disp32 2759 # . . discard args 2760 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2761 # check-ints-equal(ecx, 4, msg) 2762 # . . push args 2763 68/push "F - test-parse-effective-address-simple/index"/imm32 2764 68/push 4/imm32/none 2765 51/push-ecx 2766 # . . call 2767 e8/call check-ints-equal/disp32 2768 # . . discard args 2769 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2770 # check-ints-equal(edx, 0, msg) 2771 # . . push args 2772 68/push "F - test-parse-effective-address-simple/scale"/imm32 2773 68/push 0/imm32/none 2774 52/push-edx 2775 # . . call 2776 e8/call check-ints-equal/disp32 2777 # . . discard args 2778 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2779 # check-ints-equal(ebx, 0, msg) 2780 # . . push args 2781 68/push "F - test-parse-effective-address-simple/displacement"/imm32 2782 68/push 0/imm32/none 2783 53/push-ebx 2784 # . . call 2785 e8/call check-ints-equal/disp32 2786 # . . discard args 2787 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2788 # . epilogue 2789 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2790 5d/pop-to-ebp 2791 c3/return 2792 2793 test-parse-effective-address-base: 2794 # . prologue 2795 55/push-ebp 2796 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2797 # var slice/ecx = "*(esi )" 2798 b8/copy-to-eax "*(esi )"/imm32 2799 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2800 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 2801 05/add-to-eax 4/imm32 2802 # . ecx = {eax, ecx} 2803 51/push-ecx 2804 50/push-eax 2805 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2806 # eax, ecx, edx, ebx = parse-effective-address(slice) 2807 # . . push args 2808 51/push-ecx 2809 # . . call 2810 e8/call parse-effective-address/disp32 2811 # . . discard args 2812 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2813 # slice clobbered beyond this point 2814 # check-ints-equal(eax, 6, msg) 2815 # . . push args 2816 68/push "F - test-parse-effective-address-base/base"/imm32 2817 68/push 6/imm32/esi 2818 50/push-eax 2819 # . . call 2820 e8/call check-ints-equal/disp32 2821 # . . discard args 2822 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2823 # check-ints-equal(ecx, 4, msg) 2824 # . . push args 2825 68/push "F - test-parse-effective-address-base/index"/imm32 2826 68/push 4/imm32/none 2827 51/push-ecx 2828 # . . call 2829 e8/call check-ints-equal/disp32 2830 # . . discard args 2831 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2832 # check-ints-equal(edx, 0, msg) 2833 # . . push args 2834 68/push "F - test-parse-effective-address-base/scale"/imm32 2835 68/push 0/imm32/none 2836 52/push-edx 2837 # . . call 2838 e8/call check-ints-equal/disp32 2839 # . . discard args 2840 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2841 # check-ints-equal(ebx, 0, msg) 2842 # . . push args 2843 68/push "F - test-parse-effective-address-base/displacement"/imm32 2844 68/push 0/imm32/none 2845 53/push-ebx 2846 # . . call 2847 e8/call check-ints-equal/disp32 2848 # . . discard args 2849 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2850 # . epilogue 2851 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2852 5d/pop-to-ebp 2853 c3/return 2854 2855 test-parse-effective-address-base-displacement: 2856 # . prologue 2857 55/push-ebp 2858 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2859 # var slice/ecx = "*(esi+3)" 2860 b8/copy-to-eax "*(esi+3)"/imm32 2861 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2862 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 2863 05/add-to-eax 4/imm32 2864 # . ecx = {eax, ecx} 2865 51/push-ecx 2866 50/push-eax 2867 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2868 # eax, ecx, edx, ebx = parse-effective-address(slice) 2869 # . . push args 2870 51/push-ecx 2871 # . . call 2872 e8/call parse-effective-address/disp32 2873 # . . discard args 2874 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2875 # slice clobbered beyond this point 2876 # check-ints-equal(eax, 6, msg) 2877 # . . push args 2878 68/push "F - test-parse-effective-address-base-displacement/base"/imm32 2879 68/push 6/imm32/esi 2880 50/push-eax 2881 # . . call 2882 e8/call check-ints-equal/disp32 2883 # . . discard args 2884 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2885 # check-ints-equal(ecx, 4, msg) 2886 # . . push args 2887 68/push "F - test-parse-effective-address-base-displacement/index"/imm32 2888 68/push 4/imm32/none 2889 51/push-ecx 2890 # . . call 2891 e8/call check-ints-equal/disp32 2892 # . . discard args 2893 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2894 # check-ints-equal(edx, 0, msg) 2895 # . . push args 2896 68/push "F - test-parse-effective-address-base-displacement/scale"/imm32 2897 68/push 0/imm32/none 2898 52/push-edx 2899 # . . call 2900 e8/call check-ints-equal/disp32 2901 # . . discard args 2902 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2903 # check-ints-equal(ebx, 3, msg) 2904 # . . push args 2905 68/push "F - test-parse-effective-address-base-displacement/displacement"/imm32 2906 68/push 3/imm32 2907 53/push-ebx 2908 # . . call 2909 e8/call check-ints-equal/disp32 2910 # . . discard args 2911 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2912 # . epilogue 2913 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2914 5d/pop-to-ebp 2915 c3/return 2916 2917 test-parse-effective-address-base-negative-displacement: 2918 # . prologue 2919 55/push-ebp 2920 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2921 # var slice/ecx = "*(esi-3)" 2922 b8/copy-to-eax "*(esi-3)"/imm32 2923 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2924 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 2925 05/add-to-eax 4/imm32 2926 # . ecx = {eax, ecx} 2927 51/push-ecx 2928 50/push-eax 2929 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2930 # eax, ecx, edx, ebx = parse-effective-address(slice) 2931 # . . push args 2932 51/push-ecx 2933 # . . call 2934 e8/call parse-effective-address/disp32 2935 # . . discard args 2936 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2937 # slice clobbered beyond this point 2938 # check-ints-equal(eax, 6, msg) 2939 # . . push args 2940 68/push "F - test-parse-effective-address-base-negative-displacement/base"/imm32 2941 68/push 6/imm32/esi 2942 50/push-eax 2943 # . . call 2944 e8/call check-ints-equal/disp32 2945 # . . discard args 2946 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2947 # check-ints-equal(ecx, 4, msg) 2948 # . . push args 2949 68/push "F - test-parse-effective-address-base-negative-displacement/index"/imm32 2950 68/push 4/imm32/none 2951 51/push-ecx 2952 # . . call 2953 e8/call check-ints-equal/disp32 2954 # . . discard args 2955 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2956 # check-ints-equal(edx, 0, msg) 2957 # . . push args 2958 68/push "F - test-parse-effective-address-base-negative-displacement/scale"/imm32 2959 68/push 0/imm32/none 2960 52/push-edx 2961 # . . call 2962 e8/call check-ints-equal/disp32 2963 # . . discard args 2964 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2965 # check-ints-equal(ebx, -3, msg) 2966 # . . push args 2967 68/push "F - test-parse-effective-address-base-negative-displacement/displacement"/imm32 2968 68/push -3/imm32 2969 53/push-ebx 2970 # . . call 2971 e8/call check-ints-equal/disp32 2972 # . . discard args 2973 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2974 # . epilogue 2975 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2976 5d/pop-to-ebp 2977 c3/return 2978 2979 test-parse-effective-address-base-index: 2980 # . prologue 2981 55/push-ebp 2982 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2983 # var slice/ecx = "*(esi+ecx)" 2984 b8/copy-to-eax "*(esi+ecx)"/imm32 2985 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 2986 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 2987 05/add-to-eax 4/imm32 2988 # . ecx = {eax, ecx} 2989 51/push-ecx 2990 50/push-eax 2991 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2992 # eax, ecx, edx, ebx = parse-effective-address(slice) 2993 # . . push args 2994 51/push-ecx 2995 # . . call 2996 e8/call parse-effective-address/disp32 2997 # . . discard args 2998 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 2999 # slice clobbered beyond this point 3000 # check-ints-equal(eax, 6, msg) 3001 # . . push args 3002 68/push "F - test-parse-effective-address-base-index/base"/imm32 3003 68/push 6/imm32/esi 3004 50/push-eax 3005 # . . call 3006 e8/call check-ints-equal/disp32 3007 # . . discard args 3008 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3009 # check-ints-equal(ecx, 1, msg) 3010 # . . push args 3011 68/push "F - test-parse-effective-address-base-index/index"/imm32 3012 68/push 1/imm32/none 3013 51/push-ecx 3014 # . . call 3015 e8/call check-ints-equal/disp32 3016 # . . discard args 3017 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3018 # check-ints-equal(edx, 0, msg) 3019 # . . push args 3020 68/push "F - test-parse-effective-address-base-index/scale"/imm32 3021 68/push 0/imm32/none 3022 52/push-edx 3023 # . . call 3024 e8/call check-ints-equal/disp32 3025 # . . discard args 3026 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3027 # check-ints-equal(ebx, 0, msg) 3028 # . . push args 3029 68/push "F - test-parse-effective-address-base-index/displacement"/imm32 3030 68/push 0/imm32 3031 53/push-ebx 3032 # . . call 3033 e8/call check-ints-equal/disp32 3034 # . . discard args 3035 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3036 # . epilogue 3037 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3038 5d/pop-to-ebp 3039 c3/return 3040 3041 test-parse-effective-address-base-index-scale: 3042 # . prologue 3043 55/push-ebp 3044 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3045 # var slice/ecx = "*(esi+ecx<<2)" 3046 b8/copy-to-eax "*(esi+ecx<<2)"/imm32 3047 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 3048 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 3049 05/add-to-eax 4/imm32 3050 # . ecx = {eax, ecx} 3051 51/push-ecx 3052 50/push-eax 3053 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 3054 # eax, ecx, edx, ebx = parse-effective-address(slice) 3055 # . . push args 3056 51/push-ecx 3057 # . . call 3058 e8/call parse-effective-address/disp32 3059 # . . discard args 3060 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3061 # slice clobbered beyond this point 3062 # check-ints-equal(eax, 6, msg) 3063 # . . push args 3064 68/push "F - test-parse-effective-address-base-index-scale/base"/imm32 3065 68/push 6/imm32/esi 3066 50/push-eax 3067 # . . call 3068 e8/call check-ints-equal/disp32 3069 # . . discard args 3070 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3071 # check-ints-equal(ecx, 1, msg) 3072 # . . push args 3073 68/push "F - test-parse-effective-address-base-index-scale/index"/imm32 3074 68/push 1/imm32/none 3075 51/push-ecx 3076 # . . call 3077 e8/call check-ints-equal/disp32 3078 # . . discard args 3079 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3080 # check-ints-equal(edx, 2, msg) 3081 # . . push args 3082 68/push "F - test-parse-effective-address-base-index-scale/scale"/imm32 3083 68/push 2/imm32 3084 52/push-edx 3085 # . . call 3086 e8/call check-ints-equal/disp32 3087 # . . discard args 3088 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3089 # check-ints-equal(ebx, 0, msg) 3090 # . . push args 3091 68/push "F - test-parse-effective-address-base-index-scale/displacement"/imm32 3092 68/push 0/imm32 3093 53/push-ebx 3094 # . . call 3095 e8/call check-ints-equal/disp32 3096 # . . discard args 3097 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3098 # . epilogue 3099 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3100 5d/pop-to-ebp 3101 c3/return 3102 3103 test-parse-effective-address-base-index-scale-displacement: 3104 # . prologue 3105 55/push-ebp 3106 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3107 # var slice/ecx = "*(esi + ecx<<2 - 0x34)" 3108 b8/copy-to-eax "*(esi + ecx<<2 - 0x34)"/imm32 3109 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 3110 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 3111 05/add-to-eax 4/imm32 3112 # . ecx = {eax, ecx} 3113 51/push-ecx 3114 50/push-eax 3115 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 3116 # eax, ecx, edx, ebx = parse-effective-address(slice) 3117 # . . push args 3118 51/push-ecx 3119 # . . call 3120 e8/call parse-effective-address/disp32 3121 # . . discard args 3122 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3123 # slice clobbered beyond this point 3124 # check-ints-equal(eax, 6, msg) 3125 # . . push args 3126 68/push "F - test-parse-effective-address-base-index-scale/base"/imm32 3127 68/push 6/imm32/esi 3128 50/push-eax 3129 # . . call 3130 e8/call check-ints-equal/disp32 3131 # . . discard args 3132 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3133 # check-ints-equal(ecx, 1, msg) 3134 # . . push args 3135 68/push "F - test-parse-effective-address-base-index-scale/index"/imm32 3136 68/push 1/imm32/none 3137 51/push-ecx 3138 # . . call 3139 e8/call check-ints-equal/disp32 3140 # . . discard args 3141 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3142 # check-ints-equal(edx, 2, msg) 3143 # . . push args 3144 68/push "F - test-parse-effective-address-base-index-scale/scale"/imm32 3145 68/push 2/imm32 3146 52/push-edx 3147 # . . call 3148 e8/call check-ints-equal/disp32 3149 # . . discard args 3150 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3151 # check-ints-equal(ebx, -0x34, msg) 3152 # . . push args 3153 68/push "F - test-parse-effective-address-base-index-scale/displacement"/imm32 3154 68/push -0x34/imm32 3155 53/push-ebx 3156 # . . call 3157 e8/call check-ints-equal/disp32 3158 # . . discard args 3159 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3160 # . epilogue 3161 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3162 5d/pop-to-ebp 3163 c3/return 3164 3165 # Code generation: 3166 # if base is esp, then goto emit-sib 3167 # if base is ebp, then goto emit-sib 3168 # if index is none and disp is 0, then mod = 0 and rm32 = base 3169 # if index is none, then mod = 2 and rm32 = base and disp32 = disp 3170 # emit-sib: 3171 # if index is not none, then mod = 2 and rm32 = 4 and base = base and index = index and disp32 = disp 3172 emit-indirect-mode: # out: (addr buffered-file), base: int, index: int, scale: int, disp: int 3173 # . prologue 3174 55/push-ebp 3175 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3176 $emit-indirect-mode:check-for-ebp: 3177 # if (base == 5) goto emit-sib 3178 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 5/imm32 # compare *(ebp+12) 3179 74/jump-if-= $emit-indirect-mode:emit-sib/disp8 3180 $emit-indirect-mode:check-for-esp: 3181 # if (base == 4) goto emit-sib 3182 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 4/imm32 # compare *(ebp+12) 3183 74/jump-if-= $emit-indirect-mode:emit-sib/disp8 3184 $emit-indirect-mode:check-for-sib: 3185 # if (index == 4/none) goto next check 3186 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 4/imm32 # compare *(ebp+16) 3187 0f 84/jump-if-= $emit-indirect-mode:check-for-disp/disp32 3188 $emit-indirect-mode:emit-sib: 3189 # emit(out, "2/mod/indirect 4/rm32/sib " base "/base " index "/index " scale "/scale " disp "/disp32") 3190 # . write-buffered(out, "2/mod/*+disp32 4/rm32/sib ") 3191 # . . push args 3192 68/push "2/mod/*+disp32 4/rm32/sib "/imm32 3193 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3194 # . . call 3195 e8/call write-buffered/disp32 3196 # . . discard args 3197 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3198 # . write-int32-hex-buffered(out, base) 3199 # . . push args 3200 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 3201 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3202 # . . call 3203 e8/call write-int32-hex-buffered/disp32 3204 # . . discard args 3205 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3206 # . write-buffered(out, "/base ") 3207 # . . push args 3208 68/push "/base "/imm32 3209 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3210 # . . call 3211 e8/call write-buffered/disp32 3212 # . . discard args 3213 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3214 # . write-int32-hex-buffered(out, index) 3215 # . . push args 3216 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 3217 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3218 # . . call 3219 e8/call write-int32-hex-buffered/disp32 3220 # . . discard args 3221 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3222 # . write-buffered(out, "/index ") 3223 # . . push args 3224 68/push "/index "/imm32 3225 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3226 # . . call 3227 e8/call write-buffered/disp32 3228 # . . discard args 3229 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3230 # . write-int32-hex-buffered(out, scale) 3231 # . . push args 3232 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 3233 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3234 # . . call 3235 e8/call write-int32-hex-buffered/disp32 3236 # . . discard args 3237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3238 # . write-buffered(out, "/scale ") 3239 # . . push args 3240 68/push "/scale "/imm32 3241 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3242 # . . call 3243 e8/call write-buffered/disp32 3244 # . . discard args 3245 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3246 # . write-int32-hex-buffered(out, disp) 3247 # . . push args 3248 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 3249 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3250 # . . call 3251 e8/call write-int32-hex-buffered/disp32 3252 # . . discard args 3253 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3254 # . write-buffered(out, "/disp32") 3255 # . . push args 3256 68/push "/disp32"/imm32 3257 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3258 # . . call 3259 e8/call write-buffered/disp32 3260 # . . discard args 3261 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3262 e9/jump $emit-indirect-mode:end/disp32 3263 $emit-indirect-mode:check-for-disp: 3264 # if (disp == 0) goto next check 3265 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 0/imm32 # compare *(ebp+24) 3266 74/jump-if-= $emit-indirect-mode:emit-indirect/disp8 3267 $emit-indirect-mode:emit-disp: 3268 # emit(out, "2/mod/*+disp32 " base "/rm32 " disp "/disp32") 3269 # . write-buffered(out, "2/mod/*+disp32 ") 3270 # . . push args 3271 68/push "2/mod/*+disp32 "/imm32 3272 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3273 # . . call 3274 e8/call write-buffered/disp32 3275 # . . discard args 3276 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3277 # . write-int32-hex-buffered(out, base) 3278 # . . push args 3279 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 3280 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3281 # . . call 3282 e8/call write-int32-hex-buffered/disp32 3283 # . . discard args 3284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3285 # . write-buffered(out, "/rm32 ") 3286 # . . push args 3287 68/push "/rm32 "/imm32 3288 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3289 # . . call 3290 e8/call write-buffered/disp32 3291 # . . discard args 3292 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3293 # . write-int32-hex-buffered(out, disp) 3294 # . . push args 3295 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 3296 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3297 # . . call 3298 e8/call write-int32-hex-buffered/disp32 3299 # . . discard args 3300 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3301 # . write-buffered(out, "/disp32") 3302 # . . push args 3303 68/push "/disp32"/imm32 3304 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3305 # . . call 3306 e8/call write-buffered/disp32 3307 # . . discard args 3308 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3309 eb/jump $emit-indirect-mode:end/disp8 3310 $emit-indirect-mode:emit-indirect: 3311 # emit(out, "0/mod/indirect " base "/rm32") 3312 # . write-buffered(out, "0/mod/indirect ") 3313 # . . push args 3314 68/push "0/mod/indirect "/imm32 3315 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3316 # . . call 3317 e8/call write-buffered/disp32 3318 # . . discard args 3319 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3320 # . write-int32-hex-buffered(out, base) 3321 # . . push args 3322 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 3323 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3324 # . . call 3325 e8/call write-int32-hex-buffered/disp32 3326 # . . discard args 3327 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3328 # . write-buffered(out, "/rm32") 3329 # . . push args 3330 68/push "/rm32"/imm32 3331 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3332 # . . call 3333 e8/call write-buffered/disp32 3334 # . . discard args 3335 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3336 $emit-indirect-mode:end: 3337 # . epilogue 3338 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3339 5d/pop-to-ebp 3340 c3/return 3341 3342 test-emit-indirect-mode: 3343 # . prologue 3344 55/push-ebp 3345 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3346 # setup 3347 # . clear-stream(_test-output-stream) 3348 # . . push args 3349 68/push _test-output-stream/imm32 3350 # . . call 3351 e8/call clear-stream/disp32 3352 # . . discard args 3353 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3354 # . clear-stream($_test-output-buffered-file->buffer) 3355 # . . push args 3356 68/push $_test-output-buffered-file->buffer/imm32 3357 # . . call 3358 e8/call clear-stream/disp32 3359 # . . discard args 3360 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3361 # emit-indirect-mode(_test-output-buffered-file, 0, 4/none, 0, 0) 3362 # . . write args 3363 68/push 0/imm32/.disp 3364 68/push 0/imm32/.scale 3365 68/push 4/imm32/.index/none 3366 68/push 0/imm32/.base 3367 68/push _test-output-buffered-file/imm32 3368 # . . call 3369 e8/call emit-indirect-mode/disp32 3370 # . . discard args 3371 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3372 # . flush(_test-output-buffered-file) 3373 # . . push args 3374 68/push _test-output-buffered-file/imm32 3375 # . . call 3376 e8/call flush/disp32 3377 # . . discard args 3378 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3379 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3405 # check-stream-equal(_test-output-stream, "0/mod/indirect 0/rm32", msg) 3406 # . . push args 3407 68/push "F - test-emit-indirect-mode"/imm32 3408 68/push "0/mod/indirect 0x00000000/rm32"/imm32 3409 68/push _test-output-stream/imm32 3410 # . . call 3411 e8/call check-stream-equal/disp32 3412 # . . discard args 3413 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3414 # . epilogue 3415 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3416 5d/pop-to-ebp 3417 c3/return 3418 3419 test-emit-indirect-mode-2: 3420 # . prologue 3421 55/push-ebp 3422 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3423 # setup 3424 # . clear-stream(_test-output-stream) 3425 # . . push args 3426 68/push _test-output-stream/imm32 3427 # . . call 3428 e8/call clear-stream/disp32 3429 # . . discard args 3430 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3431 # . clear-stream($_test-output-buffered-file->buffer) 3432 # . . push args 3433 68/push $_test-output-buffered-file->buffer/imm32 3434 # . . call 3435 e8/call clear-stream/disp32 3436 # . . discard args 3437 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3438 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 0) 3439 # . . write args 3440 68/push 0/imm32/.disp 3441 68/push 0/imm32/.scale 3442 68/push 4/imm32/.index/none 3443 68/push 7/imm32/.base 3444 68/push _test-output-buffered-file/imm32 3445 # . . call 3446 e8/call emit-indirect-mode/disp32 3447 # . . discard args 3448 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3449 # . flush(_test-output-buffered-file) 3450 # . . push args 3451 68/push _test-output-buffered-file/imm32 3452 # . . call 3453 e8/call flush/disp32 3454 # . . discard args 3455 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3456 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3482 # check-stream-equal(_test-output-stream, "0/mod/indirect 7/rm32", msg) 3483 # . . push args 3484 68/push "F - test-emit-indirect-mode-2"/imm32 3485 68/push "0/mod/indirect 0x00000007/rm32"/imm32 3486 68/push _test-output-stream/imm32 3487 # . . call 3488 e8/call check-stream-equal/disp32 3489 # . . discard args 3490 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3491 # . epilogue 3492 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3493 5d/pop-to-ebp 3494 c3/return 3495 3496 test-emit-indirect-mode-with-disp: 3497 # . prologue 3498 55/push-ebp 3499 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3500 # setup 3501 # . clear-stream(_test-output-stream) 3502 # . . push args 3503 68/push _test-output-stream/imm32 3504 # . . call 3505 e8/call clear-stream/disp32 3506 # . . discard args 3507 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3508 # . clear-stream($_test-output-buffered-file->buffer) 3509 # . . push args 3510 68/push $_test-output-buffered-file->buffer/imm32 3511 # . . call 3512 e8/call clear-stream/disp32 3513 # . . discard args 3514 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3515 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 4) 3516 # . . write args 3517 68/push 4/imm32/.disp 3518 68/push 0/imm32/.scale 3519 68/push 4/imm32/.index/none 3520 68/push 6/imm32/.base 3521 68/push _test-output-buffered-file/imm32 3522 # . . call 3523 e8/call emit-indirect-mode/disp32 3524 # . . discard args 3525 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3526 # . flush(_test-output-buffered-file) 3527 # . . push args 3528 68/push _test-output-buffered-file/imm32 3529 # . . call 3530 e8/call flush/disp32 3531 # . . discard args 3532 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3533 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3559 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 4/disp32", msg) 3560 # . . push args 3561 68/push "F - test-emit-indirect-mode-with-disp"/imm32 3562 68/push "2/mod/*+disp32 0x00000006/rm32 0x00000004/disp32"/imm32 3563 68/push _test-output-stream/imm32 3564 # . . call 3565 e8/call check-stream-equal/disp32 3566 # . . discard args 3567 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3568 # . epilogue 3569 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3570 5d/pop-to-ebp 3571 c3/return 3572 3573 test-emit-indirect-mode-with-disp-negative: 3574 # . prologue 3575 55/push-ebp 3576 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3577 # setup 3578 # . clear-stream(_test-output-stream) 3579 # . . push args 3580 68/push _test-output-stream/imm32 3581 # . . call 3582 e8/call clear-stream/disp32 3583 # . . discard args 3584 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3585 # . clear-stream($_test-output-buffered-file->buffer) 3586 # . . push args 3587 68/push $_test-output-buffered-file->buffer/imm32 3588 # . . call 3589 e8/call clear-stream/disp32 3590 # . . discard args 3591 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3592 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, -4) 3593 # . . write args 3594 68/push -4/imm32/.disp 3595 68/push 0/imm32/.scale 3596 68/push 4/imm32/.index/none 3597 68/push 6/imm32/.base 3598 68/push _test-output-buffered-file/imm32 3599 # . . call 3600 e8/call emit-indirect-mode/disp32 3601 # . . discard args 3602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3603 # . flush(_test-output-buffered-file) 3604 # . . push args 3605 68/push _test-output-buffered-file/imm32 3606 # . . call 3607 e8/call flush/disp32 3608 # . . discard args 3609 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3610 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3636 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 -4/disp32", msg) 3637 # . . push args 3638 68/push "F - test-emit-indirect-mode-with-disp"/imm32 3639 68/push "2/mod/*+disp32 0x00000006/rm32 0xfffffffc/disp32"/imm32 3640 68/push _test-output-stream/imm32 3641 # . . call 3642 e8/call check-stream-equal/disp32 3643 # . . discard args 3644 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3645 # . epilogue 3646 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3647 5d/pop-to-ebp 3648 c3/return 3649 3650 test-emit-indirect-mode-with-sib: 3651 # . prologue 3652 55/push-ebp 3653 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3654 # setup 3655 # . clear-stream(_test-output-stream) 3656 # . . push args 3657 68/push _test-output-stream/imm32 3658 # . . call 3659 e8/call clear-stream/disp32 3660 # . . discard args 3661 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3662 # . clear-stream($_test-output-buffered-file->buffer) 3663 # . . push args 3664 68/push $_test-output-buffered-file->buffer/imm32 3665 # . . call 3666 e8/call clear-stream/disp32 3667 # . . discard args 3668 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3669 # emit-indirect-mode(_test-output-buffered-file, 6/base, 1/index, 2/scale, 4/disp) 3670 # . . write args 3671 68/push 4/imm32/.disp 3672 68/push 2/imm32/.scale 3673 68/push 1/imm32/.index 3674 68/push 6/imm32/.base 3675 68/push _test-output-buffered-file/imm32 3676 # . . call 3677 e8/call emit-indirect-mode/disp32 3678 # . . discard args 3679 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3680 # . flush(_test-output-buffered-file) 3681 # . . push args 3682 68/push _test-output-buffered-file/imm32 3683 # . . call 3684 e8/call flush/disp32 3685 # . . discard args 3686 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3687 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3713 # check-stream-equal(_test-output-stream, "2/mod/indirect 4/rm32/sib 6/base 1/index 2/scale 4/disp", msg) 3714 # . . push args 3715 68/push "F - test-emit-indirect-mode-with-sib"/imm32 3716 68/push "2/mod/*+disp32 4/rm32/sib 0x00000006/base 0x00000001/index 0x00000002/scale 0x00000004/disp32"/imm32 3717 68/push _test-output-stream/imm32 3718 # . . call 3719 e8/call check-stream-equal/disp32 3720 # . . discard args 3721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3722 # . epilogue 3723 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3724 5d/pop-to-ebp 3725 c3/return 3726 3727 test-emit-indirect-mode-ebp: 3728 # . prologue 3729 55/push-ebp 3730 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3731 # setup 3732 # . clear-stream(_test-output-stream) 3733 # . . push args 3734 68/push _test-output-stream/imm32 3735 # . . call 3736 e8/call clear-stream/disp32 3737 # . . discard args 3738 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3739 # . clear-stream($_test-output-buffered-file->buffer) 3740 # . . push args 3741 68/push $_test-output-buffered-file->buffer/imm32 3742 # . . call 3743 e8/call clear-stream/disp32 3744 # . . discard args 3745 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3746 # emit-indirect-mode(_test-output-buffered-file, 5/base, 0/index, 0/scale, 0/disp) 3747 # . . write args 3748 68/push 0/imm32/.disp 3749 68/push 0/imm32/.scale 3750 68/push 0/imm32/.index 3751 68/push 5/imm32/.base/ebp 3752 68/push _test-output-buffered-file/imm32 3753 # . . call 3754 e8/call emit-indirect-mode/disp32 3755 # . . discard args 3756 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3757 # . flush(_test-output-buffered-file) 3758 # . . push args 3759 68/push _test-output-buffered-file/imm32 3760 # . . call 3761 e8/call flush/disp32 3762 # . . discard args 3763 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3764 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3790 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 5/base/ebp 0/index 0/scale 0/disp32", msg) 3791 # . . push args 3792 68/push "F - test-emit-indirect-mode-ebp"/imm32 3793 68/push "2/mod/*+disp32 4/rm32/sib 0x00000005/base 0x00000000/index 0x00000000/scale 0x00000000/disp32"/imm32 3794 68/push _test-output-stream/imm32 3795 # . . call 3796 e8/call check-stream-equal/disp32 3797 # . . discard args 3798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3799 # . epilogue 3800 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3801 5d/pop-to-ebp 3802 c3/return 3803 3804 test-emit-indirect-mode-esp: 3805 # . prologue 3806 55/push-ebp 3807 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3808 # setup 3809 # . clear-stream(_test-output-stream) 3810 # . . push args 3811 68/push _test-output-stream/imm32 3812 # . . call 3813 e8/call clear-stream/disp32 3814 # . . discard args 3815 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3816 # . clear-stream($_test-output-buffered-file->buffer) 3817 # . . push args 3818 68/push $_test-output-buffered-file->buffer/imm32 3819 # . . call 3820 e8/call clear-stream/disp32 3821 # . . discard args 3822 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3823 # emit-indirect-mode(_test-output-buffered-file, 4/base, 0/index, 0/scale, 0/disp) 3824 # . . write args 3825 68/push 0/imm32/.disp 3826 68/push 0/imm32/.scale 3827 68/push 0/imm32/.index 3828 68/push 4/imm32/.base/esp 3829 68/push _test-output-buffered-file/imm32 3830 # . . call 3831 e8/call emit-indirect-mode/disp32 3832 # . . discard args 3833 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp 3834 # . flush(_test-output-buffered-file) 3835 # . . push args 3836 68/push _test-output-buffered-file/imm32 3837 # . . call 3838 e8/call flush/disp32 3839 # . . discard args 3840 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 3841 +-- 26 lines: #? # dump output ------------------------------------------------------------------------------------------------------------------------------------------------------ 3867 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 4/base/ebp 0/index 0/scale 0/disp32", msg) 3868 # . . push args 3869 68/push "F - test-emit-indirect-mode-esp"/imm32 3870 68/push "2/mod/*+disp32 4/rm32/sib 0x00000004/base 0x00000000/index 0x00000000/scale 0x00000000/disp32"/imm32 3871 68/push _test-output-stream/imm32 3872 # . . call 3873 e8/call check-stream-equal/disp32 3874 # . . discard args 3875 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3876 # . epilogue 3877 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3878 5d/pop-to-ebp 3879 c3/return 3880 3881 disp32-mode?: # in: (addr slice) -> reg/eax: boolean 3882 # . prologue 3883 55/push-ebp 3884 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3885 # . save registers 3886 56/push-esi 3887 57/push-edi 3888 # var local-slice/esi: slice = {in->start, in->end} 3889 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 3890 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 3891 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 3892 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi 3893 # ++local-slice->start to skip '*' 3894 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 3895 # if (*local-slice->start == '(') return false 3896 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax 3897 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL 3898 25/and-eax-with 0xff/imm32 3899 3d/compare-eax-and 0x28/imm32/open-paren 3900 74/jump-if-= $disp32-mode?:false/disp8 3901 $disp32-mode?:check-for-register: 3902 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/") 3903 # . . push args 3904 56/push-esi 3905 68/push 0x2f/imm32/slash 3906 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 3907 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 3908 # . . call 3909 e8/call next-token-from-slice/disp32 3910 # . . discard args 3911 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 3912 # reg-num/eax = maybe-get-slice(Registers, local-slice, row-size=12) 3913 # . . push args 3914 68/push 0xc/imm32/row-size 3915 56/push-esi 3916 68/push Registers/imm32 3917 # . . cal 3918 e8/call maybe-get-slice/disp32 3919 # . . discard args 3920 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 3921 # if (eax != 0) return false 3922 3d/compare-eax-and 0/imm32 3923 75/jump-if-!= $disp32-mode?:false/disp8 3924 # return true 3925 b8/copy-to-eax 1/imm32/true 3926 eb/jump $disp32-mode?:end/disp8 3927 $disp32-mode?:false: 3928 b8/copy-to-eax 0/imm32/false 3929 $disp32-mode?:end: 3930 # . reclaim locals 3931 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3932 # . restore registers 3933 5f/pop-to-edi 3934 5e/pop-to-esi 3935 # . epilogue 3936 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3937 5d/pop-to-ebp 3938 c3/return 3939 3940 emit-indirect-disp32: # out: (addr buffered-file), word-slice: (addr slice) 3941 # . prologue 3942 55/push-ebp 3943 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3944 # . save registers 3945 56/push-esi 3946 # var local-slice/esi: slice = {in->start, in->end} 3947 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 3948 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 3949 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 3950 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi 3951 # ++local-slice->start to skip '*' 3952 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi 3953 # write-buffered(out, "0/mod/indirect 5/rm32/.disp32 ") 3954 # . . push args 3955 68/push "0/mod/indirect 5/rm32/.disp32 "/imm32 3956 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3957 # . . call 3958 e8/call write-buffered/disp32 3959 # . . discard args 3960 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3961 # write-slice-buffered(out, local-slice) 3962 # . . push args 3963 56/push-esi 3964 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3965 # . . call 3966 e8/call write-slice-buffered/disp32 3967 # . . discard args 3968 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3969 # write-buffered(out, "/disp32") 3970 # . . push args 3971 68/push "/disp32"/imm32 3972 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 3973 # . . call 3974 e8/call write-buffered/disp32 3975 # . . discard args 3976 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3977 $emit-indirect-disp32:end: 3978 # . reclaim locals 3979 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 3980 # . restore registers 3981 5e/pop-to-esi 3982 # . epilogue 3983 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 3984 5d/pop-to-ebp 3985 c3/return 3986 3987 # assumes 'in' starts with optional '+' or '-', optional whitespace, and an unsigned integer 3988 # returns the value of the integer 3989 # side-effect: modifies 'in' to skip past the integer 3990 next-hex-int: # in: (addr slice) -> result/eax 3991 # . prologue 3992 55/push-ebp 3993 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 3994 # . save registers 3995 51/push-ecx 3996 52/push-edx 3997 53/push-ebx 3998 56/push-esi 3999 57/push-edi 4000 # result/edi = 0 4001 31/xor 3/mod/direct 7/rm32/edi . . . 7/r32/edi . . # clear edi 4002 # esi = in 4003 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 4004 # edx = in->end 4005 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx 4006 # curr/ecx = in->start 4007 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 4008 # negate?/ebx = false 4009 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 4010 # eax = *curr 4011 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 4012 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4013 $next-hex-int:positive: 4014 # if (*curr == '+') ++curr 4015 3d/compare-eax-and 0x2b/imm32/+ 4016 75/jump-if-!= $next-hex-int:negative/disp8 4017 # . ++curr 4018 41/increment-ecx 4019 eb/jump $next-hex-int:skip-whitespace/disp8 4020 $next-hex-int:negative: 4021 # else if (*curr == '-') ++curr, negate = true 4022 3d/compare-eax-and 0x2d/imm32/- 4023 75/jump-if-!= $next-hex-int:skip-whitespace/disp8 4024 $next-hex-int:need-to-negate: 4025 # . ++curr 4026 41/increment-ecx 4027 # . negate = true 4028 bb/copy-to-ebx 1/imm32/true 4029 # fall through 4030 $next-hex-int:skip-whitespace: 4031 # spill eax 4032 50/push-eax 4033 # eax = skip-chars-matching-whitespace-in-slice(word-slice->start, word-slice->end) 4034 # . . push args 4035 52/push-edx 4036 51/push-ecx 4037 # . . call 4038 e8/call skip-chars-matching-whitespace-in-slice/disp32 4039 # . . discard args 4040 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 4041 # ecx = eax 4042 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx 4043 # restore eax 4044 58/pop-to-eax 4045 $next-hex-int:initial-0: 4046 # skip past leading '0x' 4047 # . if (*curr != '0') jump to loop 4048 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4049 3d/compare-eax-and 0x30/imm32/0 4050 75/jump-if-!= $next-hex-int:loop/disp8 4051 # . ++curr 4052 41/increment-ecx 4053 $next-hex-int:initial-0x: 4054 # . if (curr >= in->end) return result 4055 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 4056 73/jump-if-addr>= $next-hex-int:end/disp8 4057 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again 4058 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 4059 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4060 3d/compare-eax-and 0x78/imm32/x 4061 75/jump-if-!= $next-hex-int:loop/disp8 4062 # . ++curr 4063 41/increment-ecx 4064 $next-hex-int:loop: 4065 # if (curr >= in->end) break 4066 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 4067 73/jump-if-addr>= $next-hex-int:break/disp8 4068 # if (!hex-digit?(*curr)) break 4069 # . eax = *curr 4070 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4071 # . eax = hex-digit?(*curr) 4072 # . . push args 4073 50/push-eax 4074 # . . call 4075 e8/call hex-digit?/disp32 4076 # . . discard args 4077 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4078 # . if (eax == false) break 4079 3d/compare-eax-and 0/imm32/false 4080 74/jump-if-= $next-hex-int:break/disp8 4081 # eax = from-hex-char(*curr) 4082 # . . copy arg to eax 4083 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4084 # . . call 4085 e8/call from-hex-char/disp32 4086 # result = result * 16 + eax 4087 c1/shift 4/subop/left 3/mod/direct 7/rm32/edi . . . . . 4/imm8 # shift edi left by 4 bits 4088 01/add 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # add eax to edi 4089 # ++curr 4090 41/increment-ecx 4091 # loop 4092 eb/jump $next-hex-int:loop/disp8 4093 $next-hex-int:break: 4094 # if (negate?) result = -result 4095 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32/false # compare ebx 4096 74/jump-if-= $next-hex-int:end/disp8 4097 $next-hex-int:negate: 4098 f7 3/subop/negate 3/mod/direct 7/rm32/edi . . . . . . # negate edi 4099 $next-hex-int:end: 4100 # word-slice->start = curr 4101 89/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy ecx to *esi 4102 # return edi 4103 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax 4104 # . restore registers 4105 5f/pop-to-edi 4106 5e/pop-to-esi 4107 5b/pop-to-ebx 4108 5a/pop-to-edx 4109 59/pop-to-ecx 4110 # . epilogue 4111 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4112 5d/pop-to-ebp 4113 c3/return 4114 4115 $next-hex-int:abort: 4116 # . _write(2/stderr, error) 4117 # . . push args 4118 68/push "next-hex-int: invalid hex char: "/imm32 4119 68/push 2/imm32/stderr 4120 # . . call 4121 e8/call _write/disp32 4122 # . . discard args 4123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 4124 # . clear-stream($Stderr->buffer) 4125 # . . save eax 4126 50/push-eax 4127 # . . push args 4128 68/push $Stderr->buffer/imm32 4129 # . . call 4130 e8/call clear-stream/disp32 4131 # . . discard args 4132 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4133 # . . restore eax 4134 58/pop-to-eax 4135 # . write-int32-hex-buffered(Stderr, eax) 4136 # . . push args 4137 50/push-eax 4138 68/push Stderr/imm32 4139 # . . call 4140 e8/call write-int32-hex-buffered/disp32 4141 # . . discard args 4142 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 4143 # . flush(Stderr) 4144 # . . push args 4145 68/push Stderr/imm32 4146 # . . call 4147 e8/call flush/disp32 4148 # . . discard args 4149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4150 # . _write(2/stderr, "\n") 4151 # . . push args 4152 68/push Newline/imm32 4153 68/push 2/imm32/stderr 4154 # . . call 4155 e8/call _write/disp32 4156 # . . discard args 4157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 4158 # . syscall_exit(1) 4159 bb/copy-to-ebx 1/imm32 4160 e8/call syscall_exit/disp32 4161 # never gets here 4162 4163 test-next-hex-int-single-digit: 4164 # . prologue 4165 55/push-ebp 4166 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4167 # (eax..ecx) = "+a)" 4168 b8/copy-to-eax "+a)"/imm32 4169 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4170 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4171 05/add-to-eax 4/imm32 4172 # var slice/ecx = {eax, ecx} 4173 51/push-ecx 4174 50/push-eax 4175 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4176 # eax = next-hex-int(slice) 4177 # . . push args 4178 51/push-ecx 4179 # . . call 4180 e8/call next-hex-int/disp32 4181 # . . discard args 4182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4183 # check-ints-equal(eax, 0xa, msg) 4184 # . . push args 4185 68/push "F - test-next-hex-int-single-digit"/imm32 4186 68/push 0xa/imm32 4187 50/push-eax 4188 # . . call 4189 e8/call check-ints-equal/disp32 4190 # . . discard args 4191 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4192 # . epilogue 4193 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4194 5d/pop-to-ebp 4195 c3/return 4196 4197 test-next-hex-int-multi-digit: 4198 # . prologue 4199 55/push-ebp 4200 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4201 # (eax..ecx) = "+ 34a)" 4202 b8/copy-to-eax "+ 34a)"/imm32 4203 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4204 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4205 05/add-to-eax 4/imm32 4206 # var slice/ecx = {eax, ecx} 4207 51/push-ecx 4208 50/push-eax 4209 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4210 # eax = next-hex-int(slice) 4211 # . . push args 4212 51/push-ecx 4213 # . . call 4214 e8/call next-hex-int/disp32 4215 # . . discard args 4216 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4217 # check-ints-equal(eax, 0x34a, msg) 4218 # . . push args 4219 68/push "F - test-next-hex-int-multi-digit"/imm32 4220 68/push 0x34a/imm32 4221 50/push-eax 4222 # . . call 4223 e8/call check-ints-equal/disp32 4224 # . . discard args 4225 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4226 # . epilogue 4227 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4228 5d/pop-to-ebp 4229 c3/return 4230 4231 test-next-hex-int-0x-prefix: 4232 # . prologue 4233 55/push-ebp 4234 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4235 # (eax..ecx) = "+0x34)" 4236 b8/copy-to-eax "+0x34)"/imm32 4237 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4238 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4239 05/add-to-eax 4/imm32 4240 # var slice/ecx = {eax, ecx} 4241 51/push-ecx 4242 50/push-eax 4243 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4244 # eax = next-hex-int(slice) 4245 # . . push args 4246 51/push-ecx 4247 # . . call 4248 e8/call next-hex-int/disp32 4249 # . . discard args 4250 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4251 # check-ints-equal(eax, 0x34, msg) 4252 # . . push args 4253 68/push "F - test-next-hex-int-0x-prefix"/imm32 4254 68/push 0x34/imm32 4255 50/push-eax 4256 # . . call 4257 e8/call check-ints-equal/disp32 4258 # . . discard args 4259 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4260 # . epilogue 4261 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4262 5d/pop-to-ebp 4263 c3/return 4264 4265 test-next-hex-int-zero: 4266 # . prologue 4267 55/push-ebp 4268 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4269 # (eax..ecx) = "+0)" 4270 b8/copy-to-eax "+0)"/imm32 4271 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4272 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4273 05/add-to-eax 4/imm32 4274 # var slice/ecx = {eax, ecx} 4275 51/push-ecx 4276 50/push-eax 4277 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4278 # eax = next-hex-int(slice) 4279 # . . push args 4280 51/push-ecx 4281 # . . call 4282 e8/call next-hex-int/disp32 4283 # . . discard args 4284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4285 # check-ints-equal(eax, 0, msg) 4286 # . . push args 4287 68/push "F - test-next-hex-int-zero"/imm32 4288 68/push 0/imm32 4289 50/push-eax 4290 # . . call 4291 e8/call check-ints-equal/disp32 4292 # . . discard args 4293 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4294 # . epilogue 4295 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4296 5d/pop-to-ebp 4297 c3/return 4298 4299 test-next-hex-int-0-prefix: 4300 # . prologue 4301 55/push-ebp 4302 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4303 # (eax..ecx) = "+ 03)" 4304 b8/copy-to-eax "+ 03)"/imm32 4305 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4306 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4307 05/add-to-eax 4/imm32 4308 # var slice/ecx = {eax, ecx} 4309 51/push-ecx 4310 50/push-eax 4311 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4312 # eax = next-hex-int(slice) 4313 # . . push args 4314 51/push-ecx 4315 # . . call 4316 e8/call next-hex-int/disp32 4317 # . . discard args 4318 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4319 # check-ints-equal(eax, 3, msg) 4320 # . . push args 4321 68/push "F - test-next-hex-int-0-prefix"/imm32 4322 68/push 3/imm32 4323 50/push-eax 4324 # . . call 4325 e8/call check-ints-equal/disp32 4326 # . . discard args 4327 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4328 # . epilogue 4329 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4330 5d/pop-to-ebp 4331 c3/return 4332 4333 test-next-hex-int-negative: 4334 # . prologue 4335 55/push-ebp 4336 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4337 # (eax..ecx) = "-03)" 4338 b8/copy-to-eax "-03)"/imm32 4339 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4340 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4341 05/add-to-eax 4/imm32 4342 # var slice/ecx = {eax, ecx} 4343 51/push-ecx 4344 50/push-eax 4345 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4346 # eax = next-hex-int(slice) 4347 # . . push args 4348 51/push-ecx 4349 # . . call 4350 e8/call next-hex-int/disp32 4351 # . . discard args 4352 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4353 # check-ints-equal(eax, -3, msg) 4354 # . . push args 4355 68/push "F - test-next-hex-int-negative"/imm32 4356 68/push -3/imm32 4357 50/push-eax 4358 # . . call 4359 e8/call check-ints-equal/disp32 4360 # . . discard args 4361 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4362 # . epilogue 4363 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4364 5d/pop-to-ebp 4365 c3/return 4366 4367 test-next-hex-int-negative-with-space: 4368 # . prologue 4369 55/push-ebp 4370 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4371 # (eax..ecx) = "- 03)" 4372 b8/copy-to-eax "- 03)"/imm32 4373 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4374 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4375 05/add-to-eax 4/imm32 4376 # var slice/ecx = {eax, ecx} 4377 51/push-ecx 4378 50/push-eax 4379 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4380 # eax = next-hex-int(slice) 4381 # . . push args 4382 51/push-ecx 4383 # . . call 4384 e8/call next-hex-int/disp32 4385 # . . discard args 4386 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4387 # check-ints-equal(eax, -3, msg) 4388 # . . push args 4389 68/push "F - test-next-hex-int-negative-with-space"/imm32 4390 68/push -3/imm32 4391 50/push-eax 4392 # . . call 4393 e8/call check-ints-equal/disp32 4394 # . . discard args 4395 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4396 # . epilogue 4397 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4398 5d/pop-to-ebp 4399 c3/return 4400 4401 # assumes 'in' starts a positive unsigned integer 4402 # returns the value of the integer 4403 # side-effect: modifies 'in' to skip past the integer 4404 next-positive-hex-int: # in: (addr slice) -> result/eax 4405 # . prologue 4406 55/push-ebp 4407 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4408 # . save registers 4409 51/push-ecx 4410 52/push-edx 4411 53/push-ebx 4412 56/push-esi 4413 57/push-edi 4414 # result/edi = 0 4415 31/xor 3/mod/direct 7/rm32/edi . . . 7/r32/edi . . # clear edi 4416 # esi = in 4417 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 4418 # edx = in->end 4419 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx 4420 # curr/ecx = in->start 4421 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 4422 # negate?/ebx = false 4423 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 4424 # eax = *curr 4425 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 4426 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4427 $next-positive-hex-int:initial-0: 4428 # skip past leading '0x' 4429 # . if (*curr != '0') jump to loop 4430 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4431 3d/compare-eax-and 0x30/imm32/0 4432 75/jump-if-!= $next-positive-hex-int:loop/disp8 4433 # . ++curr 4434 41/increment-ecx 4435 $next-positive-hex-int:initial-0x: 4436 # . if (curr >= in->end) return result 4437 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 4438 73/jump-if-addr>= $next-positive-hex-int:end/disp8 4439 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again 4440 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 4441 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4442 3d/compare-eax-and 0x78/imm32/x 4443 75/jump-if-!= $next-positive-hex-int:loop/disp8 4444 # . ++curr 4445 41/increment-ecx 4446 $next-positive-hex-int:loop: 4447 # if (curr >= in->end) break 4448 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 4449 73/jump-if-addr>= $next-positive-hex-int:end/disp8 4450 # if (!hex-digit?(*curr)) break 4451 # . eax = *curr 4452 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4453 # . eax = hex-digit?(*curr) 4454 # . . push args 4455 50/push-eax 4456 # . . call 4457 e8/call hex-digit?/disp32 4458 # . . discard args 4459 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4460 # . if (eax == false) break 4461 3d/compare-eax-and 0/imm32/false 4462 74/jump-if-= $next-positive-hex-int:end/disp8 4463 # eax = from-hex-char(*curr) 4464 # . . copy arg to eax 4465 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 4466 # . . call 4467 e8/call from-hex-char/disp32 4468 # result = result * 16 + eax 4469 c1/shift 4/subop/left 3/mod/direct 7/rm32/edi . . . . . 4/imm8 # shift edi left by 4 bits 4470 01/add 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # add eax to edi 4471 # ++curr 4472 41/increment-ecx 4473 # loop 4474 eb/jump $next-positive-hex-int:loop/disp8 4475 $next-positive-hex-int:end: 4476 # word-slice->start = curr 4477 89/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy ecx to *esi 4478 # return edi 4479 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax 4480 # . restore registers 4481 5f/pop-to-edi 4482 5e/pop-to-esi 4483 5b/pop-to-ebx 4484 5a/pop-to-edx 4485 59/pop-to-ecx 4486 # . epilogue 4487 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4488 5d/pop-to-ebp 4489 c3/return 4490 4491 test-next-positive-hex-int-single-digit: 4492 # . prologue 4493 55/push-ebp 4494 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4495 # (eax..ecx) = "a)" 4496 b8/copy-to-eax "a)"/imm32 4497 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4498 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4499 05/add-to-eax 4/imm32 4500 # var slice/ecx = {eax, ecx} 4501 51/push-ecx 4502 50/push-eax 4503 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4504 # eax = next-positive-hex-int(slice) 4505 # . . push args 4506 51/push-ecx 4507 # . . call 4508 e8/call next-positive-hex-int/disp32 4509 # . . discard args 4510 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4511 # check-ints-equal(eax, 0xa, msg) 4512 # . . push args 4513 68/push "F - test-next-positive-hex-int-single-digit"/imm32 4514 68/push 0xa/imm32 4515 50/push-eax 4516 # . . call 4517 e8/call check-ints-equal/disp32 4518 # . . discard args 4519 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4520 # . epilogue 4521 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4522 5d/pop-to-ebp 4523 c3/return 4524 4525 test-next-positive-hex-int-multi-digit: 4526 # . prologue 4527 55/push-ebp 4528 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4529 # (eax..ecx) = "34a)" 4530 b8/copy-to-eax "34a)"/imm32 4531 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4532 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4533 05/add-to-eax 4/imm32 4534 # var slice/ecx = {eax, ecx} 4535 51/push-ecx 4536 50/push-eax 4537 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4538 # eax = next-positive-hex-int(slice) 4539 # . . push args 4540 51/push-ecx 4541 # . . call 4542 e8/call next-positive-hex-int/disp32 4543 # . . discard args 4544 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4545 # check-ints-equal(eax, 0x34a, msg) 4546 # . . push args 4547 68/push "F - test-next-positive-hex-int-multi-digit"/imm32 4548 68/push 0x34a/imm32 4549 50/push-eax 4550 # . . call 4551 e8/call check-ints-equal/disp32 4552 # . . discard args 4553 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4554 # . epilogue 4555 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4556 5d/pop-to-ebp 4557 c3/return 4558 4559 test-next-positive-hex-int-0x-prefix: 4560 # . prologue 4561 55/push-ebp 4562 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4563 # (eax..ecx) = "0x34)" 4564 b8/copy-to-eax "0x34)"/imm32 4565 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4566 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4567 05/add-to-eax 4/imm32 4568 # var slice/ecx = {eax, ecx} 4569 51/push-ecx 4570 50/push-eax 4571 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4572 # eax = next-positive-hex-int(slice) 4573 # . . push args 4574 51/push-ecx 4575 # . . call 4576 e8/call next-positive-hex-int/disp32 4577 # . . discard args 4578 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4579 # check-ints-equal(eax, 0x34, msg) 4580 # . . push args 4581 68/push "F - test-next-positive-hex-int-0x-prefix"/imm32 4582 68/push 0x34/imm32 4583 50/push-eax 4584 # . . call 4585 e8/call check-ints-equal/disp32 4586 # . . discard args 4587 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4588 # . epilogue 4589 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4590 5d/pop-to-ebp 4591 c3/return 4592 4593 test-next-positive-hex-int-zero: 4594 # . prologue 4595 55/push-ebp 4596 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4597 # (eax..ecx) = "0" 4598 b8/copy-to-eax "0"/imm32 4599 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4600 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4601 05/add-to-eax 4/imm32 4602 # var slice/ecx = {eax, ecx} 4603 51/push-ecx 4604 50/push-eax 4605 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4606 # eax = next-positive-hex-int(slice) 4607 # . . push args 4608 51/push-ecx 4609 # . . call 4610 e8/call next-positive-hex-int/disp32 4611 # . . discard args 4612 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4613 # check-ints-equal(eax, 0, msg) 4614 # . . push args 4615 68/push "F - test-next-positive-hex-int-zero"/imm32 4616 68/push 0/imm32 4617 50/push-eax 4618 # . . call 4619 e8/call check-ints-equal/disp32 4620 # . . discard args 4621 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4622 # . epilogue 4623 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4624 5d/pop-to-ebp 4625 c3/return 4626 4627 test-next-positive-hex-int-0-prefix: 4628 # . prologue 4629 55/push-ebp 4630 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 4631 # (eax..ecx) = "03)" 4632 b8/copy-to-eax "03)"/imm32 4633 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 4634 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 4635 05/add-to-eax 4/imm32 4636 # var slice/ecx = {eax, ecx} 4637 51/push-ecx 4638 50/push-eax 4639 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 4640 # eax = next-positive-hex-int(slice) 4641 # . . push args 4642 51/push-ecx 4643 # . . call 4644 e8/call next-positive-hex-int/disp32 4645 # . . discard args 4646 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 4647 # check-ints-equal(eax, 3, msg) 4648 # . . push args 4649 68/push "F - test-next-positive-hex-int-0-prefix"/imm32 4650 68/push 3/imm32 4651 50/push-eax 4652 # . . call 4653 e8/call check-ints-equal/disp32 4654 # . . discard args 4655 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 4656 # . epilogue 4657 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 4658 5d/pop-to-ebp 4659 c3/return 4660 4661 # . . vim:nowrap:textwidth=0