mu/linux/133subx-widths.subx
Kartik K. Agaram 71e4f38129 7842 - new directory organization
Baremetal is now the default build target and therefore has its sources
at the top-level. Baremetal programs build using the phase-2 Mu toolchain
that requires a Linux kernel. This phase-2 codebase which used to be at
the top-level is now under the linux/ directory. Finally, the phase-2 toolchain,
while self-hosting, has a way to bootstrap from a C implementation, which
is now stored in linux/bootstrap. The bootstrap C implementation uses some
literate programming tools that are now in linux/bootstrap/tools.

So the whole thing has gotten inverted. Each directory should build one
artifact and include the main sources (along with standard library). Tools
used for building it are relegated to sub-directories, even though those
tools are often useful in their own right, and have had lots of interesting
programs written using them.

A couple of things have gotten dropped in this process:
  - I had old ways to run on just a Linux kernel, or with a Soso kernel.
    No more.
  - I had some old tooling for running a single test at the cursor. I haven't
    used that lately. Maybe I'll bring it back one day.

The reorg isn't done yet. Still to do:
  - redo documentation everywhere. All the README files, all other markdown,
    particularly vocabulary.md.
  - clean up how-to-run comments at the start of programs everywhere
  - rethink what to do with the html/ directory. Do we even want to keep
    supporting it?

In spite of these shortcomings, all the scripts at the top-level, linux/
and linux/bootstrap are working. The names of the scripts also feel reasonable.
This is a good milestone to take stock at.
2021-03-03 22:21:03 -08:00

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) -> 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