## SubX: a simplistic assembly language SubX is a minimalist assembly language designed: * to explore ways to turn arbitrary manual tests into reproducible automated tests, * to be easy to implement in itself, and * to help learn and teach the x86 instruction set. ``` $ git clone https://github.com/akkartik/mu $ cd mu/subx $ ./subx # print out a help message ``` [![Build Status](https://api.travis-ci.org/akkartik/mu.svg)](https://travis-ci.org/akkartik/mu) Expanding on the first bullet, it hopes to support more comprehensive tests by: 0. Running generated binaries in _emulated mode_. Emulated mode is slower than native execution (which will also work), but there's more sanity checking, and more descriptive error messages for common low-level problems. ```sh $ ./subx translate examples/ex1.subx -o examples/ex1 $ ./examples/ex1 # only on Linux $ echo $? 42 $ ./subx run examples/ex1 # on Linux or BSD or OS X $ echo $? 42 ``` The assembly syntax is designed so the assembler (`subx translate`) has very little to do, making it feasible to reimplement in itself. Programmers have to explicitly specify all opcodes and operands. ```sh (just for syntax highlighting) # exit(42) bb/copy-to-EBX 0x2a/imm32 # 42 in hex b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 ``` To keep code readable you can add _metadata_ to any word after a `/`. Metadata can be just comments for readers, and they'll be ignored. They can also trigger checks. Here, tagging operands with the `imm32` type allows SubX to check that instructions have precisely the operand types they should. x86 instructions have 14 types of operands, and missing one causes all future instructions to go off the rails, interpreting operands as opcodes and vice versa. So this is a useful check. 1. Designing testable wrappers for operating system interfaces. For example, it can `read()` from or `write()` to fake in-memory files in tests. More details [below](#subx-library). We are continuing to port syscalls from [the old Mu VM in the parent directory](https://github.com/akkartik/mu). 2. Supporting a special _trace_ stream in addition to the default `stdin`, `stdout` and `stderr` streams. The trace stream is designed for programs to emit structured facts they deduce about their domain as they execute. Tests can then check the set of facts deduced in addition to the results of the function under test. This form of _automated whitebox testing_ permits writing tests for performance, fault tolerance, deadlock-freedom, memory usage, etc. For example, if a sort function traces each swap, a performance test could check that the number of swaps doesn't quadruple when the size of the input doubles. The hypothesis is that designing the entire system to be testable from day 1 and from the ground up would radically impact the culture of an eco-system in a way that no bolted-on tool or service at higher levels can replicate. It would make it easier to write programs that can be [easily understood by newcomers](http://akkartik.name/about). It would reassure authors that an app is free from regression if all automated tests pass. It would make the stack easy to rewrite and simplify by dropping features, without fear that a subset of targeted apps might break. As a result people might fork projects more easily, and also exchange code between disparate forks more easily (copy the tests over, then try copying code over and making tests pass, rewriting and polishing where necessary). The community would have in effect a diversified portfolio of forks, a “wavefront” of possible combinations of features and alternative implementations of features instead of the single trunk with monotonically growing complexity that we get today. Application writers who wrote thorough tests for their apps (something they just can’t do today) would be able to bounce around between forks more easily without getting locked in to a single one as currently happens. However, that vision is far away, and SubX is just a first, hesitant step. SubX supports a small, regular subset of the 32-bit x86 instruction set. (Think of the name as short for "sub-x86".) - Only instructions that operate on the 32-bit integer E\*X registers, and a couple of instructions for operating on 8-bit values. No floating-point yet. Most legacy registers will never be supported. - Only instructions that assume a flat address space; legacy instructions that use segment registers will never be supported. - No instructions that check the carry or parity flags; arithmetic operations always operate on signed integers (while bitwise operations always operate on unsigned integers). - Only relative jump instructions (with 8-bit or 32-bit offsets). The (ru
# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Workaround to allow running single test cases directly"""
try:
from __init__ import init, Fake, OK, raise_ok
except:
from test import init, Fake, OK, raise_ok