5856
This commit is contained in:
parent
1b050736ee
commit
113bae7311
|
@ -27,7 +27,7 @@ put_new(Help, "syntax",
|
|||
"after a '/', but they can never contain whitespace. Metadata has no effect\n"
|
||||
"at runtime, but can be handy when rewriting macros.\n"
|
||||
"\n"
|
||||
"Check out the examples in the examples/ directory.\n"
|
||||
"Check out the example programs in the apps/ directory, particularly apps/ex*.\n"
|
||||
);
|
||||
:(before "End Help Contents")
|
||||
cerr << " syntax\n";
|
||||
|
|
43
Readme.md
43
Readme.md
|
@ -48,7 +48,7 @@ In priority order:
|
|||
|
||||
You get a thin syntax called SubX for programming in (a subset of) x86 machine
|
||||
code. (A memory-safe compiled language is [being designed](http://akkartik.name/post/mu-2019-2).)
|
||||
Here's a program (`examples/ex1.subx`) that returns 42:
|
||||
Here's a program (`apps/ex1.subx`) that returns 42:
|
||||
|
||||
```sh
|
||||
bb/copy-to-ebx 0x2a/imm32 # 42 in hex
|
||||
|
@ -59,8 +59,8 @@ Here's a program (`examples/ex1.subx`) that returns 42:
|
|||
You can generate tiny zero-dependency ELF binaries with it that run on Linux.
|
||||
|
||||
```sh
|
||||
$ ./subx translate init.linux examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac
|
||||
$ ./examples/ex1 # only on Linux
|
||||
$ ./subx translate init.linux apps/ex1.subx -o apps/ex1 # on Linux or BSD or Mac
|
||||
$ ./apps/ex1 # only on Linux
|
||||
$ echo $?
|
||||
42
|
||||
```
|
||||
|
@ -72,7 +72,7 @@ You can run the generated binaries on an interpreter/VM for better error
|
|||
messages.
|
||||
|
||||
```sh
|
||||
$ ./subx run examples/ex1 # on Linux or BSD or Mac
|
||||
$ ./subx run apps/ex1 # on Linux or BSD or Mac
|
||||
$ echo $?
|
||||
42
|
||||
```
|
||||
|
@ -80,11 +80,11 @@ messages.
|
|||
Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/tools/browse_trace.readme.md).
|
||||
|
||||
```sh
|
||||
$ ./subx --debug translate init.linux examples/factorial.subx -o examples/factorial
|
||||
$ ./subx --debug translate init.linux apps/factorial.subx -o apps/factorial
|
||||
saving address->label information to 'labels'
|
||||
saving address->source information to 'source_lines'
|
||||
|
||||
$ ./subx --debug --trace run examples/factorial
|
||||
$ ./subx --debug --trace run apps/factorial
|
||||
saving trace to 'last_run'
|
||||
|
||||
$ tools/browse_trace last_run # text-mode debugger UI
|
||||
|
@ -111,14 +111,14 @@ You can use SubX to translate itself. For example, running natively on Linux:
|
|||
$ chmod +x hex survey pack assort dquotes tests
|
||||
|
||||
# use the generated translator phases to translate SubX programs
|
||||
$ cat init.linux examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
|
||||
$ cat init.linux apps/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
|
||||
$ chmod +x a.elf
|
||||
$ ./a.elf
|
||||
$ echo $?
|
||||
42
|
||||
|
||||
# or, automating the above steps
|
||||
$ ./translate_subx init.linux examples/ex1.subx
|
||||
$ ./translate_subx init.linux apps/ex1.subx
|
||||
$ ./a.elf
|
||||
$ echo $?
|
||||
42
|
||||
|
@ -142,7 +142,7 @@ work on a cloud server.)
|
|||
$ sudo apt install util-linux nasm xorriso # maybe also dosfstools and mtools
|
||||
# package up a "hello world" program with a third-party kernel into mu_soso.iso
|
||||
# requires sudo
|
||||
$ ./gen_soso_iso init.soso examples/ex6.subx
|
||||
$ ./gen_soso_iso init.soso apps/ex6.subx
|
||||
# try it out
|
||||
$ qemu-system-i386 -cdrom mu_soso.iso
|
||||
```
|
||||
|
@ -154,7 +154,7 @@ kernel; that number will gradually go down.)
|
|||
|
||||
```sh
|
||||
$ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso
|
||||
$ ./gen_linux_iso init.linux examples/ex6.subx
|
||||
$ ./gen_linux_iso init.linux apps/ex6.subx
|
||||
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
|
||||
```
|
||||
|
||||
|
@ -299,7 +299,7 @@ and digest it:
|
|||
|
||||
Here's a more meaty example:
|
||||
|
||||
<img alt='examples/ex3.subx' src='html/ex3.png'>
|
||||
<img alt='apps/ex3.subx' src='html/ex3.png'>
|
||||
|
||||
This program sums the first 10 natural numbers. By convention I use horizontal
|
||||
tabstops to help read instructions, dots to help follow the long lines,
|
||||
|
@ -313,8 +313,8 @@ like decimal numbers.
|
|||
Try running this example now:
|
||||
|
||||
```sh
|
||||
$ ./subx translate init.linux examples/ex3.subx -o examples/ex3
|
||||
$ ./subx run examples/ex3
|
||||
$ ./subx translate init.linux apps/ex3.subx -o apps/ex3
|
||||
$ ./subx run apps/ex3
|
||||
$ echo $?
|
||||
55
|
||||
```
|
||||
|
@ -322,7 +322,7 @@ $ echo $?
|
|||
If you're on Linux you can also run it natively:
|
||||
|
||||
```sh
|
||||
$ ./examples/ex3
|
||||
$ ./apps/ex3
|
||||
$ echo $?
|
||||
55
|
||||
```
|
||||
|
@ -413,13 +413,14 @@ SubX will transparently copy it to the `data` segment and replace it with its
|
|||
address. Strings are the only place where a SubX word is allowed to contain
|
||||
spaces.
|
||||
|
||||
That should be enough information for writing SubX programs. The `examples/`
|
||||
directory provides some fodder for practice, giving a more gradual introduction
|
||||
to SubX features. This repo includes the binary for all examples. At any
|
||||
commit, an example's binary should be identical bit for bit with the result of
|
||||
translating the corresponding `.subx` file. The binary should also be natively
|
||||
runnable on a Linux system running on Intel x86 processors, either 32- or
|
||||
64-bit. If either of these invariants is broken it's a bug on my part.
|
||||
That should be enough information for writing SubX programs. The `apps/`
|
||||
directory provides some fodder for practice in the `apps/ex*` files, giving a
|
||||
more gradual introduction to SubX features. This repo includes binaries for
|
||||
all examples. At any commit, an example's binary should be identical bit for
|
||||
bit with the result of translating the corresponding `.subx` file. The binary
|
||||
should also be natively runnable on a Linux system running on Intel x86
|
||||
processors, either 32- or 64-bit. If either of these invariants is broken it's
|
||||
a bug on my part.
|
||||
|
||||
## Running
|
||||
|
||||
|
|
|
@ -1,2 +1,11 @@
|
|||
Larger programs than in the examples/ subdirectory, combining the techniques
|
||||
demonstrated there.
|
||||
Some apps written in SubX and Mu, in 3 categories:
|
||||
|
||||
* `ex*`: small stand-alone examples that don't need any of the shared code at
|
||||
the top-level. They each have a simple pedagogical goal. Try these first.
|
||||
|
||||
* Code unique to phases of our build toolchain:
|
||||
* Core SubX: `hex`, `survey`, `pack`, `dquotes`, `assort`, `tests`
|
||||
* Syntax sugar for SubX: `sigils`, `calls`, `braces`
|
||||
* More ambitious translator for a memory-safe language (in progress): `mu`
|
||||
|
||||
* Miscellaneous test programs.
|
||||
|
|
9
edit
9
edit
|
@ -12,12 +12,7 @@ fi
|
|||
|
||||
if [[ $EDITOR == *'vim'* ]]
|
||||
then
|
||||
LOCAL_SETTINGS='-S vimrc.vim'
|
||||
fi
|
||||
|
||||
if [[ $1 == 'ex'* ]]
|
||||
then
|
||||
eval $EDITOR $LOCAL_SETTINGS examples/$1.subx
|
||||
$EDITOR -S vimrc.vim apps/$1.subx
|
||||
else
|
||||
eval $EDITOR $LOCAL_SETTINGS apps/$1.subx
|
||||
$EDITOR apps/$1.subx
|
||||
fi
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Small example programs, each with a simple pedagogical goal.
|
||||
|
||||
They also help to validate SubX instruction semantics against native x86
|
||||
hardware. For example, loading a single byte to a register would for some time
|
||||
clear the rest of the register. This behavior was internally consistent with
|
||||
unit tests. It took running an example binary natively to catch the discrepancy.
|
104
test_apps
104
test_apps
|
@ -28,144 +28,144 @@ echo "== translating and running using C++"
|
|||
# example programs
|
||||
|
||||
echo ex1
|
||||
./subx translate init.$OS examples/ex1.subx -o examples/ex1
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex1
|
||||
./subx translate init.$OS apps/ex1.subx -o apps/ex1
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex1
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex1 || ret=$?
|
||||
./subx run apps/ex1 || ret=$?
|
||||
test $ret -eq 42 # life, the universe and everything
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex1 || ret=$?
|
||||
apps/ex1 || ret=$?
|
||||
test $ret -eq 42 # life, the universe and everything
|
||||
}
|
||||
|
||||
echo ex2
|
||||
./subx translate init.$OS examples/ex2.subx -o examples/ex2
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex2
|
||||
./subx translate init.$OS apps/ex2.subx -o apps/ex2
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex2
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex2 || ret=$?
|
||||
./subx run apps/ex2 || ret=$?
|
||||
test $ret -eq 2 # 1 + 1
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex2 || ret=$?
|
||||
apps/ex2 || ret=$?
|
||||
test $ret -eq 2 # 1 + 1
|
||||
}
|
||||
|
||||
echo ex3
|
||||
./subx translate init.$OS examples/ex3.subx -o examples/ex3
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex3
|
||||
./subx translate init.$OS apps/ex3.subx -o apps/ex3
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex3
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex3 || ret=$?
|
||||
./subx run apps/ex3 || ret=$?
|
||||
test $ret -eq 55 # 1 + 2 + ... + 10
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex3 || ret=$?
|
||||
apps/ex3 || ret=$?
|
||||
test $ret -eq 55 # 1 + 2 + ... + 10
|
||||
}
|
||||
|
||||
echo ex4
|
||||
./subx translate init.$OS examples/ex4.subx -o examples/ex4
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex4
|
||||
./subx translate init.$OS apps/ex4.subx -o apps/ex4
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex4
|
||||
test $EMULATED && {
|
||||
echo a | ./subx run examples/ex4 >ex4.out || true
|
||||
echo a | ./subx run apps/ex4 >ex4.out || true
|
||||
test `cat ex4.out` = 'a'
|
||||
}
|
||||
test $NATIVE && {
|
||||
echo a | examples/ex4 >ex4.out || true
|
||||
echo a | apps/ex4 >ex4.out || true
|
||||
test `cat ex4.out` = 'a'
|
||||
}
|
||||
|
||||
echo ex5
|
||||
./subx translate init.$OS examples/ex5.subx -o examples/ex5
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex5
|
||||
./subx translate init.$OS apps/ex5.subx -o apps/ex5
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex5
|
||||
test $EMULATED && {
|
||||
echo a | ./subx run examples/ex5 >ex5.out || true
|
||||
echo a | ./subx run apps/ex5 >ex5.out || true
|
||||
test `cat ex5.out` = 'a'
|
||||
}
|
||||
test $NATIVE && {
|
||||
echo a | examples/ex5 >ex5.out || true
|
||||
echo a | apps/ex5 >ex5.out || true
|
||||
test `cat ex5.out` = 'a'
|
||||
}
|
||||
|
||||
echo ex6
|
||||
./subx translate init.$OS examples/ex6.subx -o examples/ex6
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex6
|
||||
./subx translate init.$OS apps/ex6.subx -o apps/ex6
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex6
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex6 >ex6.out || true
|
||||
./subx run apps/ex6 >ex6.out || true
|
||||
test "`cat ex6.out`" = 'Hello, world!'
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex6 >ex6.out || true
|
||||
apps/ex6 >ex6.out || true
|
||||
test "`cat ex6.out`" = 'Hello, world!'
|
||||
}
|
||||
|
||||
echo ex7
|
||||
./subx translate init.$OS examples/ex7.subx -o examples/ex7
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex7
|
||||
./subx translate init.$OS apps/ex7.subx -o apps/ex7
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex7
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex7 || ret=$?
|
||||
./subx run apps/ex7 || ret=$?
|
||||
test $ret -eq 97 # 'a'
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex7 || ret=$?
|
||||
apps/ex7 || ret=$?
|
||||
test $ret -eq 97 # 'a'
|
||||
}
|
||||
|
||||
echo ex8
|
||||
./subx translate init.$OS examples/ex8.subx -o examples/ex8
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex8
|
||||
./subx translate init.$OS apps/ex8.subx -o apps/ex8
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex8
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex8 abcd || ret=$?
|
||||
./subx run apps/ex8 abcd || ret=$?
|
||||
test $ret -eq 4 # length('abcd')
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex8 abcd || ret=$?
|
||||
apps/ex8 abcd || ret=$?
|
||||
test $ret -eq 4 # length('abcd')
|
||||
}
|
||||
|
||||
echo ex9
|
||||
./subx translate init.$OS examples/ex9.subx -o examples/ex9
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex9
|
||||
./subx translate init.$OS apps/ex9.subx -o apps/ex9
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex9
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex9 z x || ret=$?
|
||||
./subx run apps/ex9 z x || ret=$?
|
||||
test $ret -eq 2 # 'z' - 'x'
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex9 z x || ret=$?
|
||||
apps/ex9 z x || ret=$?
|
||||
test $ret -eq 2 # 'z' - 'x'
|
||||
}
|
||||
|
||||
echo ex10
|
||||
./subx translate init.$OS examples/ex10.subx -o examples/ex10
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex10
|
||||
./subx translate init.$OS apps/ex10.subx -o apps/ex10
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex10
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex10 abc abc || ret=$?
|
||||
./subx run apps/ex10 abc abc || ret=$?
|
||||
test $ret -eq 1 # equal
|
||||
./subx run examples/ex10 abc abcd # 0; not equal
|
||||
./subx run apps/ex10 abc abcd # 0; not equal
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex10 abc abc || ret=$?
|
||||
apps/ex10 abc abc || ret=$?
|
||||
test $ret -eq 1 # equal
|
||||
examples/ex10 abc abcd # 0; not equal
|
||||
apps/ex10 abc abcd # 0; not equal
|
||||
}
|
||||
|
||||
echo ex11
|
||||
./subx translate init.$OS examples/ex11.subx -o examples/ex11
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex11
|
||||
./subx translate init.$OS apps/ex11.subx -o apps/ex11
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex11
|
||||
test $EMULATED && {
|
||||
./subx run examples/ex11
|
||||
./subx run apps/ex11
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
examples/ex11
|
||||
apps/ex11
|
||||
echo
|
||||
}
|
||||
|
||||
echo ex12
|
||||
./subx translate init.$OS examples/ex12.subx -o examples/ex12
|
||||
test "$1" = 'record' || git diff --exit-code examples/ex12
|
||||
test $EMULATED && ./subx run examples/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0
|
||||
test $NATIVE && examples/ex12
|
||||
./subx translate init.$OS apps/ex12.subx -o apps/ex12
|
||||
test "$1" = 'record' || git diff --exit-code apps/ex12
|
||||
test $EMULATED && ./subx run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0
|
||||
test $NATIVE && apps/ex12
|
||||
|
||||
# Larger apps that use the standard library.
|
||||
|
||||
|
@ -304,8 +304,8 @@ echo "== translating using SubX (native only)"
|
|||
for n in `seq 1 12`
|
||||
do
|
||||
echo ex$n
|
||||
./translate_subx init.$OS examples/ex$n.subx
|
||||
diff examples/ex$n a.elf
|
||||
./translate_subx init.$OS apps/ex$n.subx
|
||||
diff apps/ex$n a.elf
|
||||
done
|
||||
|
||||
# Larger apps that use the standard library.
|
||||
|
|
10
vimrc.vim
10
vimrc.vim
|
@ -44,15 +44,7 @@ else
|
|||
endif
|
||||
|
||||
function! EditSubx(cmd, arg)
|
||||
exec "silent! " . a:cmd . " " . SubxPath(a:arg)
|
||||
endfunction
|
||||
|
||||
function! SubxPath(arg)
|
||||
if a:arg =~ "^ex"
|
||||
return "examples/" . a:arg . ".subx"
|
||||
else
|
||||
return "apps/" . a:arg . ".subx"
|
||||
endif
|
||||
exec "silent! " . a:cmd . " apps/" . a:arg . ".subx"
|
||||
endfunction
|
||||
|
||||
" we often want to crib lines of machine code from other files
|
||||
|
|
Loading…
Reference in New Issue