1 # some utilities for converting numbers from hex 2 # lowercase letters only for now 3 4 == code 5 # instruction effective address register displacement immediate 6 # . op subop mod rm32 base index scale r32 7 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 8 9 is-hex-int?: # in : (address slice) -> eax : boolean 10 # . prologue 11 55/push-ebp 12 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 13 # . save registers 14 51/push-ecx 15 52/push-edx 16 53/push-ebx 17 # ecx = s 18 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx 19 # edx = s->end 20 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx 21 # var curr/ecx : (address byte) = s->start 22 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx 23 # if s is empty return false 24 b8/copy-to-eax 0/imm32/false 25 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 26 73/jump-if-greater-or-equal-unsigned $is-hex-int?:end/disp8 27 # skip past leading '-' 28 # . if (*curr == '-') ++curr 29 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 30 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL 31 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x2d/imm32/- # compare ebx 32 75/jump-if-not-equal $is-hex-int?:initial-0/disp8 33 # . ++curr 34 41/increment-ecx 35 # skip past leading '0x' 36 $is-hex-int?:initial-0: 37 # . if (*curr != '0') jump to loop 38 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 39 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL 40 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x30/imm32/0 # compare ebx 41 75/jump-if-not-equal $is-hex-int?:loop/disp8 42 # . ++curr 43 41/increment-ecx 44 $is-hex-int?:initial-0x: 45 # . if (curr >= in->end) return true 46 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 47 73/jump-if-greater-or-equal-unsigned $is-hex-int?:true/disp8 48 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again 49 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 50 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL 51 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x78/imm32/x # compare ebx 52 75/jump-if-not-equal $is-hex-int?:loop/disp8 53 # . ++curr 54 41/increment-ecx 55 $is-hex-int?:loop: 56 # if (curr >= in->end) return true 57 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 58 73/jump-if-greater-or-equal-unsigned $is-hex-int?:true/disp8 59 # var eax : boolean = is-hex-digit?(*curr) 60 # . . push args 61 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 62 50/push-eax 63 # . . call 64 e8/call is-hex-digit?/disp32 65 # . . discard args 66 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 67 # if (eax == false) return false 68 3d/compare-eax-and 0/imm32 69 74/jump-if-equal $is-hex-int?:end/disp8 70 # ++curr 71 41/increment-ecx 72 # loop 73 eb/jump $is-hex-int?:loop/disp8 74 $is-hex-int?:true: 75 # return true 76 b8/copy-to-eax 1/imm32/true 77 $is-hex-int?:end: 78 # . restore registers 79 5b/pop-to-ebx 80 5a/pop-to-edx 81 59/pop-to-ecx 82 # . epilogue 83 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 84 5d/pop-to-ebp 85 c3/return 86 87 test-is-hex-int: 88 # . prologue 89 55/push-ebp 90 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 91 # (eax..ecx) = "34" 92 b8/copy-to-eax "34"/imm32 93 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 94 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 95 05/add-to-eax 4/imm32 96 # var slice/ecx : (ref slice) = {eax, ecx} 97 51/push-ecx 98 50/push-eax 99 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 100 # eax = is-hex-int?(slice) 101 # . . push args 102 51/push-ecx 103 # . . call 104 e8/call is-hex-int?/disp32 105 # . . discard args 106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 107 # check-ints-equal(eax, 1, msg) 108 # . . push args 109 68/push "F - test-is-hex-int"/imm32 110 68/push 1/imm32/true 111 50/push-eax 112 # . . call 113 e8/call check-ints-equal/disp32 114 # . . discard args 115 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 116 # . epilogue 117 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 118 5d/pop-to-ebp 119 c3/return 120 121 test-is-hex-int-handles-letters: 122 # . prologue 123 55/push-ebp 124 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 125 # (eax..ecx) = "34a" 126 b8/copy-to-eax "34a"/imm32 127 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 128 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 129 05/add-to-eax 4/imm32 130 # var slice/ecx : (ref slice) = {eax, ecx} 131 51/push-ecx 132 50/push-eax 133 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 134 # eax = is-hex-int?(slice) 135 # . . push args 136 51/push-ecx 137 # . . call 138 e8/call is-hex-int?/disp32 139 # . . discard args 140 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 141 # check-ints-equal(eax, 1, msg) 142 # . . push args 143 68/push "F - test-is-hex-int-handles-letters"/imm32 144 68/push 1/imm32/true 145 50/push-eax 146 # . . call 147 e8/call check-ints-equal/disp32 148 # . . discard args 149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 150 # . epilogue 151 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 152 5d/pop-to-ebp 153 c3/return 154 155 test-is-hex-int-with-trailing-char: 156 # . prologue 157 55/push-ebp 158 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 159 # (eax..ecx) = "34q" 160 b8/copy-to-eax "34q"/imm32 161 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 162 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 163 05/add-to-eax 4/imm32 164 # var slice/ecx : (ref slice) = {eax, ecx} 165 51/push-ecx 166 50/push-eax 167 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 168 # eax = is-hex-int?(slice) 169 # . . push args 170 51/push-ecx 171 # . . call 172 e8/call is-hex-int?/disp32 173 # . . discard args 174 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 175 # check-ints-equal(eax, 0, msg) 176 # . . push args 177 68/push "F - test-is-hex-int-with-trailing-char"/imm32 178 68/push 0/imm32/false 179 50/push-eax 180 # . . call 181 e8/call check-ints-equal/disp32 182 # . . discard args 183 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 184 # . epilogue 185 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 186 5d/pop-to-ebp 187 c3/return 188 189 test-is-hex-int-with-leading-char: 190 # . prologue 191 55/push-ebp 192 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 193 # (eax..ecx) = "q34" 194 b8/copy-to-eax "q34"/imm32 195 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 196 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 197 05/add-to-eax 4/imm32 198 # var slice/ecx : (ref slice) = {eax, ecx} 199 51/push-ecx 200 50/push-eax 201 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 202 # eax = is-hex-int?(slice) 203 # . . push args 204 51/push-ecx 205 # . . call 206 e8/call is-hex-int?/disp32 207 # . . discard args 208 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 209 # check-ints-equal(eax, 0, msg) 210 # . . push args 211 68/push "F - test-is-hex-int-with-leading-char"/imm32 212 68/push 0/imm32/false 213 50/push-eax 214 # . . call 215 e8/call check-ints-equal/disp32 216 # . . discard args 217 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 218 # . epilogue 219 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 220 5d/pop-to-ebp 221 c3/return 222 223 test-is-hex-int-empty: 224 # . prologue 225 55/push-ebp 226 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 227 # var slice/ecx : (ref slice) = "" 228 68/push 0/imm32 229 68/push 0/imm32 230 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 231 # eax = is-hex-int?(slice) 232 # . . push args 233 51/push-ecx 234 # . . call 235 e8/call is-hex-int?/disp32 236 # . . discard args 237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 238 # check-ints-equal(eax, 0, msg) 239 # . . push args 240 68/push "F - test-is-hex-int-empty"/imm32 241 68/push 0/imm32/false 242 50/push-eax 243 # . . call 244 e8/call check-ints-equal/disp32 245 # . . discard args 246 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 247 # . epilogue 248 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 249 5d/pop-to-ebp 250 c3/return 251 252 test-is-hex-int-handles-0x-prefix: 253 # . prologue 254 55/push-ebp 255 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 256 # (eax..ecx) = "0x3a" 257 b8/copy-to-eax "0x3a"/imm32 258 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 259 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 260 05/add-to-eax 4/imm32 261 # var slice/ecx : (ref slice) = {eax, ecx} 262 51/push-ecx 263 50/push-eax 264 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 265 # eax = is-hex-int?(slice) 266 # . . push args 267 51/push-ecx 268 # . . call 269 e8/call is-hex-int?/disp32 270 # . . discard args 271 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 272 # check-ints-equal(eax, 1, msg) 273 # . . push args 274 68/push "F - test-is-hex-int-handles-0x-prefix"/imm32 275 68/push 1/imm32/true 276 50/push-eax 277 # . . call 278 e8/call check-ints-equal/disp32 279 # . . discard args 280 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 281 # . epilogue 282 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 283 5d/pop-to-ebp 284 c3/return 285 286 test-is-hex-int-handles-negative: 287 # . prologue 288 55/push-ebp 289 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 290 # (eax..ecx) = "-34a" 291 b8/copy-to-eax "-34a"/imm32 292 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 293 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 294 05/add-to-eax 4/imm32 295 # var slice/ecx : (ref slice) = {eax, ecx} 296 51/push-ecx 297 50/push-eax 298 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 299 # eax = is-hex-int?(slice) 300 # . . push args 301 51/push-ecx 302 # . . call 303 e8/call is-hex-int?/disp32 304 # . . discard args 305 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 306 # check-ints-equal(eax, 1, msg) 307 # . . push args 308 68/push "F - test-is-hex-int-handles-negative"/imm32 309 68/push 1/imm32/true 310 50/push-eax 311 # . . call 312 e8/call check-ints-equal/disp32 313 # . . discard args 314 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 315 # . epilogue 316 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 317 5d/pop-to-ebp 318 c3/return 319 320 test-is-hex-int-handles-negative-0x-prefix: 321 # . prologue 322 55/push-ebp 323 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 324 # (eax..ecx) = "-0x3a" 325 b8/copy-to-eax "-0x3a"/imm32 326 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 327 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 328 05/add-to-eax 4/imm32 329 # var slice/ecx : (ref slice) = {eax, ecx} 330 51/push-ecx 331 50/push-eax 332 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 333 # eax = is-hex-int?(slice) 334 # . . push args 335 51/push-ecx 336 # . . call 337 e8/call is-hex-int?/disp32 338 # . . discard args 339 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 340 # check-ints-equal(eax, 1, msg) 341 # . . push args 342 68/push "F - test-is-hex-int-handles-negative-0x-prefix"/imm32 343 68/push 1/imm32/true 344 50/push-eax 345 # . . call 346 e8/call check-ints-equal/disp32 347 # . . discard args 348 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 349 # . epilogue 350 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 351 5d/pop-to-ebp 352 c3/return 353 354 parse-hex-int: # in : (address slice) -> result/eax : int 355 # . prologue 356 55/push-ebp 357 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 358 # . save registers 359 51/push-ecx 360 52/push-edx 361 53/push-ebx 362 56/push-esi 363 # var result/ebx : int = 0 364 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 365 # ecx = in 366 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx 367 # edx = in->end 368 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx 369 # var curr/ecx : (address byte) = in->start 370 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx 371 # var negate?/esi : boolean = false 372 31/xor 3/mod/direct 6/rm32/esi . . . 6/r32/esi . . # clear esi 373 $parse-hex-int:negative: 374 # if (*curr == '-') ++curr, negate = true 375 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 376 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 377 3d/compare-eax-and 0x2d/imm32/- 378 75/jump-if-not-equal $parse-hex-int:initial-0/disp8 379 # . ++curr 380 41/increment-ecx 381 # . negate = true 382 be/copy-to-esi 1/imm32/true 383 $parse-hex-int:initial-0: 384 # skip past leading '0x' 385 # . if (*curr != '0') jump to loop 386 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 387 3d/compare-eax-and 0x30/imm32/0 388 75/jump-if-not-equal $parse-hex-int:loop/disp8 389 # . ++curr 390 41/increment-ecx 391 $parse-hex-int:initial-0x: 392 # . if (curr >= in->end) return result 393 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 394 73/jump-if-greater-or-equal-unsigned $parse-hex-int:end/disp8 395 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again 396 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 397 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 398 3d/compare-eax-and 0x78/imm32/x 399 75/jump-if-not-equal $parse-hex-int:loop/disp8 400 # . ++curr 401 41/increment-ecx 402 $parse-hex-int:loop: 403 # if (curr >= in->end) break 404 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 405 73/jump-if-greater-or-equal-unsigned $parse-hex-int:negate/disp8 406 # var eax : int = from-hex-char(*curr) 407 # . . copy arg to eax 408 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 409 # . . call 410 e8/call from-hex-char/disp32 411 # result = result * 16 + eax 412 c1/shift 4/subop/left 3/mod/direct 3/rm32/ebx . . . . . 4/imm8 # shift ebx left by 4 bits 413 01/add 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # add eax to ebx 414 # ++curr 415 41/increment-ecx 416 # loop 417 eb/jump $parse-hex-int:loop/disp8 418 $parse-hex-int:negate: 419 # if (negate?) result = -result 420 81 7/subop/compare 3/mod/direct 6/rm32/esi . . . . . 0/imm32/false # compare esi 421 74/jump-if-equal $parse-hex-int:end/disp8 422 f7 3/subop/negate 3/mod/direct 3/rm32/ebx . . . . . . # negate ebx 423 $parse-hex-int:end: 424 # return result 425 89/copy 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # copy ebx to eax 426 # . restore registers 427 5e/pop-to-esi 428 5b/pop-to-ebx 429 5a/pop-to-edx 430 59/pop-to-ecx 431 # . epilogue 432 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 433 5d/pop-to-ebp 434 c3/return 435 436 test-parse-hex-int-single-digit: 437 # . prologue 438 55/push-ebp 439 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 440 # (eax..ecx) = "a" 441 b8/copy-to-eax "a"/imm32 442 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 443 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 444 05/add-to-eax 4/imm32 445 # var slice/ecx : (ref slice) = {eax, ecx} 446 51/push-ecx 447 50/push-eax 448 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 449 # eax = parse-hex-int(slice) 450 # . . push args 451 51/push-ecx 452 # . . call 453 e8/call parse-hex-int/disp32 454 # . . discard args 455 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 456 # check-ints-equal(eax, 0xa, msg) 457 # . . push args 458 68/push "F - test-parse-hex-int-single-digit"/imm32 459 68/push 0xa/imm32 460 50/push-eax 461 # . . call 462 e8/call check-ints-equal/disp32 463 # . . discard args 464 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 465 # . epilogue 466 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 467 5d/pop-to-ebp 468 c3/return 469 470 test-parse-hex-int-multi-digit: 471 # . prologue 472 55/push-ebp 473 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 474 # (eax..ecx) = "34a" 475 b8/copy-to-eax "34a"/imm32 476 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 477 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 478 05/add-to-eax 4/imm32 479 # var slice/ecx : (ref slice) = {eax, ecx} 480 51/push-ecx 481 50/push-eax 482 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 483 # eax = parse-hex-int(slice) 484 # . . push args 485 51/push-ecx 486 # . . call 487 e8/call parse-hex-int/disp32 488 # . . discard args 489 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 490 # check-ints-equal(eax, 0x34a, msg) 491 # . . push args 492 68/push "F - test-parse-hex-int-multi-digit"/imm32 493 68/push 0x34a/imm32 494 50/push-eax 495 # . . call 496 e8/call check-ints-equal/disp32 497 # . . discard args 498 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 499 # . epilogue 500 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 501 5d/pop-to-ebp 502 c3/return 503 504 test-parse-hex-int-0x-prefix: 505 # . prologue 506 55/push-ebp 507 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 508 # (eax..ecx) = "0x34" 509 b8/copy-to-eax "0x34"/imm32 510 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 511 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 512 05/add-to-eax 4/imm32 513 # var slice/ecx : (ref slice) = {eax, ecx} 514 51/push-ecx 515 50/push-eax 516 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 517 # eax = parse-hex-int(slice) 518 # . . push args 519 51/push-ecx 520 # . . call 521 e8/call parse-hex-int/disp32 522 # . . discard args 523 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 524 # check-ints-equal(eax, 0x34a, msg) 525 # . . push args 526 68/push "F - test-parse-hex-int-0x-prefix"/imm32 527 68/push 0x34/imm32 528 50/push-eax 529 # . . call 530 e8/call check-ints-equal/disp32 531 # . . discard args 532 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 533 # . epilogue 534 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 535 5d/pop-to-ebp 536 c3/return 537 538 test-parse-hex-int-zero: 539 # . prologue 540 55/push-ebp 541 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 542 # (eax..ecx) = "0" 543 b8/copy-to-eax "0"/imm32 544 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 545 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 546 05/add-to-eax 4/imm32 547 # var slice/ecx : (ref slice) = {eax, ecx} 548 51/push-ecx 549 50/push-eax 550 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 551 # eax = parse-hex-int(slice) 552 # . . push args 553 51/push-ecx 554 # . . call 555 e8/call parse-hex-int/disp32 556 # . . discard args 557 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 558 # check-ints-equal(eax, 0x34a, msg) 559 # . . push args 560 68/push "F - test-parse-hex-int-zero"/imm32 561 68/push 0/imm32 562 50/push-eax 563 # . . call 564 e8/call check-ints-equal/disp32 565 # . . discard args 566 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 567 # . epilogue 568 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 569 5d/pop-to-ebp 570 c3/return 571 572 test-parse-hex-int-0-prefix: 573 # . prologue 574 55/push-ebp 575 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 576 # (eax..ecx) = "03" 577 b8/copy-to-eax "03"/imm32 578 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 579 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 580 05/add-to-eax 4/imm32 581 # var slice/ecx : (ref slice) = {eax, ecx} 582 51/push-ecx 583 50/push-eax 584 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 585 # eax = parse-hex-int(slice) 586 # . . push args 587 51/push-ecx 588 # . . call 589 e8/call parse-hex-int/disp32 590 # . . discard args 591 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 592 # check-ints-equal(eax, 0x3, msg) 593 # . . push args 594 68/push "F - test-parse-hex-int-0-prefix"/imm32 595 68/push 0x3/imm32 596 50/push-eax 597 # . . call 598 e8/call check-ints-equal/disp32 599 # . . discard args 600 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 601 # . epilogue 602 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 603 5d/pop-to-ebp 604 c3/return 605 606 test-parse-hex-int-negative: 607 # . prologue 608 55/push-ebp 609 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 610 # (eax..ecx) = "-03" 611 b8/copy-to-eax "-03"/imm32 612 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 613 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 614 05/add-to-eax 4/imm32 615 # var slice/ecx : (ref slice) = {eax, ecx} 616 51/push-ecx 617 50/push-eax 618 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 619 # eax = parse-hex-int(slice) 620 # . . push args 621 51/push-ecx 622 # . . call 623 e8/call parse-hex-int/disp32 624 # . . discard args 625 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 626 # check-ints-equal(eax, -3, msg) 627 # . . push args 628 68/push "F - test-parse-hex-int-negative"/imm32 629 68/push -3/imm32 630 50/push-eax 631 # . . call 632 e8/call check-ints-equal/disp32 633 # . . discard args 634 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 635 # . epilogue 636 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 637 5d/pop-to-ebp 638 c3/return 639 640 is-hex-digit?: # c : byte -> eax : boolean 641 # . prologue 642 55/push-ebp 643 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 644 # . save registers 645 51/push-ecx 646 # ecx = c 647 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx 648 # return false if c < '0' 649 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x30/imm32 # compare ecx 650 7c/jump-if-lesser $is-hex-digit?:false/disp8 651 # return true if c <= '9' 652 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x39/imm32 # compare ecx 653 7e/jump-if-lesser-or-equal $is-hex-digit?:true/disp8 654 # drop case 655 25/and-eax-with 0x5f/imm32 656 # return false if c > 'f' 657 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x66/imm32 # compare ecx 658 7f/jump-if-greater $is-hex-digit?:false/disp8 659 # return true if c >= 'a' 660 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x61/imm32 # compare ecx 661 7d/jump-if-greater-or-equal $is-hex-digit?:true/disp8 662 # otherwise return false 663 $is-hex-digit?:false: 664 b8/copy-to-eax 0/imm32/false 665 eb/jump $is-hex-digit?:end/disp8 666 $is-hex-digit?:true: 667 b8/copy-to-eax 1/imm32/true 668 $is-hex-digit?:end: 669 # . restore registers 670 59/pop-to-ecx 671 # . epilogue 672 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 673 5d/pop-to-ebp 674 c3/return 675 676 test-hex-below-0: 677 # eax = is-hex-digit?(0x2f) 678 # . . push args 679 68/push 0x2f/imm32 680 # . . call 681 e8/call is-hex-digit?/disp32 682 # . . discard args 683 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 684 # check-ints-equal(eax, 0, msg) 685 # . . push args 686 68/push "F - test-hex-below-0"/imm32 687 68/push 0/imm32/false 688 50/push-eax 689 # . . call 690 e8/call check-ints-equal/disp32 691 # . . discard args 692 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 693 c3/return 694 695 test-hex-0-to-9: 696 # eax = is-hex-digit?(0x30) 697 # . . push args 698 68/push 0x30/imm32 699 # . . call 700 e8/call is-hex-digit?/disp32 701 # . . discard args 702 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 703 # check-ints-equal(eax, 1, msg) 704 # . . push args 705 68/push "F - test-hex-at-0"/imm32 706 68/push 1/imm32/true 707 50/push-eax 708 # . . call 709 e8/call check-ints-equal/disp32 710 # . . discard args 711 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 712 # eax = is-hex-digit?(0x39) 713 # . . push args 714 68/push 0x39/imm32 715 # . . call 716 e8/call is-hex-digit?/disp32 717 # . . discard args 718 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 719 # check-ints-equal(eax, 1, msg) 720 # . . push args 721 68/push "F - test-hex-at-9"/imm32 722 68/push 1/imm32/true 723 50/push-eax 724 # . . call 725 e8/call check-ints-equal/disp32 726 # . . discard args 727 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 728 c3/return 729 730 test-hex-above-9-to-a: 731 # eax = is-hex-digit?(0x3a) 732 # . . push args 733 68/push 0x3a/imm32 734 # . . call 735 e8/call is-hex-digit?/disp32 736 # . . discard args 737 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 738 # check-ints-equal(eax, 0, msg) 739 # . . push args 740 68/push "F - test-hex-above-9-to-a"/imm32 741 68/push 0/imm32/false 742 50/push-eax 743 # . . call 744 e8/call check-ints-equal/disp32 745 # . . discard args 746 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 747 c3/return 748 749 test-hex-a-to-f: 750 # eax = is-hex-digit?(0x61) 751 # . . push args 752 68/push 0x61/imm32 753 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 */## deleting sandboxes scenario deleting-sandboxes [ trace-until 100/app # trace too long assume-screen 100/width, 15/height 1:text <- new [] 2:text <- new [] 3:&:environment <- new-programming-environment screen:&:screen, 1:text, 2:text # run a few commands assume-console [ left-click 1, 80 type [divide-with-remainder 11, 3] press F4 type [add 2, 2] press F4 ] event-loop screen:&:screen, console:&:console, 3:&:environment screen-should-contain [ . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊0 edit copy delete . . ┊add 2, 2 . . ┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊1 edit copy delete . . ┊divide-with-remainder 11, 3 . . ┊3 . . ┊2 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] # delete second sandbox by clicking on left edge of 'delete' button assume-console<