.
[mu.git] / subx.md
blob055f86179032b94970379ac166aa1fd2cc46fe5a
1 ## SubX
3 SubX is a notation for a subset of x86 machine code. [The Mu translator](http://akkartik.github.io/mu/html/linux/mu.subx.html)
4 is implemented in SubX and also emits SubX code.
6 Here's an example program in SubX that adds 1 and 1 and returns the result to
7 the parent shell process:
9 ```sh
10 == code
11 Entry:
12   # ebx = 1
13   bb/copy-to-ebx  1/imm32
14   # increment ebx
15   43/increment-ebx
16   # exit(ebx)
17   e8/call  syscall_exit/disp32
18 ```
20 ## The syntax of SubX instructions
22 Just like in regular machine code, SubX programs consist mostly of instructions,
23 which are basically sequences of numbers (always in hex). Instructions consist
24 of words separated by whitespace. Words may be _opcodes_ (defining the
25 operation being performed) or _arguments_ (specifying the data the operation
26 acts on). Any word can have extra _metadata_ attached to it after `/`. Some
27 metadata is required (like the `/imm32` and `/imm8` above), but unrecognized
28 metadata is silently skipped so you can attach comments to words (like the
29 instruction name `/copy-to-ebx` above, or the `/exit` argument).
31 What do all these numbers mean? SubX supports a small subset of the 32-bit x86
32 instruction set that likely runs on your computer. (Think of the name as short
33 for "sub-x86".) The instruction set contains instructions like `89/copy`,
34 `01/add`, `3d/compare` and `51/push-ecx` which modify registers and a byte-addressable
35 memory. For a complete list of supported instructions, run `./help opcodes`.
37 The registers instructions operate on are as follows:
39 - Six 32-bit integer registers: `0/eax`, `1/ebx`, `2/ecx`, `3/edx`, `6/esi`
40   and `7/edi`.
41 - Two additional 32-bit registers: `4/esp` and `5/ebp`. (I suggest you only
42   use these to manage the call stack.)
43 - Eight 8-bit integer registers aliased with parts of the 32-bit registers:
44   `0/al`, `1/cl`, `2/dl`, `3/bl`, `4/ah`, `5/ch`, `6/dh` and `7/bh`.
45 - Eight 32-bit floating-point registers: `xmm0` through `xmm7`.
47 (Intel processors support a 16-bit mode and 64-bit mode. SubX will never
48 support them. There are also _many_ more instructions that SubX will never
49 support.)
51 While SubX doesn't provide the usual mnemonics for opcodes, it _does_ provide
52 error-checking. If you miss an argument or accidentally add an extra argument,
53 you'll get a nice error. SubX won't arbitrarily interpret bytes of data as
54 instructions or vice versa.
56 It's worth distinguishing between an instruction's arguments and its _operands_.
57 Arguments are provided directly in instructions. Operands are pieces of data
58 in register or memory that are operated on by instructions.
60 Intel processors typically operate on no more than two operands, and at most
61 one of them (the 'reg/mem' operand) can access memory. The address of the
62 reg/mem operand is constructed by expressions of one of these forms:
64   - `%reg`: operate on just a register, not memory
65   - `*reg`: look up memory with the address in some register
66   - `*(reg + disp)`: add a constant to the address in some register
67   - `*(base + (index << scale) + disp)` where `base` and `index` are registers,
68     and `scale` and `disp` are 2- and 32-bit constants respectively.
70 Under the hood, SubX turns expressions of these forms into multiple arguments
71 with metadata in some complex ways. See [the doc on bare SubX](subx_bare.md).
73 That covers the complexities of the reg/mem operand. The second operand is
74 simpler. It comes from exactly one of the following argument types:
76   - `/r32`
77   - displacement: `/disp8` or `/disp32`
78   - immediate: `/imm8` or `/imm32`
80 Putting all this together, here's an example that adds the integer in `eax` to
81 the one at address `edx`:
83 ```
84 01/add %edx 0/r32/eax
85 ```
87 ## The syntax of SubX programs
89 SubX programs consist of functions and global variables. It's very important
90 the two stay separate; executing data as code is the most common vector for
91 security issues. Consequently, SubX programs maintain separate code and data
92 _segments_. To add to a segment, specify it using a `==` header.
94 Details of segment header syntax depend on where you want the program to run:
96 * On Linux, segment headers consist of `==`, a name and an approximate
97   starting address (which might perturb slightly during translation)
99 * For bootable disks that run without an OS, segment headers consist of `==`
100   and a name. Boot disks really only have one segment of contiguous memory,
101   and segment headers merely affect parsing and error-checking.
103 Segments can be added to.
105 ```sh
106 == code 0x09000000  # first mention requires starting address on Linux
107 ...A...
109 == data 0x0a000000
110 ...B...
112 == code             # no address necessary when adding
113 ...C...
116 The `code` segment now contains the instructions of `A` as well as `C`.
118 Within the `code` segment, each line contains a comment, label or instruction.
119 Comments start with a `#` and are ignored. Labels should always be the first
120 word on a line, and they end with a `:`.
122 Instructions can refer to labels in displacement or immediate arguments, and
123 they'll obtain a value based on the address of the label: immediate arguments
124 will contain the address directly, while displacement arguments will contain
125 the difference between the address and the address of the current instruction.
126 The latter is mostly useful for `jump` and `call` instructions.
128 Functions are defined using labels. By convention, labels internal to functions
129 (that must only be jumped to) start with a `$`. Any other labels must only be
130 called, never jumped to. All labels must be unique.
132 Functions are called using the following syntax:
134 (func arg1 arg2 ...)
137 Function arguments must be either literals (integers or strings) or a reg/mem
138 operand using the syntax in the previous section.
140 Another special pair of labels are the block delimiters `{` and `}`. They can
141 be nested, and jump instructions can take arguments `loop` or `break` that
142 jump to the enclosing `{` and `}` respectively.
144 The data segment consists of labels as before and byte values. Referring to
145 data labels in either `code` segment instructions or `data` segment values
146 yields their address.
148 Automatic tests are an important part of SubX, and there's a simple mechanism
149 to provide a test harness: all functions that start with `test-` are called in
150 turn by a special, auto-generated function called `run-tests`. How you choose
151 to call it is up to you.
153 I try to keep things simple so that there's less work to do when implementing
154 SubX in SubX. But there _is_ one convenience: instructions can provide a
155 string literal surrounded by quotes (`"`) in an `imm32` argument. SubX will
156 transparently copy it to the `data` segment and replace it with its address.
157 Strings are the only place where a SubX word is allowed to contain spaces.
159 That should be enough information for writing SubX programs. The `linux/`
160 directory provides some fodder for practice in the `linux/ex*.subx` files,
161 giving a more gradual introduction to SubX features. In particular, you should
162 work through `linux/factorial4.subx`, which demonstrates all the above ideas in
163 concert.