# Helpers to compute widths of SubX arguments based on their metadata. # /imm8 => 1 byte, # /disp32 => 4 bytes, # and so on. == code # instruction effective address register displacement immediate # . op subop mod rm32 base index scale r32 # . 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 compute-width: # word: (addr array byte) -> result/eax: int # . prologue 55/push-ebp 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp # . save registers 51/push-ecx # eax = word 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to ecx # var ecx: (addr byte) = &word[word->size] 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 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 # eax = word->data 05/add-to-eax 4/imm32 # var in/ecx: slice = {eax, ecx} 51/push-ecx 50/push-eax 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx # return compute-width-of-slice(ecx) # . . push args 51/push-ecx # . . call e8/call compute-width-of-slice/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp $compute-width:end: # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp # . restore registers 59/pop-to-ecx # . epilogue 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 5d/pop-to-ebp c3/return compute-width-of-slice: # s: (addr slice) -> result/eax: int # . prologue 55/push-ebp 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp # . save registers 51/push-ecx # ecx = s 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx # if (has-metadata?(word, "imm32")) return 4 # . eax = has-metadata?(word, "imm32") # . . push args 68/push "imm32"/imm32 51/push-ecx # . . call e8/call has-metadata?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp # . if (eax != false) return 4 3d/compare-eax-and 0/imm32/false b8/copy-to-eax 4/imm32 # ZF is set, so we can overwrite eax now 75/jump-if-!= $compute-width-of-slice:end/disp8 # if (has-metadata?(word, "disp32")) return 4 # . eax = has-metadata?(word, "disp32") # . . push args 68/push "disp32"/imm32 51/push-ecx # . . call e8/call has-metadata?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp # . if (eax != false) return 4 3d/compare-eax-and 0/imm32/false b8/copy-to-eax 4/imm32 # ZF is set, so we can overwrite eax now 75/jump-if-!= $compute-width-of-slice:end/disp8 # if (has-metadata?(word, "imm16")) return 2 # . eax = has-metadata?(word, "imm16") # . . push args 68/push "imm16"/imm32 51/push-ecx # . . call e8/call has-metadata?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp # . if (eax != false) return 2 3d/compare-eax-and 0/imm32/false b8/copy-to-eax 2/imm32 # ZF is set, so we can overwrite eax now 75/jump-if-!= $compute-width-of-slice:end/disp8 # if (has-metadata?(word, "disp16")) return 2 # . eax = has-metadata?(word, "disp16") # . . push args 68/push "disp16"/imm32 51/push-ecx # . . call e8/call has-metadata?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp # . if (eax != false) return 2 3d/compare-eax-and 0/imm32/false b8/copy-to-eax 2/imm32 # ZF is set, so we can overwrite eax now 75/jump-if-!= $compute-width-of-slice:end/disp8 # otherwise return 1 b8/copy-to-eax 1/imm32 $compute-width-of-slice:end: # . restore registers 59/pop-to-ecx # . epilogue 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 5d/pop-to-ebp c3/return test-compute-width: # . prologue 55/push-ebp 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp $test-compute-width:imm8: # eax = compute-width("0x2/imm8") # . . push args 68/push "0x2/imm8"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 1, msg) # . . push args 68/push "F - test-compute-width: 0x2/imm8"/imm32 50/push-eax 68/push 1/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:imm16: # eax = compute-width("4/imm16") # . . push args 68/push "4/imm16"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 2, msg) # . . push args 68/push "F - test-compute-width: 4/imm16"/imm32 50/push-eax 68/push 2/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:imm32: # eax = compute-width("4/imm32") # . . push args 68/push "4/imm32"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 4, msg) # . . push args 68/push "F - test-compute-width: 4/imm32"/imm32 50/push-eax 68/push 4/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:disp8: # eax = compute-width("foo/disp8") # . . push args 68/push "foo/disp8"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 1, msg) # . . push args 68/push "F - test-compute-width: foo/disp8"/imm32 50/push-eax 68/push 1/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:disp16: # eax = compute-width("foo/disp16") # . . push args 68/push "foo/disp16"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 2, msg) # . . push args 68/push "F - test-compute-width: foo/disp16"/imm32 50/push-eax 68/push 2/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:disp32: # eax = compute-width("foo/disp32") # . . push args 68/push "foo/disp32"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 4, msg) # . . push args 68/push "F - test-compute-width: foo/disp32"/imm32 50/push-eax 68/push 4/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp $test-compute-width:no-metadata: # eax = compute-width("45") # . . push args 68/push "45"/imm32 # . . call e8/call compute-width/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp # check-ints-equal(eax, 1, msg) # . . push args 68/push "F - test-compute-width: 45 (no metadata)"/imm32 50/push-eax 68/push 1/imm32 # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp # . epilogue 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 5d/pop-to-ebp c3/return # . . vim:nowrap:textwidth=0