So far it's unclear how to do this in a series of small commits. Still nibbling around the edges. In this commit we standardize some terminology: The length of an array or stream is denominated in the high-level elements. The _size_ is denominated in bytes. The thing we encode into the type is always the size, not the length. There's still an open question of what to do about the Mu `length` operator. I'd like to modify it to provide the length. Currently it provides the size. If I can't fix that I'll rename it.
244 lines
11 KiB
Plaintext
244 lines
11 KiB
Plaintext
# 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) -> 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) -> 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
|