From 113bae7311b63e55e55160970718d19bfeeb56c3 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Wed, 1 Jan 2020 17:23:29 -0800 Subject: 5856 --- 011run.cc | 2 +- Readme.md | 43 ++--- apps/Readme.md | 13 +- apps/ex1 | Bin 0 -> 197 bytes apps/ex1.subx | 18 ++ apps/ex10 | Bin 0 -> 264 bytes apps/ex10.subx | 69 +++++++ apps/ex11 | Bin 0 -> 1178 bytes apps/ex11.subx | 355 ++++++++++++++++++++++++++++++++++++ apps/ex12 | Bin 0 -> 234 bytes apps/ex12.subx | 43 +++++ apps/ex2 | Bin 0 -> 198 bytes apps/ex2.subx | 20 ++ apps/ex3 | Bin 0 -> 215 bytes apps/ex3.subx | 36 ++++ apps/ex4 | Bin 0 -> 236 bytes apps/ex4.subx | 39 ++++ apps/ex5 | Bin 0 -> 238 bytes apps/ex5.subx | 41 +++++ apps/ex6 | Bin 0 -> 232 bytes apps/ex6.subx | 35 ++++ apps/ex7 | Bin 0 -> 366 bytes apps/ex7.subx | 98 ++++++++++ apps/ex8 | Bin 0 -> 234 bytes apps/ex8.subx | 60 ++++++ apps/ex9 | Bin 0 -> 228 bytes apps/ex9.subx | 52 ++++++ edit | 9 +- examples/Readme.md | 6 - examples/ex1 | Bin 197 -> 0 bytes examples/ex1.subx | 18 -- examples/ex10 | Bin 264 -> 0 bytes examples/ex10.subx | 69 ------- examples/ex11 | Bin 1178 -> 0 bytes examples/ex11.subx | 355 ------------------------------------ examples/ex12 | Bin 234 -> 0 bytes examples/ex12.subx | 43 ----- examples/ex2 | Bin 198 -> 0 bytes examples/ex2.subx | 20 -- examples/ex3 | Bin 215 -> 0 bytes examples/ex3.subx | 36 ---- examples/ex4 | Bin 236 -> 0 bytes examples/ex4.subx | 39 ---- examples/ex5 | Bin 238 -> 0 bytes examples/ex5.subx | 41 ----- examples/ex6 | Bin 232 -> 0 bytes examples/ex6.subx | 35 ---- examples/ex7 | Bin 366 -> 0 bytes examples/ex7.subx | 98 ---------- examples/ex8 | Bin 234 -> 0 bytes examples/ex8.subx | 60 ------ examples/ex9 | Bin 228 -> 0 bytes examples/ex9.subx | 52 ------ html/apps/ex1.subx.html | 77 ++++++++ html/apps/ex10.subx.html | 132 ++++++++++++++ html/apps/ex11.subx.html | 421 +++++++++++++++++++++++++++++++++++++++++++ html/apps/ex12.subx.html | 104 +++++++++++ html/apps/ex2.subx.html | 79 ++++++++ html/apps/ex3.subx.html | 98 ++++++++++ html/apps/ex4.subx.html | 99 ++++++++++ html/apps/ex5.subx.html | 102 +++++++++++ html/apps/ex6.subx.html | 96 ++++++++++ html/apps/ex7.subx.html | 159 ++++++++++++++++ html/apps/ex8.subx.html | 123 +++++++++++++ html/apps/ex9.subx.html | 114 ++++++++++++ html/examples/ex1.subx.html | 77 -------- html/examples/ex10.subx.html | 132 -------------- html/examples/ex11.subx.html | 421 ------------------------------------------- html/examples/ex12.subx.html | 104 ----------- html/examples/ex2.subx.html | 79 -------- html/examples/ex3.subx.html | 98 ---------- html/examples/ex4.subx.html | 99 ---------- html/examples/ex5.subx.html | 102 ----------- html/examples/ex6.subx.html | 96 ---------- html/examples/ex7.subx.html | 159 ---------------- html/examples/ex8.subx.html | 123 ------------- html/examples/ex9.subx.html | 114 ------------ test_apps | 104 +++++------ vimrc.vim | 10 +- 79 files changed, 2559 insertions(+), 2568 deletions(-) create mode 100755 apps/ex1 create mode 100644 apps/ex1.subx create mode 100755 apps/ex10 create mode 100644 apps/ex10.subx create mode 100755 apps/ex11 create mode 100644 apps/ex11.subx create mode 100755 apps/ex12 create mode 100644 apps/ex12.subx create mode 100755 apps/ex2 create mode 100644 apps/ex2.subx create mode 100755 apps/ex3 create mode 100644 apps/ex3.subx create mode 100755 apps/ex4 create mode 100644 apps/ex4.subx create mode 100755 apps/ex5 create mode 100644 apps/ex5.subx create mode 100755 apps/ex6 create mode 100644 apps/ex6.subx create mode 100755 apps/ex7 create mode 100644 apps/ex7.subx create mode 100755 apps/ex8 create mode 100644 apps/ex8.subx create mode 100755 apps/ex9 create mode 100644 apps/ex9.subx delete mode 100644 examples/Readme.md delete mode 100755 examples/ex1 delete mode 100644 examples/ex1.subx delete mode 100755 examples/ex10 delete mode 100644 examples/ex10.subx delete mode 100755 examples/ex11 delete mode 100644 examples/ex11.subx delete mode 100755 examples/ex12 delete mode 100644 examples/ex12.subx delete mode 100755 examples/ex2 delete mode 100644 examples/ex2.subx delete mode 100755 examples/ex3 delete mode 100644 examples/ex3.subx delete mode 100755 examples/ex4 delete mode 100644 examples/ex4.subx delete mode 100755 examples/ex5 delete mode 100644 examples/ex5.subx delete mode 100755 examples/ex6 delete mode 100644 examples/ex6.subx delete mode 100755 examples/ex7 delete mode 100644 examples/ex7.subx delete mode 100755 examples/ex8 delete mode 100644 examples/ex8.subx delete mode 100755 examples/ex9 delete mode 100644 examples/ex9.subx create mode 100644 html/apps/ex1.subx.html create mode 100644 html/apps/ex10.subx.html create mode 100644 html/apps/ex11.subx.html create mode 100644 html/apps/ex12.subx.html create mode 100644 html/apps/ex2.subx.html create mode 100644 html/apps/ex3.subx.html create mode 100644 html/apps/ex4.subx.html create mode 100644 html/apps/ex5.subx.html create mode 100644 html/apps/ex6.subx.html create mode 100644 html/apps/ex7.subx.html create mode 100644 html/apps/ex8.subx.html create mode 100644 html/apps/ex9.subx.html delete mode 100644 html/examples/ex1.subx.html delete mode 100644 html/examples/ex10.subx.html delete mode 100644 html/examples/ex11.subx.html delete mode 100644 html/examples/ex12.subx.html delete mode 100644 html/examples/ex2.subx.html delete mode 100644 html/examples/ex3.subx.html delete mode 100644 html/examples/ex4.subx.html delete mode 100644 html/examples/ex5.subx.html delete mode 100644 html/examples/ex6.subx.html delete mode 100644 html/examples/ex7.subx.html delete mode 100644 html/examples/ex8.subx.html delete mode 100644 html/examples/ex9.subx.html diff --git a/011run.cc b/011run.cc index 194676d8..585f9930 100644 --- a/011run.cc +++ b/011run.cc @@ -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"; diff --git a/Readme.md b/Readme.md index 1d0329de..04bd4b5a 100644 --- a/Readme.md +++ b/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: -examples/ex3.subx +apps/ex3.subx 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 diff --git a/apps/Readme.md b/apps/Readme.md index 1861d949..1e1a5685 100644 --- a/apps/Readme.md +++ b/apps/Readme.md @@ -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. diff --git a/apps/ex1 b/apps/ex1 new file mode 100755 index 00000000..5f17bc66 Binary files /dev/null and b/apps/ex1 differ diff --git a/apps/ex1.subx b/apps/ex1.subx new file mode 100644 index 00000000..5558d310 --- /dev/null +++ b/apps/ex1.subx @@ -0,0 +1,18 @@ +# First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html +# Just return 42. +# +# To run: +# $ ./subx translate init.linux examples/ex1.2.subx -o examples/ex1 +# $ ./subx run examples/ex1 +# Expected result: +# $ echo $? +# 42 + +== code + +Entry: +# exit(42) +bb/copy-to-ebx 2a/imm32 # 42 in hex +e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex10 b/apps/ex10 new file mode 100755 index 00000000..cb8973fe Binary files /dev/null and b/apps/ex10 differ diff --git a/apps/ex10.subx b/apps/ex10.subx new file mode 100644 index 00000000..c091fe52 --- /dev/null +++ b/apps/ex10.subx @@ -0,0 +1,69 @@ +# String comparison: return 1 iff the two args passed in at the commandline are equal. +# +# To run: +# $ ./subx translate init.linux examples/ex10.subx -o examples/ex10 +# $ ./subx run examples/ex10 abc abd +# Expected result: +# $ echo $? +# 0 # false + +== 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 + +Entry: # return argv-equal(argv[1], argv[2]) +# At the start of a SubX program: +# argc: *esp +# argv[0]: *(esp+4) +# argv[1]: *(esp+8) +# ... + # . prologue + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # argv-equal(argv[1], argv[2]) + # . . push argv[2] + ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) + # . . push argv[1] + ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) + # . . call + e8/call argv-equal/disp32 + # exit(eax) + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + e8/call syscall_exit/disp32 + +# compare two null-terminated ascii strings +# reason for the name: the only place we should have null-terminated ascii strings is from commandline args +argv-equal: # (s1, s2) : null-terminated ascii strings -> eax : boolean + # initialize s1 (ecx) and s2 (edx) + 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 1/r32/ecx 4/disp8 . # copy *(esp+4) to ecx + 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 2/r32/edx 8/disp8 . # copy *(esp+8) to edx +$argv-equal:loop: + # c1/eax, c2/ebx = *s1, *s2 + b8/copy-to-eax 0/imm32 + 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL + bb/copy-to-ebx 0/imm32 + 8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 3/r32/BL . . # copy byte at *edx to BL + # if (c1 == 0) break + 3d/compare-eax-and 0/imm32 + 74/jump-if-equal $argv-equal:break/disp8 + # if (c1 != c2) return false + 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx + 75/jump-if-not-equal $argv-equal:false/disp8 + # ++s1, ++s2 + 41/increment-ecx + 42/increment-edx + # end while + eb/jump $argv-equal:loop/disp8 +$argv-equal:break: + # if (c2 == 0) return true + 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32 # compare ebx + 75/jump-if-not-equal $argv-equal:false/disp8 +$argv-equal:success: + b8/copy-to-eax 1/imm32 + c3/return + # return false +$argv-equal:false: + b8/copy-to-eax 0/imm32 + c3/return + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex11 b/apps/ex11 new file mode 100755 index 00000000..1cb1aa5c Binary files /dev/null and b/apps/ex11 differ diff --git a/apps/ex11.subx b/apps/ex11.subx new file mode 100644 index 00000000..b235927d --- /dev/null +++ b/apps/ex11.subx @@ -0,0 +1,355 @@ +# Null-terminated vs length-prefixed ascii strings. +# +# By default we create strings with a 4-byte length prefix rather than a null suffix. +# However we still need null-prefixed strings when interacting with the Linux +# kernel in a few places. This layer implements a function for comparing +# a null-terminated 'kernel string' with a length-prefixed 'SubX string'. +# +# To run: +# $ ./subx translate init.linux examples/ex11.subx -o examples/ex11 +# $ ./subx run examples/ex11 # runs a series of tests +# ...... # all tests pass +# +# (We can't yet run the tests when given a "test" commandline argument, +# because checking for it would require the function being tested! Breakage +# would cause tests to not run, rather than to fail as we'd like.) + +== 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 + +Entry: # run all tests + e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + # exit(eax) + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + e8/call syscall_exit/disp32 + +# compare a null-terminated ascii string with a more idiomatic length-prefixed byte array +# reason for the name: the only place we should have null-terminated ascii strings is from commandline args +kernel-string-equal?: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> eax : boolean + # pseudocode: + # n = benchmark->length + # s1 = s + # s2 = benchmark->data + # i = 0 + # while i < n + # c1 = *s1 + # c2 = *s2 + # if (c1 == 0) return false + # if (c1 != c2) return false + # ++s1, ++s2, ++i + # return *s1 == 0 + # + # registers: + # i: ecx + # n: edx + # s1: edi + # s2: esi + # c1: eax + # c2: ebx + # + # . prologue + 55/push-ebp + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # s1/edi = s + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi + # n/edx = benchmark->length + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx + 8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx + # s2/esi = benchmark->data + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi + 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 4/imm32 # add to esi + # i/ecx = c1/eax = c2/ebx = 0 + b9/copy-to-ecx 0/imm32/exit + b8/copy-to-eax 0/imm32 + bb/copy-to-ebx 0/imm32 +$kernel-string-equal?:loop: + # if (i >= n) break + 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx + 7d/jump-if-greater-or-equal $kernel-string-equal?:break/disp8 + # c1 = *s1 + 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL + # c2 = *s2 + 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL + # if (c1 == 0) return false + 3d/compare-eax-and 0/imm32 + 74/jump-if-equal $kernel-string-equal?:false/disp8 + # if (c1 != c2) return false + 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx + 75/jump-if-not-equal $kernel-string-equal?:false/disp8 + # ++i + 41/increment-ecx + # ++s1 + 47/increment-edi + # ++s2 + 46/increment-esi + eb/jump $kernel-string-equal?:loop/disp8 +$kernel-string-equal?:break: + # return *s1 == 0 + 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL + 3d/compare-eax-and 0/imm32 + 75/jump-if-not-equal $kernel-string-equal?:false/disp8 +$kernel-string-equal?:true: + b8/copy-to-eax 1/imm32 + eb/jump $kernel-string-equal?:end/disp8 +$kernel-string-equal?:false: + b8/copy-to-eax 0/imm32 +$kernel-string-equal?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 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 + +# - tests + +test-compare-null-kernel-string-with-empty-array: + # eax = kernel-string-equal?(Null-kernel-string, "") + # . . push args + 68/push ""/imm32 + 68/push Null-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 1, msg) + # . . push args + 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 + 68/push 1/imm32/true + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-null-kernel-string-with-non-empty-array: + # eax = kernel-string-equal?(Null-kernel-string, "Abc") + # . . push args + 68/push "Abc"/imm32 + 68/push Null-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 0, msg) + # . . push args + 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 + 68/push 0/imm32/false + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-kernel-string-with-equal-array: + # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc") + # . . push args + 68/push "Abc"/imm32 + 68/push _test-Abc-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 1, msg) + # . . push args + 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 + 68/push 1/imm32/true + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-kernel-string-with-inequal-array: + # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc") + # . . push args + 68/push "Adc"/imm32 + 68/push _test-Abc-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 0, msg) + # . . push args + 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 + 68/push 0/imm32/false + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-kernel-string-with-empty-array: + # eax = kernel-string-equal?(_test-Abc-kernel-string, "") + # . . push args + 68/push ""/imm32 + 68/push _test-Abc-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 0, msg) + # . . push args + 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 + 68/push 0/imm32/false + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-kernel-string-with-shorter-array: + # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab") + # . . push args + 68/push "Ab"/imm32 + 68/push _test-Abc-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 0, msg) + # . . push args + 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 + 68/push 0/imm32/false + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +test-compare-kernel-string-with-longer-array: + # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd") + # . . push args + 68/push "Abcd"/imm32 + 68/push _test-Abc-kernel-string/imm32 + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-ints-equal(eax, 0, msg) + # . . push args + 68/push "F - test-compare-kernel-string-with-longer-array"/imm32 + 68/push 0/imm32/false + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + c3/return + +# - helpers + +# print msg to stderr if a != b, otherwise print "." +check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean + # . prologue + 55/push-ebp + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # . save registers + 51/push-ecx + 53/push-ebx + # load args into eax, ebx and ecx + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx + # if (eax == b/ebx) print('.') and return + 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx + 75/jump-if-unequal $check-ints-equal:else/disp8 + # . write-stderr('.') + # . . push args + 68/push "."/imm32 + # . . call + e8/call write-stderr/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp + # . return + eb/jump $check-ints-equal:end/disp8 + # otherwise print(msg) +$check-ints-equal:else: + # copy msg into ecx + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # copy *(ebp+16) to ecx + # print(ecx) + # . . push args + 51/push-ecx + # . . call + e8/call write-stderr/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp + # print newline + # . . push args + 68/push Newline/imm32 + # . . call + e8/call write-stderr/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp +$check-ints-equal:end: + # . restore registers + 5b/pop-to-ebx + 59/pop-to-ecx + # end + 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 5d/pop-to-ebp + c3/return + +write-stderr: # s : (address array byte) -> + # . prologue + 55/push-ebp + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # syscall(write, 2/stderr, (data) s+4, (size) *s) + # . . fd = 2 (stderr) + bb/copy-to-ebx 2/imm32 + # . . x = s+4 + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx + 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx + # . . size = *s + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 8/disp8 . # copy *(ebp+8) to edx + 8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx + # . . syscall + e8/call syscall_write/disp32 + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . end + 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 5d/pop-to-ebp + c3/return + +== data + +Newline: + # size + 1/imm32 + # data + 0a/newline + +# for kernel-string-equal tests +Null-kernel-string: + 00/null + +_test-Abc-kernel-string: + 41/A 62/b 63/c 00/null + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex12 b/apps/ex12 new file mode 100755 index 00000000..80e5deeb Binary files /dev/null and b/apps/ex12 differ diff --git a/apps/ex12.subx b/apps/ex12.subx new file mode 100644 index 00000000..9c67f909 --- /dev/null +++ b/apps/ex12.subx @@ -0,0 +1,43 @@ +# Example showing mmap syscall. +# Create a new segment using mmap, save the address, write to it. +# +# To run: +# $ ./subx translate init.linux examples/ex12.subx -o examples/ex12 +# $ ./subx run examples/ex12 +# You shouldn't get a segmentation fault. + +== 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 + +Entry: + # mmap(Mmap-new-segment->len) + bb/copy-to-ebx Mmap-new-segment/imm32 + e8/call syscall_mmap/disp32 + + # write to *eax to check that we have access to the newly-allocated segment + c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0x34/imm32 # copy to *eax + + # exit(eax) + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + e8/call syscall_exit/disp32 + +== data + +# various constants used here were found in the Linux sources (search for file mman-common.h) +Mmap-new-segment: # type mmap_arg_struct + # addr + 0/imm32 + # len + 0x100/imm32 + # protection flags + 3/imm32 # PROT_READ | PROT_WRITE + # sharing flags + 0x22/imm32 # MAP_PRIVATE | MAP_ANONYMOUS + # fd + -1/imm32 # since MAP_ANONYMOUS is specified + # offset + 0/imm32 # since MAP_ANONYMOUS is specified + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex2 b/apps/ex2 new file mode 100755 index 00000000..5e0c1be1 Binary files /dev/null and b/apps/ex2 differ diff --git a/apps/ex2.subx b/apps/ex2.subx new file mode 100644 index 00000000..8df4c62c --- /dev/null +++ b/apps/ex2.subx @@ -0,0 +1,20 @@ +# Add 1 and 1, and return the result in the exit code. +# +# To run: +# $ ./subx translate init.linux examples/ex2.subx -o examples/ex2 +# $ ./subx run examples/ex2 +# Expected result: +# $ echo $? +# 2 + +== code + +Entry: +# ebx = 1 +bb/copy-to-ebx 1/imm32 +# increment ebx +43/increment-ebx +# exit(ebx) +e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex3 b/apps/ex3 new file mode 100755 index 00000000..af787c11 Binary files /dev/null and b/apps/ex3 differ diff --git a/apps/ex3.subx b/apps/ex3.subx new file mode 100644 index 00000000..f6f8c17d --- /dev/null +++ b/apps/ex3.subx @@ -0,0 +1,36 @@ +# Add the first 10 numbers, and return the result in the exit code. +# +# To run: +# $ ./subx translate init.linux examples/ex3.subx -o examples/ex3 +# $ ./subx run examples/ex3 +# Expected result: +# $ echo $? +# 55 + +== 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 + +Entry: + # result: ebx = 0 + bb/copy-to-ebx 0/imm32 + # counter: ecx = 1 + b9/copy-to-ecx 1/imm32 + +$loop: + # if (counter > 10) break + 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0xa/imm32 # compare ecx + 7f/jump-if-greater $exit/disp8 + # result += counter + 01/add 3/mod/direct 3/rm32/ebx . . . 1/r32/ecx . . # add ecx to ebx + # ++counter + 41/increment-ecx + # loop + eb/jump $loop/disp8 + +$exit: + # exit(ebx) + e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex4 b/apps/ex4 new file mode 100755 index 00000000..35ade1ee Binary files /dev/null and b/apps/ex4 differ diff --git a/apps/ex4.subx b/apps/ex4.subx new file mode 100644 index 00000000..78a97433 --- /dev/null +++ b/apps/ex4.subx @@ -0,0 +1,39 @@ +# Read a character from stdin, save it to a global, write it to stdout. +# +# To run: +# $ ./subx translate init.linux examples/ex4.subx -o examples/ex4 +# $ ./subx run examples/ex4 + +== data + +# the global variable we save to +X: + 0/imm32 # space for read() to write to + +== code + +Entry: +# read(stdin, X, 1) +# . fd = 0 (stdin) +bb/copy-to-ebx 0/imm32 +# . data = X (location to write result to) +b9/copy-to-ecx X/imm32 +# . size = 1 character +ba/copy-to-edx 1/imm32 +# . syscall +e8/call syscall_read/disp32 + +# write(stdout, X, 1) +# . fd = 1 (stdout) +bb/copy-to-ebx 1/imm32 +# . initialize X (location to read from) +b9/copy-to-ecx X/imm32 +# . size = 1 character +ba/copy-to-edx 1/imm32 +# . syscall +e8/call syscall_write/disp32 + +# exit(ebx) +e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex5 b/apps/ex5 new file mode 100755 index 00000000..805cadc3 Binary files /dev/null and b/apps/ex5 differ diff --git a/apps/ex5.subx b/apps/ex5.subx new file mode 100644 index 00000000..bacef8d4 --- /dev/null +++ b/apps/ex5.subx @@ -0,0 +1,41 @@ +# Read a character from stdin, save it to a local on the stack, write it to stdout. +# +# To run: +# $ ./subx translate init.linux examples/ex5.subx -o examples/ex5 +# $ ./subx run examples/ex5 + +== 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 + +Entry: + + # allocate x on the stack + 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # subtract from esp + + # read(stdin, x, 1) + # . fd = 0 (stdin) + bb/copy-to-ebx 0/imm32 + # . data = x (location to write result to) + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx + # . size = 1 character + ba/copy-to-edx 1/imm32 + # . syscall + e8/call syscall_read/disp32 + + # syscall(write, stdout, x, 1) + # . fd = 1 (stdout) + bb/copy-to-ebx 1/imm32 + # . data = x (location to read from) + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx + # . size = 1 character + ba/copy-to-edx 1/imm32 + # . syscall + b8/copy-to-eax 4/imm32/write + cd/syscall 0x80/imm8 + + # exit(ebx) + e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex6 b/apps/ex6 new file mode 100755 index 00000000..06fdfd7b Binary files /dev/null and b/apps/ex6 differ diff --git a/apps/ex6.subx b/apps/ex6.subx new file mode 100644 index 00000000..42612578 --- /dev/null +++ b/apps/ex6.subx @@ -0,0 +1,35 @@ +# Print out a (global variable) string to stdout. +# +# To run: +# $ ./subx translate init.linux examples/ex6.subx -o examples/ex6 +# $ ./subx run examples/ex6 +# Hello, world! + +== code + +# . 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 + +Entry: + # write(stdout, X, Size) + # . fd = 1 (stdout) + bb/copy-to-ebx 1/imm32 + # . initialize X (location to write result to) + b9/copy-to-ecx X/imm32 + # . initialize Size + 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/edx Size/disp32 . # copy *Size to edx + # . syscall + e8/call syscall_write/disp32 + + # exit(ebx) + e8/call syscall_exit/disp32 + +== data + +Size: # size of string + 0x0e/imm32 # 14 +X: # string to print + 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a 00 +# H e l l o , ␣ w o r l d ! newline null + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex7 b/apps/ex7 new file mode 100755 index 00000000..0a535d45 Binary files /dev/null and b/apps/ex7 differ diff --git a/apps/ex7.subx b/apps/ex7.subx new file mode 100644 index 00000000..1c551cad --- /dev/null +++ b/apps/ex7.subx @@ -0,0 +1,98 @@ +# Example showing file syscalls. +# +# Create a file, open it for writing, write a character to it, close it, open +# it for reading, read a character from it, close it, delete it, and return +# the character read. +# +# To run: +# $ ./subx translate init.linux examples/ex7.subx -o examples/ex7 +# $ ./subx run examples/ex7 +# Expected result: +# $ echo $? +# 97 + +== 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 + +Entry: + # creat(Filename) + bb/copy-to-ebx Filename/imm32 + b9/copy-to-ecx 0x180/imm32/fixed-perms + e8/call syscall_creat/disp32 + + # stream = open(Filename, O_WRONLY, 0) # we can't use 'fd' because it looks like a hex byte + bb/copy-to-ebx Filename/imm32 + b9/copy-to-ecx 1/imm32/wronly + ba/copy-to-edx 0x180/imm32/fixed-perms + e8/call syscall_open/disp32 + # save stream + bb/copy-to-ebx Stream/imm32 + 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx + + # write(Stream, "a", 1) + # . load stream + bb/copy-to-ebx Stream/imm32 + 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx + # . + b9/copy-to-ecx A/imm32 + ba/copy-to-edx 1/imm32/size + e8/call syscall_write/disp32 + + # close(Stream) + # . load stream + bb/copy-to-ebx Stream/imm32 + 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx + # . + e8/call syscall_close/disp32 + + # stream = open(Filename, O_RDONLY, 0) + bb/copy-to-ebx Filename/imm32 + b9/copy-to-ecx 0/imm32/rdonly + ba/copy-to-edx 0x180/imm32/fixed-perms + e8/call syscall_open/disp32 + # . save Stream + bb/copy-to-ebx Stream/imm32 + 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx + + # read(Stream, B, 1) + # . load stream + bb/copy-to-ebx Stream/imm32 + 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx + # . + b9/copy-to-ecx B/imm32 + ba/copy-to-edx 1/imm32/size + e8/call syscall_read/disp32 + + # close(Stream) + # . load stream + bb/copy-to-ebx Stream/imm32 + 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx + # + e8/call syscall_close/disp32 + + # unlink(filename) + bb/copy-to-ebx Filename/imm32 + e8/call syscall_unlink/disp32 + + # exit(b) + # . load b + bb/copy-to-ebx B/imm32 + 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx + # + e8/call syscall_exit/disp32 + +== data + +Stream: + 0/imm32 +A: + 61/imm32/A +B: + 0/imm32 +Filename: + 2e 66 6f 6f 00 00 00 00 +# . f o o null + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex8 b/apps/ex8 new file mode 100755 index 00000000..78f1773d Binary files /dev/null and b/apps/ex8 differ diff --git a/apps/ex8.subx b/apps/ex8.subx new file mode 100644 index 00000000..0e44a883 --- /dev/null +++ b/apps/ex8.subx @@ -0,0 +1,60 @@ +# Example reading commandline arguments: compute length of first arg. +# +# To run: +# $ ./subx translate init.linux examples/ex8.subx -o examples/ex8 +# $ ./subx run examples/ex8 abc de fghi +# Expected result: +# $ echo $? +# 3 # length of 'abc' +# +# At the start of a SubX program: +# argc: *esp +# argv[0]: *(esp+4) +# argv[1]: *(esp+8) +# ... +# Locals start from esp-4 downwards. + +== 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 + +Entry: + # . prologue + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # eax = ascii-length(argv[1]) + # . . push args + ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) + # . . call + e8/call ascii-length/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp + + # exit(eax) + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + e8/call syscall_exit/disp32 + +ascii-length: # s : (address array byte) -> n/eax + # edx = s + 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 2/r32/edx 4/disp8 . # copy *(esp+4) to edx + # var result/eax = 0 + b8/copy-to-eax 0/imm32 +$ascii-length:loop: + # var c/ecx = *s + 8a/copy-byte 0/mod/* 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL + # if (c == '\0') break + 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx + 74/jump-if-equal $ascii-length:end/disp8 + # ++s + 42/increment-edx + # ++result + 40/increment-eax + # loop + eb/jump $ascii-length:loop/disp8 +$ascii-length:end: + # return eax + c3/return + +== data + +# . . vim:nowrap:textwidth=0 diff --git a/apps/ex9 b/apps/ex9 new file mode 100755 index 00000000..5140cf68 Binary files /dev/null and b/apps/ex9 differ diff --git a/apps/ex9.subx b/apps/ex9.subx new file mode 100644 index 00000000..443e443e --- /dev/null +++ b/apps/ex9.subx @@ -0,0 +1,52 @@ +# Example showing arg order on the stack. +# +# Show difference between ascii codes of first letter of first arg and first +# letter of second arg. +# +# To run: +# $ ./subx translate init.linux examples/ex9.subx -o examples/ex9 +# $ ./subx run examples/ex9 z x +# Expected result: +# $ echo $? +# 2 +# +# At the start of a SubX program: +# argc: *esp +# argv[0]: *(esp+4) +# argv[1]: *(esp+8) +# ... +# Locals start from esp-4 downwards. + +== 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 + +Entry: + # . prologue + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # ascii-difference(argv[1], argv[2]) + # . . push argv[2] + ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) + # . . push argv[1] + ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) + # . . call + e8/call ascii-difference/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # exit(eax) + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + e8/call syscall_exit/disp32 + +ascii-difference: # (s1, s2) : null-terminated ascii strings + # a = first letter of s1 (ecx) + 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 0/r32/eax 4/disp8 . # copy *(esp+4) to eax + 8b/copy 0/mod/indirect 0/rm32/eax . . . 0/r32/eax . . # copy *eax to eax + # b = first letter of s2 (edx) + 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 8/disp8 # copy *(esp+8) to ecx + 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx + # a-b + 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax + c3/return + +# . . vim:nowrap:textwidth=0 diff --git a/edit b/edit index dc434f58..400ab370 100755 --- a/edit +++ b/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 diff --git a/examples/Readme.md b/examples/Readme.md deleted file mode 100644 index d4bb1ff5..00000000 --- a/examples/Readme.md +++ /dev/null @@ -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. diff --git a/examples/ex1 b/examples/ex1 deleted file mode 100755 index 5f17bc66..00000000 Binary files a/examples/ex1 and /dev/null differ diff --git a/examples/ex1.subx b/examples/ex1.subx deleted file mode 100644 index 5558d310..00000000 --- a/examples/ex1.subx +++ /dev/null @@ -1,18 +0,0 @@ -# First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html -# Just return 42. -# -# To run: -# $ ./subx translate init.linux examples/ex1.2.subx -o examples/ex1 -# $ ./subx run examples/ex1 -# Expected result: -# $ echo $? -# 42 - -== code - -Entry: -# exit(42) -bb/copy-to-ebx 2a/imm32 # 42 in hex -e8/call syscall_exit/disp32 - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex10 b/examples/ex10 deleted file mode 100755 index cb8973fe..00000000 Binary files a/examples/ex10 and /dev/null differ diff --git a/examples/ex10.subx b/examples/ex10.subx deleted file mode 100644 index c091fe52..00000000 --- a/examples/ex10.subx +++ /dev/null @@ -1,69 +0,0 @@ -# String comparison: return 1 iff the two args passed in at the commandline are equal. -# -# To run: -# $ ./subx translate init.linux examples/ex10.subx -o examples/ex10 -# $ ./subx run examples/ex10 abc abd -# Expected result: -# $ echo $? -# 0 # false - -== 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 - -Entry: # return argv-equal(argv[1], argv[2]) -# At the start of a SubX program: -# argc: *esp -# argv[0]: *(esp+4) -# argv[1]: *(esp+8) -# ... - # . prologue - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # argv-equal(argv[1], argv[2]) - # . . push argv[2] - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - # . . push argv[1] - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call argv-equal/disp32 - # exit(eax) - 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx - e8/call syscall_exit/disp32 - -# compare two null-terminated ascii strings -# reason for the name: the only place we should have null-terminated ascii strings is from commandline args -argv-equal: # (s1, s2) : null-terminated ascii strings -> eax : boolean - # initialize s1 (ecx) and s2 (edx) - 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 1/r32/ecx 4/disp8 . # copy *(esp+4) to ecx - 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 2/r32/edx 8/disp8 . # copy *(esp+8) to edx -$argv-equal:loop: - # c1/eax, c2/ebx = *s1, *s2 - b8/copy-to-eax 0/imm32 - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - bb/copy-to-ebx 0/imm32 - 8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 3/r32/BL . . # copy byte at *edx to BL - # if (c1 == 0) break - 3d/compare-eax-and 0/imm32 - 74/jump-if-equal $argv-equal:break/disp8 - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx - 75/jump-if-not-equal $argv-equal:false/disp8 - # ++s1, ++s2 - 41/increment-ecx - 42/increment-edx - # end while - eb/jump $argv-equal:loop/disp8 -$argv-equal:break: - # if (c2 == 0) return true - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32 # compare ebx - 75/jump-if-not-equal $argv-equal:false/disp8 -$argv-equal:success: - b8/copy-to-eax 1/imm32 - c3/return - # return false -$argv-equal:false: - b8/copy-to-eax 0/imm32 - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex11 b/examples/ex11 deleted file mode 100755 index 1cb1aa5c..00000000 Binary files a/examples/ex11 and /dev/null differ diff --git a/examples/ex11.subx b/examples/ex11.subx deleted file mode 100644 index b235927d..00000000 --- a/examples/ex11.subx +++ /dev/null @@ -1,355 +0,0 @@ -# Null-terminated vs length-prefixed ascii strings. -# -# By default we create strings with a 4-byte length prefix rather than a null suffix. -# However we still need null-prefixed strings when interacting with the Linux -# kernel in a few places. This layer implements a function for comparing -# a null-terminated 'kernel string' with a length-prefixed 'SubX string'. -# -# To run: -# $ ./subx translate init.linux examples/ex11.subx -o examples/ex11 -# $ ./subx run examples/ex11 # runs a series of tests -# ...... # all tests pass -# -# (We can't yet run the tests when given a "test" commandline argument, -# because checking for it would require the function being tested! Breakage -# would cause tests to not run, rather than to fail as we'd like.) - -== 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 - -Entry: # run all tests - e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - # exit(eax) - 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx - e8/call syscall_exit/disp32 - -# compare a null-terminated ascii string with a more idiomatic length-prefixed byte array -# reason for the name: the only place we should have null-terminated ascii strings is from commandline args -kernel-string-equal?: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> eax : boolean - # pseudocode: - # n = benchmark->length - # s1 = s - # s2 = benchmark->data - # i = 0 - # while i < n - # c1 = *s1 - # c2 = *s2 - # if (c1 == 0) return false - # if (c1 != c2) return false - # ++s1, ++s2, ++i - # return *s1 == 0 - # - # registers: - # i: ecx - # n: edx - # s1: edi - # s2: esi - # c1: eax - # c2: ebx - # - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # s1/edi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # n/edx = benchmark->length - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx - 8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx - # s2/esi = benchmark->data - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi - 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 4/imm32 # add to esi - # i/ecx = c1/eax = c2/ebx = 0 - b9/copy-to-ecx 0/imm32/exit - b8/copy-to-eax 0/imm32 - bb/copy-to-ebx 0/imm32 -$kernel-string-equal?:loop: - # if (i >= n) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 7d/jump-if-greater-or-equal $kernel-string-equal?:break/disp8 - # c1 = *s1 - 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL - # c2 = *s2 - 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL - # if (c1 == 0) return false - 3d/compare-eax-and 0/imm32 - 74/jump-if-equal $kernel-string-equal?:false/disp8 - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx - 75/jump-if-not-equal $kernel-string-equal?:false/disp8 - # ++i - 41/increment-ecx - # ++s1 - 47/increment-edi - # ++s2 - 46/increment-esi - eb/jump $kernel-string-equal?:loop/disp8 -$kernel-string-equal?:break: - # return *s1 == 0 - 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL - 3d/compare-eax-and 0/imm32 - 75/jump-if-not-equal $kernel-string-equal?:false/disp8 -$kernel-string-equal?:true: - b8/copy-to-eax 1/imm32 - eb/jump $kernel-string-equal?:end/disp8 -$kernel-string-equal?:false: - b8/copy-to-eax 0/imm32 -$kernel-string-equal?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 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 - -# - tests - -test-compare-null-kernel-string-with-empty-array: - # eax = kernel-string-equal?(Null-kernel-string, "") - # . . push args - 68/push ""/imm32 - 68/push Null-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-null-kernel-string-with-non-empty-array: - # eax = kernel-string-equal?(Null-kernel-string, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push Null-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-kernel-string-with-equal-array: - # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-Abc-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-kernel-string-with-inequal-array: - # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc") - # . . push args - 68/push "Adc"/imm32 - 68/push _test-Abc-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-kernel-string-with-empty-array: - # eax = kernel-string-equal?(_test-Abc-kernel-string, "") - # . . push args - 68/push ""/imm32 - 68/push _test-Abc-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-kernel-string-with-shorter-array: - # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab") - # . . push args - 68/push "Ab"/imm32 - 68/push _test-Abc-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-kernel-string-with-longer-array: - # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd") - # . . push args - 68/push "Abcd"/imm32 - 68/push _test-Abc-kernel-string/imm32 - # . . call - e8/call kernel-string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-kernel-string-with-longer-array"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -# - helpers - -# print msg to stderr if a != b, otherwise print "." -check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 53/push-ebx - # load args into eax, ebx and ecx - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx - # if (eax == b/ebx) print('.') and return - 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx - 75/jump-if-unequal $check-ints-equal:else/disp8 - # . write-stderr('.') - # . . push args - 68/push "."/imm32 - # . . call - e8/call write-stderr/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . return - eb/jump $check-ints-equal:end/disp8 - # otherwise print(msg) -$check-ints-equal:else: - # copy msg into ecx - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # copy *(ebp+16) to ecx - # print(ecx) - # . . push args - 51/push-ecx - # . . call - e8/call write-stderr/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # print newline - # . . push args - 68/push Newline/imm32 - # . . call - e8/call write-stderr/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp -$check-ints-equal:end: - # . restore registers - 5b/pop-to-ebx - 59/pop-to-ecx - # end - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -write-stderr: # s : (address array byte) -> - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - # syscall(write, 2/stderr, (data) s+4, (size) *s) - # . . fd = 2 (stderr) - bb/copy-to-ebx 2/imm32 - # . . x = s+4 - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx - # . . size = *s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 8/disp8 . # copy *(ebp+8) to edx - 8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx - # . . syscall - e8/call syscall_write/disp32 - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . end - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -== data - -Newline: - # size - 1/imm32 - # data - 0a/newline - -# for kernel-string-equal tests -Null-kernel-string: - 00/null - -_test-Abc-kernel-string: - 41/A 62/b 63/c 00/null - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex12 b/examples/ex12 deleted file mode 100755 index 80e5deeb..00000000 Binary files a/examples/ex12 and /dev/null differ diff --git a/examples/ex12.subx b/examples/ex12.subx deleted file mode 100644 index 9c67f909..00000000 --- a/examples/ex12.subx +++ /dev/null @@ -1,43 +0,0 @@ -# Example showing mmap syscall. -# Create a new segment using mmap, save the address, write to it. -# -# To run: -# $ ./subx translate init.linux examples/ex12.subx -o examples/ex12 -# $ ./subx run examples/ex12 -# You shouldn't get a segmentation fault. - -== 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 - -Entry: - # mmap(Mmap-new-segment->len) - bb/copy-to-ebx Mmap-new-segment/imm32 - e8/call syscall_mmap/disp32 - - # write to *eax to check that we have access to the newly-allocated segment - c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0x34/imm32 # copy to *eax - - # exit(eax) - 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx - e8/call syscall_exit/disp32 - -== data - -# various constants used here were found in the Linux sources (search for file mman-common.h) -Mmap-new-segment: # type mmap_arg_struct - # addr - 0/imm32 - # len - 0x100/imm32 - # protection flags - 3/imm32 # PROT_READ | PROT_WRITE - # sharing flags - 0x22/imm32 # MAP_PRIVATE | MAP_ANONYMOUS - # fd - -1/imm32 # since MAP_ANONYMOUS is specified - # offset - 0/imm32 # since MAP_ANONYMOUS is specified - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex2 b/examples/ex2 deleted file mode 100755 index 5e0c1be1..00000000 Binary files a/examples/ex2 and /dev/null differ diff --git a/examples/ex2.subx b/examples/ex2.subx deleted file mode 100644 index 8df4c62c..00000000 --- a/examples/ex2.subx +++ /dev/null @@ -1,20 +0,0 @@ -# Add 1 and 1, and return the result in the exit code. -# -# To run: -# $ ./subx translate init.linux examples/ex2.subx -o examples/ex2 -# $ ./subx run examples/ex2 -# Expected result: -# $ echo $? -# 2 - -== code - -Entry: -# ebx = 1 -bb/copy-to-ebx 1/imm32 -# increment ebx -43/increment-ebx -# exit(ebx) -e8/call syscall_exit/disp32 - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex3 b/examples/ex3 deleted file mode 100755 index af787c11..00000000 Binary files a/examples/ex3 and /dev/null differ diff --git a/examples/ex3.subx b/examples/ex3.subx deleted file mode 100644 index f6f8c17d..00000000 --- a/examples/ex3.subx +++ /dev/null @@ -1,36 +0,0 @@ -# Add the first 10 numbers, and return the result in the exit code. -# -# To run: -# $ ./subx translate init.linux examples/ex3.subx -o examples/ex3 -# $ ./subx run examples/ex3 -# Expected result: -# $ echo $? -# 55 - -== 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 - -Entry: - # result: ebx = 0 - bb/copy-to-ebx 0/imm32 - # counter: ecx = 1 - b9/copy-to-ecx 1/imm32 - -$loop: - # if (counter > 10) break - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0xa/imm32 # compare ecx - 7f/jump-if-greater $exit/disp8 - # result += counter - 01/add 3/mod/direct 3/rm32/ebx . . . 1/r32/ecx . . # add ecx to ebx - # ++counter - 41/increment-ecx - # loop - eb/jump $loop/disp8 - -$exit: - # exit(ebx) - e8/call syscall_exit/disp32 - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex4 b/examples/ex4 deleted file mode 100755 index 35ade1ee..00000000 Binary files a/examples/ex4 and /dev/null differ diff --git a/examples/ex4.subx b/examples/ex4.subx deleted file mode 100644 index 78a97433..00000000 --- a/examples/ex4.subx +++ /dev/null @@ -1,39 +0,0 @@ -# Read a character from stdin, save it to a global, write it to stdout. -# -# To run: -# $ ./subx translate init.linux examples/ex4.subx -o examples/ex4 -# $ ./subx run examples/ex4 - -== data - -# the global variable we save to -X: - 0/imm32 # space for read() to write to - -== code - -Entry: -# read(stdin, X, 1) -# . fd = 0 (stdin) -bb/copy-to-ebx 0/imm32 -# . data = X (location to write result to) -b9/copy-to-ecx X/imm32 -# . size = 1 character -ba/copy-to-edx 1/imm32 -# . syscall -e8/call syscall_read/disp32 - -# write(stdout, X, 1) -# . fd = 1 (stdout) -bb/copy-to-ebx 1/imm32 -# . initialize X (location to read from) -b9/copy-to-ecx X/imm32 -# . size = 1 character -ba/copy-to-edx 1/imm32 -# . syscall -e8/call syscall_write/disp32 - -# exit(ebx) -e8/call syscall_exit/disp32 - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex5 b/examples/ex5 deleted file mode 100755 index 805cadc3..00000000 Binary files a/examples/ex5 and /dev/null differ diff --git a/examples/ex5.subx b/examples/ex5.subx deleted file mode 100644 index bacef8d4..00000000 --- a/examples/ex5.subx +++ /dev/null @@ -1,41 +0,0 @@ -# Read a character from stdin, save it to a local on the stack, write it to stdout. -# -# To run: -# $ ./subx translate init.linux examples/ex5.subx -o examples/ex5 -# $ ./subx run examples/ex5 - -== 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 - -Entry: - - # allocate x on the stack - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # subtract from esp - - # read(stdin, x, 1) - # . fd = 0 (stdin) - bb/copy-to-ebx 0/imm32 - # . data = x (location to write result to) - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx - # . size = 1 character - ba/copy-to-edx 1/imm32 - # . syscall - e8/call syscall_read/disp32 - - # syscall(write, stdout, x, 1) - # . fd = 1 (stdout) - bb/copy-to-ebx 1/imm32 - # . data = x (location to read from) - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx - # . size = 1 character - ba/copy-to-edx 1/imm32 - # . syscall - b8/copy-to-eax 4/imm32/write - cd/syscall 0x80/imm8 - - # exit(ebx) - e8/call syscall_exit/disp32 - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex6 b/examples/ex6 deleted file mode 100755 index 06fdfd7b..00000000 Binary files a/examples/ex6 and /dev/null differ diff --git a/examples/ex6.subx b/examples/ex6.subx deleted file mode 100644 index 42612578..00000000 --- a/examples/ex6.subx +++ /dev/null @@ -1,35 +0,0 @@ -# Print out a (global variable) string to stdout. -# -# To run: -# $ ./subx translate init.linux examples/ex6.subx -o examples/ex6 -# $ ./subx run examples/ex6 -# Hello, world! - -== code - -# . 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 - -Entry: - # write(stdout, X, Size) - # . fd = 1 (stdout) - bb/copy-to-ebx 1/imm32 - # . initialize X (location to write result to) - b9/copy-to-ecx X/imm32 - # . initialize Size - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/edx Size/disp32 . # copy *Size to edx - # . syscall - e8/call syscall_write/disp32 - - # exit(ebx) - e8/call syscall_exit/disp32 - -== data - -Size: # size of string - 0x0e/imm32 # 14 -X: # string to print - 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a 00 -# H e l l o , ␣ w o r l d ! newline null - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex7 b/examples/ex7 deleted file mode 100755 index 0a535d45..00000000 Binary files a/examples/ex7 and /dev/null differ diff --git a/examples/ex7.subx b/examples/ex7.subx deleted file mode 100644 index 1c551cad..00000000 --- a/examples/ex7.subx +++ /dev/null @@ -1,98 +0,0 @@ -# Example showing file syscalls. -# -# Create a file, open it for writing, write a character to it, close it, open -# it for reading, read a character from it, close it, delete it, and return -# the character read. -# -# To run: -# $ ./subx translate init.linux examples/ex7.subx -o examples/ex7 -# $ ./subx run examples/ex7 -# Expected result: -# $ echo $? -# 97 - -== 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 - -Entry: - # creat(Filename) - bb/copy-to-ebx Filename/imm32 - b9/copy-to-ecx 0x180/imm32/fixed-perms - e8/call syscall_creat/disp32 - - # stream = open(Filename, O_WRONLY, 0) # we can't use 'fd' because it looks like a hex byte - bb/copy-to-ebx Filename/imm32 - b9/copy-to-ecx 1/imm32/wronly - ba/copy-to-edx 0x180/imm32/fixed-perms - e8/call syscall_open/disp32 - # save stream - bb/copy-to-ebx Stream/imm32 - 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx - - # write(Stream, "a", 1) - # . load stream - bb/copy-to-ebx Stream/imm32 - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx - # . - b9/copy-to-ecx A/imm32 - ba/copy-to-edx 1/imm32/size - e8/call syscall_write/disp32 - - # close(Stream) - # . load stream - bb/copy-to-ebx Stream/imm32 - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx - # . - e8/call syscall_close/disp32 - - # stream = open(Filename, O_RDONLY, 0) - bb/copy-to-ebx Filename/imm32 - b9/copy-to-ecx 0/imm32/rdonly - ba/copy-to-edx 0x180/imm32/fixed-perms - e8/call syscall_open/disp32 - # . save Stream - bb/copy-to-ebx Stream/imm32 - 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx - - # read(Stream, B, 1) - # . load stream - bb/copy-to-ebx Stream/imm32 - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx - # . - b9/copy-to-ecx B/imm32 - ba/copy-to-edx 1/imm32/size - e8/call syscall_read/disp32 - - # close(Stream) - # . load stream - bb/copy-to-ebx Stream/imm32 - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx - # - e8/call syscall_close/disp32 - - # unlink(filename) - bb/copy-to-ebx Filename/imm32 - e8/call syscall_unlink/disp32 - - # exit(b) - # . load b - bb/copy-to-ebx B/imm32 - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 3/r32/ebx . . # copy *ebx to ebx - # - e8/call syscall_exit/disp32 - -== data - -Stream: - 0/imm32 -A: - 61/imm32/A -B: - 0/imm32 -Filename: - 2e 66 6f 6f 00 00 00 00 -# . f o o null - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex8 b/examples/ex8 deleted file mode 100755 index 78f1773d..00000000 Binary files a/examples/ex8 and /dev/null differ diff --git a/examples/ex8.subx b/examples/ex8.subx deleted file mode 100644 index 0e44a883..00000000 --- a/examples/ex8.subx +++ /dev/null @@ -1,60 +0,0 @@ -# Example reading commandline arguments: compute length of first arg. -# -# To run: -# $ ./subx translate init.linux examples/ex8.subx -o examples/ex8 -# $ ./subx run examples/ex8 abc de fghi -# Expected result: -# $ echo $? -# 3 # length of 'abc' -# -# At the start of a SubX program: -# argc: *esp -# argv[0]: *(esp+4) -# argv[1]: *(esp+8) -# ... -# Locals start from esp-4 downwards. - -== 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 - -Entry: - # . prologue - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # eax = ascii-length(argv[1]) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call ascii-length/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - - # exit(eax) - 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx - e8/call syscall_exit/disp32 - -ascii-length: # s : (address array byte) -> n/eax - # edx = s - 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none . 2/r32/edx 4/disp8 . # copy *(esp+4) to edx - # var result/eax = 0 - b8/copy-to-eax 0/imm32 -$ascii-length:loop: - # var c/ecx = *s - 8a/copy-byte 0/mod/* 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL - # if (c == '\0') break - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx - 74/jump-if-equal $ascii-length:end/disp8 - # ++s - 42/increment-edx - # ++result - 40/increment-eax - # loop - eb/jump $ascii-length:loop/disp8 -$ascii-length:end: - # return eax - c3/return - -== data - -# . . vim:nowrap:textwidth=0 diff --git a/examples/ex9 b/examples/ex9 deleted file mode 100755 index 5140cf68..00000000 Binary files a/examples/ex9 and /dev/null differ diff --git a/examples/ex9.subx b/examples/ex9.subx deleted file mode 100644 index 443e443e..00000000 --- a/examples/ex9.subx +++ /dev/null @@ -1,52 +0,0 @@ -# Example showing arg order on the stack. -# -# Show difference between ascii codes of first letter of first arg and first -# letter of second arg. -# -# To run: -# $ ./subx translate init.linux examples/ex9.subx -o examples/ex9 -# $ ./subx run examples/ex9 z x -# Expected result: -# $ echo $? -# 2 -# -# At the start of a SubX program: -# argc: *esp -# argv[0]: *(esp+4) -# argv[1]: *(esp+8) -# ... -# Locals start from esp-4 downwards. - -== 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 - -Entry: - # . prologue - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # ascii-difference(argv[1], argv[2]) - # . . push argv[2] - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - # . . push argv[1] - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call ascii-difference/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # exit(eax) - 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx - e8/call syscall_exit/disp32 - -ascii-difference: # (s1, s2) : null-terminated ascii strings - # a = first letter of s1 (ecx) - 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 0/r32/eax 4/disp8 . # copy *(esp+4) to eax - 8b/copy 0/mod/indirect 0/rm32/eax . . . 0/r32/eax . . # copy *eax to eax - # b = first letter of s2 (edx) - 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 8/disp8 # copy *(esp+8) to ecx - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx - # a-b - 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/html/apps/ex1.subx.html b/html/apps/ex1.subx.html new file mode 100644 index 00000000..c4105769 --- /dev/null +++ b/html/apps/ex1.subx.html @@ -0,0 +1,77 @@ + + + + +Mu - examples/ex1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex1.subx +
+ 1 # First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ 2 # Just return 42.
+ 3 #
+ 4 # To run:
+ 5 #   $ ./subx translate init.linux examples/ex1.2.subx -o examples/ex1
+ 6 #   $ ./subx run examples/ex1
+ 7 # Expected result:
+ 8 #   $ echo $?
+ 9 #   42
+10 
+11 == code
+12 
+13 Entry:
+14 # exit(42)
+15 bb/copy-to-ebx  2a/imm32  # 42 in hex
+16 e8/call  syscall_exit/disp32
+17 
+18 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex10.subx.html b/html/apps/ex10.subx.html new file mode 100644 index 00000000..bcf0e466 --- /dev/null +++ b/html/apps/ex10.subx.html @@ -0,0 +1,132 @@ + + + + +Mu - examples/ex10.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex10.subx +
+ 1 # String comparison: return 1 iff the two args passed in at the commandline are equal.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex10.subx -o examples/ex10
+ 5 #   $ ./subx run examples/ex10 abc abd
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   0  # false
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:  # return argv-equal(argv[1], argv[2])
+16 #       At the start of a SubX program:
+17 #         argc: *esp
+18 #         argv[0]: *(esp+4)
+19 #         argv[1]: *(esp+8)
+20 #         ...
+21     # . prologue
+22     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+23     # argv-equal(argv[1], argv[2])
+24     # . . push argv[2]
+25     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+26     # . . push argv[1]
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call argv-equal/disp32
+30     # exit(eax)
+31     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+32     e8/call  syscall_exit/disp32
+33 
+34 # compare two null-terminated ascii strings
+35 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+36 argv-equal:  # (s1, s2) : null-terminated ascii strings -> eax : boolean
+37     # initialize s1 (ecx) and s2 (edx)
+38     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   4/disp8         .                 # copy *(esp+4) to ecx
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   8/disp8         .                 # copy *(esp+8) to edx
+40 $argv-equal:loop:
+41     # c1/eax, c2/ebx = *s1, *s2
+42     b8/copy-to-eax  0/imm32
+43     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+44     bb/copy-to-ebx  0/imm32
+45     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
+46     # if (c1 == 0) break
+47     3d/compare-eax-and  0/imm32
+48     74/jump-if-equal  $argv-equal:break/disp8
+49     # if (c1 != c2) return false
+50     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+51     75/jump-if-not-equal  $argv-equal:false/disp8
+52     # ++s1, ++s2
+53     41/increment-ecx
+54     42/increment-edx
+55     # end while
+56     eb/jump  $argv-equal:loop/disp8
+57 $argv-equal:break:
+58     # if (c2 == 0) return true
+59     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32           # compare ebx
+60     75/jump-if-not-equal  $argv-equal:false/disp8
+61 $argv-equal:success:
+62     b8/copy-to-eax  1/imm32
+63     c3/return
+64     # return false
+65 $argv-equal:false:
+66     b8/copy-to-eax  0/imm32
+67     c3/return
+68 
+69 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex11.subx.html b/html/apps/ex11.subx.html new file mode 100644 index 00000000..47c0b289 --- /dev/null +++ b/html/apps/ex11.subx.html @@ -0,0 +1,421 @@ + + + + +Mu - examples/ex11.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex11.subx +
+  1 # Null-terminated vs length-prefixed ascii strings.
+  2 #
+  3 # By default we create strings with a 4-byte length prefix rather than a null suffix.
+  4 # However we still need null-prefixed strings when interacting with the Linux
+  5 # kernel in a few places. This layer implements a function for comparing
+  6 # a null-terminated 'kernel string' with a length-prefixed 'SubX string'.
+  7 #
+  8 # To run:
+  9 #   $ ./subx translate init.linux examples/ex11.subx -o examples/ex11
+ 10 #   $ ./subx run examples/ex11  # runs a series of tests
+ 11 #   ......  # all tests pass
+ 12 #
+ 13 # (We can't yet run the tests when given a "test" commandline argument,
+ 14 # because checking for it would require the function being tested! Breakage
+ 15 # would cause tests to not run, rather than to fail as we'd like.)
+ 16 
+ 17 == code
+ 18 #   instruction                     effective address                                                   register    displacement    immediate
+ 19 # . op          subop               mod             rm32          base        index         scale       r32
+ 20 # . 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
+ 21 
+ 22 Entry:  # run all tests
+ 23     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 24     # exit(eax)
+ 25     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+ 26     e8/call  syscall_exit/disp32
+ 27 
+ 28 # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array
+ 29 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+ 30 kernel-string-equal?:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> eax : boolean
+ 31     # pseudocode:
+ 32     #   n = benchmark->length
+ 33     #   s1 = s
+ 34     #   s2 = benchmark->data
+ 35     #   i = 0
+ 36     #   while i < n
+ 37     #     c1 = *s1
+ 38     #     c2 = *s2
+ 39     #     if (c1 == 0) return false
+ 40     #     if (c1 != c2) return false
+ 41     #     ++s1, ++s2, ++i
+ 42     #   return *s1 == 0
+ 43     #
+ 44     # registers:
+ 45     #   i: ecx
+ 46     #   n: edx
+ 47     #   s1: edi
+ 48     #   s2: esi
+ 49     #   c1: eax
+ 50     #   c2: ebx
+ 51     #
+ 52     # . prologue
+ 53     55/push-ebp
+ 54     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 55     # . save registers
+ 56     51/push-ecx
+ 57     52/push-edx
+ 58     53/push-ebx
+ 59     56/push-esi
+ 60     57/push-edi
+ 61     # s1/edi = s
+ 62     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 63     # n/edx = benchmark->length
+ 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 65     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+ 66     # s2/esi = benchmark->data
+ 67     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 68     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
+ 69     # i/ecx = c1/eax = c2/ebx = 0
+ 70     b9/copy-to-ecx  0/imm32/exit
+ 71     b8/copy-to-eax  0/imm32
+ 72     bb/copy-to-ebx  0/imm32
+ 73 $kernel-string-equal?:loop:
+ 74     # if (i >= n) break
+ 75     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 76     7d/jump-if-greater-or-equal  $kernel-string-equal?:break/disp8
+ 77     # c1 = *s1
+ 78     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 79     # c2 = *s2
+ 80     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
+ 81     # if (c1 == 0) return false
+ 82     3d/compare-eax-and  0/imm32
+ 83     74/jump-if-equal  $kernel-string-equal?:false/disp8
+ 84     # if (c1 != c2) return false
+ 85     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+ 86     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
+ 87     # ++i
+ 88     41/increment-ecx
+ 89     # ++s1
+ 90     47/increment-edi
+ 91     # ++s2
+ 92     46/increment-esi
+ 93     eb/jump  $kernel-string-equal?:loop/disp8
+ 94 $kernel-string-equal?:break:
+ 95     # return *s1 == 0
+ 96     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 97     3d/compare-eax-and  0/imm32
+ 98     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
+ 99 $kernel-string-equal?:true:
+100     b8/copy-to-eax  1/imm32
+101     eb/jump  $kernel-string-equal?:end/disp8
+102 $kernel-string-equal?:false:
+103     b8/copy-to-eax  0/imm32
+104 $kernel-string-equal?:end:
+105     # . restore registers
+106     5f/pop-to-edi
+107     5e/pop-to-esi
+108     5b/pop-to-ebx
+109     5a/pop-to-edx
+110     59/pop-to-ecx
+111     # . epilogue
+112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+113     5d/pop-to-ebp
+114     c3/return
+115 
+116 # - tests
+117 
+118 test-compare-null-kernel-string-with-empty-array:
+119     # eax = kernel-string-equal?(Null-kernel-string, "")
+120     # . . push args
+121     68/push  ""/imm32
+122     68/push  Null-kernel-string/imm32
+123     # . . call
+124     e8/call  kernel-string-equal?/disp32
+125     # . . discard args
+126     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+127     # check-ints-equal(eax, 1, msg)
+128     # . . push args
+129     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
+130     68/push  1/imm32/true
+131     50/push-eax
+132     # . . call
+133     e8/call  check-ints-equal/disp32
+134     # . . discard args
+135     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+136     c3/return
+137 
+138 test-compare-null-kernel-string-with-non-empty-array:
+139     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
+140     # . . push args
+141     68/push  "Abc"/imm32
+142     68/push  Null-kernel-string/imm32
+143     # . . call
+144     e8/call  kernel-string-equal?/disp32
+145     # . . discard args
+146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+147     # check-ints-equal(eax, 0, msg)
+148     # . . push args
+149     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
+150     68/push  0/imm32/false
+151     50/push-eax
+152     # . . call
+153     e8/call  check-ints-equal/disp32
+154     # . . discard args
+155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+156     c3/return
+157 
+158 test-compare-kernel-string-with-equal-array:
+159     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
+160     # . . push args
+161     68/push  "Abc"/imm32
+162     68/push  _test-Abc-kernel-string/imm32
+163     # . . call
+164     e8/call  kernel-string-equal?/disp32
+165     # . . discard args
+166     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+167     # check-ints-equal(eax, 1, msg)
+168     # . . push args
+169     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+170     68/push  1/imm32/true
+171     50/push-eax
+172     # . . call
+173     e8/call  check-ints-equal/disp32
+174     # . . discard args
+175     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+176     c3/return
+177 
+178 test-compare-kernel-string-with-inequal-array:
+179     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
+180     # . . push args
+181     68/push  "Adc"/imm32
+182     68/push  _test-Abc-kernel-string/imm32
+183     # . . call
+184     e8/call  kernel-string-equal?/disp32
+185     # . . discard args
+186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+187     # check-ints-equal(eax, 0, msg)
+188     # . . push args
+189     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+190     68/push  0/imm32/false
+191     50/push-eax
+192     # . . call
+193     e8/call  check-ints-equal/disp32
+194     # . . discard args
+195     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+196     c3/return
+197 
+198 test-compare-kernel-string-with-empty-array:
+199     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
+200     # . . push args
+201     68/push  ""/imm32
+202     68/push  _test-Abc-kernel-string/imm32
+203     # . . call
+204     e8/call  kernel-string-equal?/disp32
+205     # . . discard args
+206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+207     # check-ints-equal(eax, 0, msg)
+208     # . . push args
+209     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+210     68/push  0/imm32/false
+211     50/push-eax
+212     # . . call
+213     e8/call  check-ints-equal/disp32
+214     # . . discard args
+215     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+216     c3/return
+217 
+218 test-compare-kernel-string-with-shorter-array:
+219     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
+220     # . . push args
+221     68/push  "Ab"/imm32
+222     68/push  _test-Abc-kernel-string/imm32
+223     # . . call
+224     e8/call  kernel-string-equal?/disp32
+225     # . . discard args
+226     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+227     # check-ints-equal(eax, 0, msg)
+228     # . . push args
+229     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
+230     68/push  0/imm32/false
+231     50/push-eax
+232     # . . call
+233     e8/call  check-ints-equal/disp32
+234     # . . discard args
+235     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+236     c3/return
+237 
+238 test-compare-kernel-string-with-longer-array:
+239     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
+240     # . . push args
+241     68/push  "Abcd"/imm32
+242     68/push  _test-Abc-kernel-string/imm32
+243     # . . call
+244     e8/call  kernel-string-equal?/disp32
+245     # . . discard args
+246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+247     # check-ints-equal(eax, 0, msg)
+248     # . . push args
+249     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
+250     68/push  0/imm32/false
+251     50/push-eax
+252     # . . call
+253     e8/call  check-ints-equal/disp32
+254     # . . discard args
+255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+256     c3/return
+257 
+258 # - helpers
+259 
+260 # print msg to stderr if a != b, otherwise print "."
+261 check-ints-equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
+262     # . prologue
+263     55/push-ebp
+264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+265     # . save registers
+266     51/push-ecx
+267     53/push-ebx
+268     # load args into eax, ebx and ecx
+269     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+270     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
+271     # if (eax == b/ebx) print('.') and return
+272     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+273     75/jump-if-unequal  $check-ints-equal:else/disp8
+274     # . write-stderr('.')
+275     # . . push args
+276     68/push  "."/imm32
+277     # . . call
+278     e8/call  write-stderr/disp32
+279     # . . discard args
+280     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+281     # . return
+282     eb/jump  $check-ints-equal:end/disp8
+283     # otherwise print(msg)
+284 $check-ints-equal:else:
+285     # copy msg into ecx
+286     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8       .                # copy *(ebp+16) to ecx
+287     # print(ecx)
+288     # . . push args
+289     51/push-ecx
+290     # . . call
+291     e8/call  write-stderr/disp32
+292     # . . discard args
+293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+294     # print newline
+295     # . . push args
+296     68/push  Newline/imm32
+297     # . . call
+298     e8/call  write-stderr/disp32
+299     # . . discard args
+300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+301 $check-ints-equal:end:
+302     # . restore registers
+303     5b/pop-to-ebx
+304     59/pop-to-ecx
+305     # end
+306     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+307     5d/pop-to-ebp
+308     c3/return
+309 
+310 write-stderr:  # s : (address array byte) -> <void>
+311     # . prologue
+312     55/push-ebp
+313     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+314     # . save registers
+315     50/push-eax
+316     51/push-ecx
+317     52/push-edx
+318     53/push-ebx
+319     # syscall(write, 2/stderr, (data) s+4, (size) *s)
+320     # . . fd = 2 (stderr)
+321     bb/copy-to-ebx  2/imm32
+322     # . . x = s+4
+323     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+324     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
+325     # . . size = *s
+326     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   8/disp8         .                 # copy *(ebp+8) to edx
+327     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+328     # . . syscall
+329     e8/call  syscall_write/disp32
+330     # . restore registers
+331     5b/pop-to-ebx
+332     5a/pop-to-edx
+333     59/pop-to-ecx
+334     58/pop-to-eax
+335     # . end
+336     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+337     5d/pop-to-ebp
+338     c3/return
+339 
+340 == data
+341 
+342 Newline:
+343     # size
+344     1/imm32
+345     # data
+346     0a/newline
+347 
+348 # for kernel-string-equal tests
+349 Null-kernel-string:
+350     00/null
+351 
+352 _test-Abc-kernel-string:
+353     41/A 62/b 63/c 00/null
+354 
+355 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex12.subx.html b/html/apps/ex12.subx.html new file mode 100644 index 00000000..a6b2dc64 --- /dev/null +++ b/html/apps/ex12.subx.html @@ -0,0 +1,104 @@ + + + + +Mu - examples/ex12.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex12.subx +
+ 1 # Example showing mmap syscall.
+ 2 # Create a new segment using mmap, save the address, write to it.
+ 3 #
+ 4 # To run:
+ 5 #   $ ./subx translate init.linux examples/ex12.subx -o examples/ex12
+ 6 #   $ ./subx run examples/ex12
+ 7 # You shouldn't get a segmentation fault.
+ 8 
+ 9 == code
+10 #   instruction                     effective address                                                   register    displacement    immediate
+11 # . op          subop               mod             rm32          base        index         scale       r32
+12 # . 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
+13 
+14 Entry:
+15     # mmap(Mmap-new-segment->len)
+16     bb/copy-to-ebx  Mmap-new-segment/imm32
+17     e8/call  syscall_mmap/disp32
+18 
+19     # write to *eax to check that we have access to the newly-allocated segment
+20     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0x34/imm32        # copy to *eax
+21 
+22     # exit(eax)
+23     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+24     e8/call  syscall_exit/disp32
+25 
+26 == data
+27 
+28 # various constants used here were found in the Linux sources (search for file mman-common.h)
+29 Mmap-new-segment:  # type mmap_arg_struct
+30     # addr
+31     0/imm32
+32     # len
+33     0x100/imm32
+34     # protection flags
+35     3/imm32  # PROT_READ | PROT_WRITE
+36     # sharing flags
+37     0x22/imm32  # MAP_PRIVATE | MAP_ANONYMOUS
+38     # fd
+39     -1/imm32  # since MAP_ANONYMOUS is specified
+40     # offset
+41     0/imm32  # since MAP_ANONYMOUS is specified
+42 
+43 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex2.subx.html b/html/apps/ex2.subx.html new file mode 100644 index 00000000..c67315e9 --- /dev/null +++ b/html/apps/ex2.subx.html @@ -0,0 +1,79 @@ + + + + +Mu - examples/ex2.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex2.subx +
+ 1 # Add 1 and 1, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex2.subx -o examples/ex2
+ 5 #   $ ./subx run examples/ex2
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   2
+ 9 
+10 == code
+11 
+12 Entry:
+13 # ebx = 1
+14 bb/copy-to-ebx  1/imm32
+15 # increment ebx
+16 43/increment-ebx
+17 # exit(ebx)
+18 e8/call  syscall_exit/disp32
+19 
+20 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex3.subx.html b/html/apps/ex3.subx.html new file mode 100644 index 00000000..7c3da099 --- /dev/null +++ b/html/apps/ex3.subx.html @@ -0,0 +1,98 @@ + + + + +Mu - examples/ex3.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex3.subx +
+ 1 # Add the first 10 numbers, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex3.subx -o examples/ex3
+ 5 #   $ ./subx run examples/ex3
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   55
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:
+16     # result: ebx = 0
+17     bb/copy-to-ebx  0/imm32
+18     # counter: ecx = 1
+19     b9/copy-to-ecx  1/imm32
+20 
+21 $loop:
+22     # if (counter > 10) break
+23     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xa/imm32         # compare ecx
+24     7f/jump-if-greater  $exit/disp8
+25     # result += counter
+26     01/add                          3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # add ecx to ebx
+27     # ++counter
+28     41/increment-ecx
+29     # loop
+30     eb/jump  $loop/disp8
+31 
+32 $exit:
+33     # exit(ebx)
+34     e8/call  syscall_exit/disp32
+35 
+36 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex4.subx.html b/html/apps/ex4.subx.html new file mode 100644 index 00000000..43f5c705 --- /dev/null +++ b/html/apps/ex4.subx.html @@ -0,0 +1,99 @@ + + + + +Mu - examples/ex4.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex4.subx +
+ 1 # Read a character from stdin, save it to a global, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex4.subx -o examples/ex4
+ 5 #   $ ./subx run examples/ex4
+ 6 
+ 7 == data
+ 8 
+ 9 # the global variable we save to
+10 X:
+11     0/imm32  # space for read() to write to
+12 
+13 == code
+14 
+15 Entry:
+16 # read(stdin, X, 1)
+17 # . fd = 0 (stdin)
+18 bb/copy-to-ebx  0/imm32
+19 # . data = X (location to write result to)
+20 b9/copy-to-ecx  X/imm32
+21 # . size = 1 character
+22 ba/copy-to-edx  1/imm32
+23 # . syscall
+24 e8/call  syscall_read/disp32
+25 
+26 # write(stdout, X, 1)
+27 # . fd = 1 (stdout)
+28 bb/copy-to-ebx  1/imm32
+29 # . initialize X (location to read from)
+30 b9/copy-to-ecx  X/imm32
+31 # . size = 1 character
+32 ba/copy-to-edx  1/imm32
+33 # . syscall
+34 e8/call  syscall_write/disp32
+35 
+36 # exit(ebx)
+37 e8/call  syscall_exit/disp32
+38 
+39 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex5.subx.html b/html/apps/ex5.subx.html new file mode 100644 index 00000000..f5112fa7 --- /dev/null +++ b/html/apps/ex5.subx.html @@ -0,0 +1,102 @@ + + + + +Mu - examples/ex5.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex5.subx +
+ 1 # Read a character from stdin, save it to a local on the stack, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex5.subx -o examples/ex5
+ 5 #   $ ./subx run examples/ex5
+ 6 
+ 7 == code
+ 8 #   instruction                     effective address                                                   register    displacement    immediate
+ 9 # . op          subop               mod             rm32          base        index         scale       r32
+10 # . 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
+11 
+12 Entry:
+13 
+14     # allocate x on the stack
+15     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # subtract from esp
+16 
+17     # read(stdin, x, 1)
+18     # . fd = 0 (stdin)
+19     bb/copy-to-ebx  0/imm32
+20     # . data = x (location to write result to)
+21     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+22     # . size = 1 character
+23     ba/copy-to-edx  1/imm32
+24     # . syscall
+25     e8/call  syscall_read/disp32
+26 
+27     # syscall(write, stdout, x, 1)
+28     # . fd = 1 (stdout)
+29     bb/copy-to-ebx  1/imm32
+30     # . data = x (location to read from)
+31     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+32     # . size = 1 character
+33     ba/copy-to-edx  1/imm32
+34     # . syscall
+35     b8/copy-to-eax  4/imm32/write
+36     cd/syscall  0x80/imm8
+37 
+38     # exit(ebx)
+39     e8/call  syscall_exit/disp32
+40 
+41 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex6.subx.html b/html/apps/ex6.subx.html new file mode 100644 index 00000000..c8bbdd21 --- /dev/null +++ b/html/apps/ex6.subx.html @@ -0,0 +1,96 @@ + + + + +Mu - examples/ex6.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex6.subx +
+ 1 # Print out a (global variable) string to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex6.subx -o examples/ex6
+ 5 #   $ ./subx run examples/ex6
+ 6 #   Hello, world!
+ 7 
+ 8 == code
+ 9 
+10 # . op          subop               mod             rm32          base        index         scale       r32
+11 # . 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
+12 
+13 Entry:
+14     # write(stdout, X, Size)
+15     # . fd = 1 (stdout)
+16     bb/copy-to-ebx  1/imm32
+17     # . initialize X (location to write result to)
+18     b9/copy-to-ecx  X/imm32
+19     # . initialize Size
+20     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           2/r32/edx   Size/disp32     .                 # copy *Size to edx
+21     # . syscall
+22     e8/call  syscall_write/disp32
+23 
+24     # exit(ebx)
+25     e8/call  syscall_exit/disp32
+26 
+27 == data
+28 
+29 Size:  # size of string
+30     0x0e/imm32  # 14
+31 X:  # string to print
+32     48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a       00
+33 #   H  e  l  l  o  ,  ␣  w  o  r  l  d  !  newline  null
+34 
+35 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex7.subx.html b/html/apps/ex7.subx.html new file mode 100644 index 00000000..762bf7ec --- /dev/null +++ b/html/apps/ex7.subx.html @@ -0,0 +1,159 @@ + + + + +Mu - examples/ex7.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex7.subx +
+ 1 # Example showing file syscalls.
+ 2 #
+ 3 # Create a file, open it for writing, write a character to it, close it, open
+ 4 # it for reading, read a character from it, close it, delete it, and return
+ 5 # the character read.
+ 6 #
+ 7 # To run:
+ 8 #   $ ./subx translate init.linux examples/ex7.subx -o examples/ex7
+ 9 #   $ ./subx run examples/ex7
+10 # Expected result:
+11 #   $ echo $?
+12 #   97
+13 
+14 == code
+15 #   instruction                     effective address                                                   register    displacement    immediate
+16 # . op          subop               mod             rm32          base        index         scale       r32
+17 # . 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
+18 
+19 Entry:
+20     # creat(Filename)
+21     bb/copy-to-ebx  Filename/imm32
+22     b9/copy-to-ecx  0x180/imm32/fixed-perms
+23     e8/call  syscall_creat/disp32
+24 
+25     # stream = open(Filename, O_WRONLY, 0)  # we can't use 'fd' because it looks like a hex byte
+26     bb/copy-to-ebx  Filename/imm32
+27     b9/copy-to-ecx  1/imm32/wronly
+28     ba/copy-to-edx  0x180/imm32/fixed-perms
+29     e8/call  syscall_open/disp32
+30     # save stream
+31     bb/copy-to-ebx  Stream/imm32
+32     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+33 
+34     # write(Stream, "a", 1)
+35     # . load stream
+36     bb/copy-to-ebx  Stream/imm32
+37     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+38     # .
+39     b9/copy-to-ecx  A/imm32
+40     ba/copy-to-edx  1/imm32/size
+41     e8/call  syscall_write/disp32
+42 
+43     # close(Stream)
+44     # . load stream
+45     bb/copy-to-ebx  Stream/imm32
+46     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+47     # .
+48     e8/call  syscall_close/disp32
+49 
+50     # stream = open(Filename, O_RDONLY, 0)
+51     bb/copy-to-ebx  Filename/imm32
+52     b9/copy-to-ecx  0/imm32/rdonly
+53     ba/copy-to-edx  0x180/imm32/fixed-perms
+54     e8/call  syscall_open/disp32
+55     # . save Stream
+56     bb/copy-to-ebx  Stream/imm32
+57     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+58 
+59     # read(Stream, B, 1)
+60     # . load stream
+61     bb/copy-to-ebx  Stream/imm32
+62     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+63     # .
+64     b9/copy-to-ecx  B/imm32
+65     ba/copy-to-edx  1/imm32/size
+66     e8/call  syscall_read/disp32
+67 
+68     # close(Stream)
+69     # . load stream
+70     bb/copy-to-ebx  Stream/imm32
+71     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+72     #
+73     e8/call  syscall_close/disp32
+74 
+75     # unlink(filename)
+76     bb/copy-to-ebx  Filename/imm32
+77     e8/call  syscall_unlink/disp32
+78 
+79     # exit(b)
+80     # . load b
+81     bb/copy-to-ebx  B/imm32
+82     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+83     #
+84     e8/call  syscall_exit/disp32
+85 
+86 == data
+87 
+88 Stream:
+89     0/imm32
+90 A:
+91     61/imm32/A
+92 B:
+93     0/imm32
+94 Filename:
+95     2e 66 6f 6f 00 00 00 00
+96 #   .  f  o  o  null
+97 
+98 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex8.subx.html b/html/apps/ex8.subx.html new file mode 100644 index 00000000..1f57fcdf --- /dev/null +++ b/html/apps/ex8.subx.html @@ -0,0 +1,123 @@ + + + + +Mu - examples/ex8.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex8.subx +
+ 1 # Example reading commandline arguments: compute length of first arg.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./subx translate init.linux examples/ex8.subx -o examples/ex8
+ 5 #   $ ./subx run examples/ex8 abc de fghi
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   3  # length of 'abc'
+ 9 #
+10 # At the start of a SubX program:
+11 #   argc: *esp
+12 #   argv[0]: *(esp+4)
+13 #   argv[1]: *(esp+8)
+14 #   ...
+15 # Locals start from esp-4 downwards.
+16 
+17 == code
+18 #   instruction                     effective address                                                   register    displacement    immediate
+19 # . op          subop               mod             rm32          base        index         scale       r32
+20 # . 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
+21 
+22 Entry:
+23     # . prologue
+24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+25     # eax = ascii-length(argv[1])
+26     # . . push args
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call  ascii-length/disp32
+30     # . . discard args
+31     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+32 
+33     # exit(eax)
+34     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+35     e8/call  syscall_exit/disp32
+36 
+37 ascii-length:  # s : (address array byte) -> n/eax
+38     # edx = s
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   4/disp8         .                 # copy *(esp+4) to edx
+40     # var result/eax = 0
+41     b8/copy-to-eax  0/imm32
+42 $ascii-length:loop:
+43     # var c/ecx = *s
+44     8a/copy-byte                    0/mod/*         2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
+45     # if (c == '\0') break
+46     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
+47     74/jump-if-equal  $ascii-length:end/disp8
+48     # ++s
+49     42/increment-edx
+50     # ++result
+51     40/increment-eax
+52     # loop
+53     eb/jump  $ascii-length:loop/disp8
+54 $ascii-length:end:
+55     # return eax
+56     c3/return
+57 
+58 == data
+59 
+60 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/ex9.subx.html b/html/apps/ex9.subx.html new file mode 100644 index 00000000..fbf7b76c --- /dev/null +++ b/html/apps/ex9.subx.html @@ -0,0 +1,114 @@ + + + + +Mu - examples/ex9.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/examples/ex9.subx +
+ 1 # Example showing arg order on the stack.
+ 2 #
+ 3 # Show difference between ascii codes of first letter of first arg and first
+ 4 # letter of second arg.
+ 5 #
+ 6 # To run:
+ 7 #   $ ./subx translate init.linux examples/ex9.subx -o examples/ex9
+ 8 #   $ ./subx run examples/ex9 z x
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   2
+12 #
+13 # At the start of a SubX program:
+14 #   argc: *esp
+15 #   argv[0]: *(esp+4)
+16 #   argv[1]: *(esp+8)
+17 #   ...
+18 # Locals start from esp-4 downwards.
+19 
+20 == code
+21 #   instruction                     effective address                                                   register    displacement    immediate
+22 # . op          subop               mod             rm32          base        index         scale       r32
+23 # . 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
+24 
+25 Entry:
+26     # . prologue
+27     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+28     # ascii-difference(argv[1], argv[2])
+29     # . . push argv[2]
+30     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+31     # . . push argv[1]
+32     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+33     # . . call
+34     e8/call  ascii-difference/disp32
+35     # . . discard args
+36     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+37     # exit(eax)
+38     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+39     e8/call  syscall_exit/disp32
+40 
+41 ascii-difference:  # (s1, s2) : null-terminated ascii strings
+42     # a = first letter of s1 (ecx)
+43     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              0/r32/eax   4/disp8         .                 # copy *(esp+4) to eax
+44     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
+45     # b = first letter of s2 (edx)
+46     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   8/disp8                           # copy *(esp+8) to ecx
+47     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # copy *ecx to ecx
+48     # a-b
+49     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+50     c3/return
+51 
+52 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/examples/ex1.subx.html b/html/examples/ex1.subx.html deleted file mode 100644 index c4105769..00000000 --- a/html/examples/ex1.subx.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - -Mu - examples/ex1.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex1.subx -
- 1 # First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
- 2 # Just return 42.
- 3 #
- 4 # To run:
- 5 #   $ ./subx translate init.linux examples/ex1.2.subx -o examples/ex1
- 6 #   $ ./subx run examples/ex1
- 7 # Expected result:
- 8 #   $ echo $?
- 9 #   42
-10 
-11 == code
-12 
-13 Entry:
-14 # exit(42)
-15 bb/copy-to-ebx  2a/imm32  # 42 in hex
-16 e8/call  syscall_exit/disp32
-17 
-18 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex10.subx.html b/html/examples/ex10.subx.html deleted file mode 100644 index bcf0e466..00000000 --- a/html/examples/ex10.subx.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - -Mu - examples/ex10.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex10.subx -
- 1 # String comparison: return 1 iff the two args passed in at the commandline are equal.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex10.subx -o examples/ex10
- 5 #   $ ./subx run examples/ex10 abc abd
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   0  # false
- 9 
-10 == code
-11 #   instruction                     effective address                                                   register    displacement    immediate
-12 # . op          subop               mod             rm32          base        index         scale       r32
-13 # . 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
-14 
-15 Entry:  # return argv-equal(argv[1], argv[2])
-16 #       At the start of a SubX program:
-17 #         argc: *esp
-18 #         argv[0]: *(esp+4)
-19 #         argv[1]: *(esp+8)
-20 #         ...
-21     # . prologue
-22     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-23     # argv-equal(argv[1], argv[2])
-24     # . . push argv[2]
-25     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-26     # . . push argv[1]
-27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-28     # . . call
-29     e8/call argv-equal/disp32
-30     # exit(eax)
-31     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
-32     e8/call  syscall_exit/disp32
-33 
-34 # compare two null-terminated ascii strings
-35 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
-36 argv-equal:  # (s1, s2) : null-terminated ascii strings -> eax : boolean
-37     # initialize s1 (ecx) and s2 (edx)
-38     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   4/disp8         .                 # copy *(esp+4) to ecx
-39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   8/disp8         .                 # copy *(esp+8) to edx
-40 $argv-equal:loop:
-41     # c1/eax, c2/ebx = *s1, *s2
-42     b8/copy-to-eax  0/imm32
-43     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
-44     bb/copy-to-ebx  0/imm32
-45     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
-46     # if (c1 == 0) break
-47     3d/compare-eax-and  0/imm32
-48     74/jump-if-equal  $argv-equal:break/disp8
-49     # if (c1 != c2) return false
-50     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
-51     75/jump-if-not-equal  $argv-equal:false/disp8
-52     # ++s1, ++s2
-53     41/increment-ecx
-54     42/increment-edx
-55     # end while
-56     eb/jump  $argv-equal:loop/disp8
-57 $argv-equal:break:
-58     # if (c2 == 0) return true
-59     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32           # compare ebx
-60     75/jump-if-not-equal  $argv-equal:false/disp8
-61 $argv-equal:success:
-62     b8/copy-to-eax  1/imm32
-63     c3/return
-64     # return false
-65 $argv-equal:false:
-66     b8/copy-to-eax  0/imm32
-67     c3/return
-68 
-69 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex11.subx.html b/html/examples/ex11.subx.html deleted file mode 100644 index 47c0b289..00000000 --- a/html/examples/ex11.subx.html +++ /dev/null @@ -1,421 +0,0 @@ - - - - -Mu - examples/ex11.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex11.subx -
-  1 # Null-terminated vs length-prefixed ascii strings.
-  2 #
-  3 # By default we create strings with a 4-byte length prefix rather than a null suffix.
-  4 # However we still need null-prefixed strings when interacting with the Linux
-  5 # kernel in a few places. This layer implements a function for comparing
-  6 # a null-terminated 'kernel string' with a length-prefixed 'SubX string'.
-  7 #
-  8 # To run:
-  9 #   $ ./subx translate init.linux examples/ex11.subx -o examples/ex11
- 10 #   $ ./subx run examples/ex11  # runs a series of tests
- 11 #   ......  # all tests pass
- 12 #
- 13 # (We can't yet run the tests when given a "test" commandline argument,
- 14 # because checking for it would require the function being tested! Breakage
- 15 # would cause tests to not run, rather than to fail as we'd like.)
- 16 
- 17 == code
- 18 #   instruction                     effective address                                                   register    displacement    immediate
- 19 # . op          subop               mod             rm32          base        index         scale       r32
- 20 # . 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
- 21 
- 22 Entry:  # run all tests
- 23     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
- 24     # exit(eax)
- 25     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
- 26     e8/call  syscall_exit/disp32
- 27 
- 28 # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array
- 29 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
- 30 kernel-string-equal?:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> eax : boolean
- 31     # pseudocode:
- 32     #   n = benchmark->length
- 33     #   s1 = s
- 34     #   s2 = benchmark->data
- 35     #   i = 0
- 36     #   while i < n
- 37     #     c1 = *s1
- 38     #     c2 = *s2
- 39     #     if (c1 == 0) return false
- 40     #     if (c1 != c2) return false
- 41     #     ++s1, ++s2, ++i
- 42     #   return *s1 == 0
- 43     #
- 44     # registers:
- 45     #   i: ecx
- 46     #   n: edx
- 47     #   s1: edi
- 48     #   s2: esi
- 49     #   c1: eax
- 50     #   c2: ebx
- 51     #
- 52     # . prologue
- 53     55/push-ebp
- 54     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 55     # . save registers
- 56     51/push-ecx
- 57     52/push-edx
- 58     53/push-ebx
- 59     56/push-esi
- 60     57/push-edi
- 61     # s1/edi = s
- 62     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
- 63     # n/edx = benchmark->length
- 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
- 65     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
- 66     # s2/esi = benchmark->data
- 67     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
- 68     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
- 69     # i/ecx = c1/eax = c2/ebx = 0
- 70     b9/copy-to-ecx  0/imm32/exit
- 71     b8/copy-to-eax  0/imm32
- 72     bb/copy-to-ebx  0/imm32
- 73 $kernel-string-equal?:loop:
- 74     # if (i >= n) break
- 75     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 76     7d/jump-if-greater-or-equal  $kernel-string-equal?:break/disp8
- 77     # c1 = *s1
- 78     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
- 79     # c2 = *s2
- 80     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
- 81     # if (c1 == 0) return false
- 82     3d/compare-eax-and  0/imm32
- 83     74/jump-if-equal  $kernel-string-equal?:false/disp8
- 84     # if (c1 != c2) return false
- 85     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
- 86     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
- 87     # ++i
- 88     41/increment-ecx
- 89     # ++s1
- 90     47/increment-edi
- 91     # ++s2
- 92     46/increment-esi
- 93     eb/jump  $kernel-string-equal?:loop/disp8
- 94 $kernel-string-equal?:break:
- 95     # return *s1 == 0
- 96     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
- 97     3d/compare-eax-and  0/imm32
- 98     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
- 99 $kernel-string-equal?:true:
-100     b8/copy-to-eax  1/imm32
-101     eb/jump  $kernel-string-equal?:end/disp8
-102 $kernel-string-equal?:false:
-103     b8/copy-to-eax  0/imm32
-104 $kernel-string-equal?:end:
-105     # . restore registers
-106     5f/pop-to-edi
-107     5e/pop-to-esi
-108     5b/pop-to-ebx
-109     5a/pop-to-edx
-110     59/pop-to-ecx
-111     # . epilogue
-112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-113     5d/pop-to-ebp
-114     c3/return
-115 
-116 # - tests
-117 
-118 test-compare-null-kernel-string-with-empty-array:
-119     # eax = kernel-string-equal?(Null-kernel-string, "")
-120     # . . push args
-121     68/push  ""/imm32
-122     68/push  Null-kernel-string/imm32
-123     # . . call
-124     e8/call  kernel-string-equal?/disp32
-125     # . . discard args
-126     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-127     # check-ints-equal(eax, 1, msg)
-128     # . . push args
-129     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
-130     68/push  1/imm32/true
-131     50/push-eax
-132     # . . call
-133     e8/call  check-ints-equal/disp32
-134     # . . discard args
-135     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-136     c3/return
-137 
-138 test-compare-null-kernel-string-with-non-empty-array:
-139     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
-140     # . . push args
-141     68/push  "Abc"/imm32
-142     68/push  Null-kernel-string/imm32
-143     # . . call
-144     e8/call  kernel-string-equal?/disp32
-145     # . . discard args
-146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-147     # check-ints-equal(eax, 0, msg)
-148     # . . push args
-149     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
-150     68/push  0/imm32/false
-151     50/push-eax
-152     # . . call
-153     e8/call  check-ints-equal/disp32
-154     # . . discard args
-155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-156     c3/return
-157 
-158 test-compare-kernel-string-with-equal-array:
-159     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
-160     # . . push args
-161     68/push  "Abc"/imm32
-162     68/push  _test-Abc-kernel-string/imm32
-163     # . . call
-164     e8/call  kernel-string-equal?/disp32
-165     # . . discard args
-166     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-167     # check-ints-equal(eax, 1, msg)
-168     # . . push args
-169     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-170     68/push  1/imm32/true
-171     50/push-eax
-172     # . . call
-173     e8/call  check-ints-equal/disp32
-174     # . . discard args
-175     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-176     c3/return
-177 
-178 test-compare-kernel-string-with-inequal-array:
-179     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
-180     # . . push args
-181     68/push  "Adc"/imm32
-182     68/push  _test-Abc-kernel-string/imm32
-183     # . . call
-184     e8/call  kernel-string-equal?/disp32
-185     # . . discard args
-186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-187     # check-ints-equal(eax, 0, msg)
-188     # . . push args
-189     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-190     68/push  0/imm32/false
-191     50/push-eax
-192     # . . call
-193     e8/call  check-ints-equal/disp32
-194     # . . discard args
-195     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-196     c3/return
-197 
-198 test-compare-kernel-string-with-empty-array:
-199     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
-200     # . . push args
-201     68/push  ""/imm32
-202     68/push  _test-Abc-kernel-string/imm32
-203     # . . call
-204     e8/call  kernel-string-equal?/disp32
-205     # . . discard args
-206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-207     # check-ints-equal(eax, 0, msg)
-208     # . . push args
-209     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-210     68/push  0/imm32/false
-211     50/push-eax
-212     # . . call
-213     e8/call  check-ints-equal/disp32
-214     # . . discard args
-215     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-216     c3/return
-217 
-218 test-compare-kernel-string-with-shorter-array:
-219     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
-220     # . . push args
-221     68/push  "Ab"/imm32
-222     68/push  _test-Abc-kernel-string/imm32
-223     # . . call
-224     e8/call  kernel-string-equal?/disp32
-225     # . . discard args
-226     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-227     # check-ints-equal(eax, 0, msg)
-228     # . . push args
-229     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
-230     68/push  0/imm32/false
-231     50/push-eax
-232     # . . call
-233     e8/call  check-ints-equal/disp32
-234     # . . discard args
-235     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-236     c3/return
-237 
-238 test-compare-kernel-string-with-longer-array:
-239     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
-240     # . . push args
-241     68/push  "Abcd"/imm32
-242     68/push  _test-Abc-kernel-string/imm32
-243     # . . call
-244     e8/call  kernel-string-equal?/disp32
-245     # . . discard args
-246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-247     # check-ints-equal(eax, 0, msg)
-248     # . . push args
-249     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
-250     68/push  0/imm32/false
-251     50/push-eax
-252     # . . call
-253     e8/call  check-ints-equal/disp32
-254     # . . discard args
-255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-256     c3/return
-257 
-258 # - helpers
-259 
-260 # print msg to stderr if a != b, otherwise print "."
-261 check-ints-equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
-262     # . prologue
-263     55/push-ebp
-264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-265     # . save registers
-266     51/push-ecx
-267     53/push-ebx
-268     # load args into eax, ebx and ecx
-269     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
-270     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
-271     # if (eax == b/ebx) print('.') and return
-272     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
-273     75/jump-if-unequal  $check-ints-equal:else/disp8
-274     # . write-stderr('.')
-275     # . . push args
-276     68/push  "."/imm32
-277     # . . call
-278     e8/call  write-stderr/disp32
-279     # . . discard args
-280     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-281     # . return
-282     eb/jump  $check-ints-equal:end/disp8
-283     # otherwise print(msg)
-284 $check-ints-equal:else:
-285     # copy msg into ecx
-286     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8       .                # copy *(ebp+16) to ecx
-287     # print(ecx)
-288     # . . push args
-289     51/push-ecx
-290     # . . call
-291     e8/call  write-stderr/disp32
-292     # . . discard args
-293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-294     # print newline
-295     # . . push args
-296     68/push  Newline/imm32
-297     # . . call
-298     e8/call  write-stderr/disp32
-299     # . . discard args
-300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-301 $check-ints-equal:end:
-302     # . restore registers
-303     5b/pop-to-ebx
-304     59/pop-to-ecx
-305     # end
-306     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-307     5d/pop-to-ebp
-308     c3/return
-309 
-310 write-stderr:  # s : (address array byte) -> <void>
-311     # . prologue
-312     55/push-ebp
-313     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-314     # . save registers
-315     50/push-eax
-316     51/push-ecx
-317     52/push-edx
-318     53/push-ebx
-319     # syscall(write, 2/stderr, (data) s+4, (size) *s)
-320     # . . fd = 2 (stderr)
-321     bb/copy-to-ebx  2/imm32
-322     # . . x = s+4
-323     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
-324     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
-325     # . . size = *s
-326     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   8/disp8         .                 # copy *(ebp+8) to edx
-327     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
-328     # . . syscall
-329     e8/call  syscall_write/disp32
-330     # . restore registers
-331     5b/pop-to-ebx
-332     5a/pop-to-edx
-333     59/pop-to-ecx
-334     58/pop-to-eax
-335     # . end
-336     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-337     5d/pop-to-ebp
-338     c3/return
-339 
-340 == data
-341 
-342 Newline:
-343     # size
-344     1/imm32
-345     # data
-346     0a/newline
-347 
-348 # for kernel-string-equal tests
-349 Null-kernel-string:
-350     00/null
-351 
-352 _test-Abc-kernel-string:
-353     41/A 62/b 63/c 00/null
-354 
-355 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex12.subx.html b/html/examples/ex12.subx.html deleted file mode 100644 index a6b2dc64..00000000 --- a/html/examples/ex12.subx.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -Mu - examples/ex12.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex12.subx -
- 1 # Example showing mmap syscall.
- 2 # Create a new segment using mmap, save the address, write to it.
- 3 #
- 4 # To run:
- 5 #   $ ./subx translate init.linux examples/ex12.subx -o examples/ex12
- 6 #   $ ./subx run examples/ex12
- 7 # You shouldn't get a segmentation fault.
- 8 
- 9 == code
-10 #   instruction                     effective address                                                   register    displacement    immediate
-11 # . op          subop               mod             rm32          base        index         scale       r32
-12 # . 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
-13 
-14 Entry:
-15     # mmap(Mmap-new-segment->len)
-16     bb/copy-to-ebx  Mmap-new-segment/imm32
-17     e8/call  syscall_mmap/disp32
-18 
-19     # write to *eax to check that we have access to the newly-allocated segment
-20     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0x34/imm32        # copy to *eax
-21 
-22     # exit(eax)
-23     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
-24     e8/call  syscall_exit/disp32
-25 
-26 == data
-27 
-28 # various constants used here were found in the Linux sources (search for file mman-common.h)
-29 Mmap-new-segment:  # type mmap_arg_struct
-30     # addr
-31     0/imm32
-32     # len
-33     0x100/imm32
-34     # protection flags
-35     3/imm32  # PROT_READ | PROT_WRITE
-36     # sharing flags
-37     0x22/imm32  # MAP_PRIVATE | MAP_ANONYMOUS
-38     # fd
-39     -1/imm32  # since MAP_ANONYMOUS is specified
-40     # offset
-41     0/imm32  # since MAP_ANONYMOUS is specified
-42 
-43 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex2.subx.html b/html/examples/ex2.subx.html deleted file mode 100644 index c67315e9..00000000 --- a/html/examples/ex2.subx.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - -Mu - examples/ex2.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex2.subx -
- 1 # Add 1 and 1, and return the result in the exit code.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex2.subx -o examples/ex2
- 5 #   $ ./subx run examples/ex2
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   2
- 9 
-10 == code
-11 
-12 Entry:
-13 # ebx = 1
-14 bb/copy-to-ebx  1/imm32
-15 # increment ebx
-16 43/increment-ebx
-17 # exit(ebx)
-18 e8/call  syscall_exit/disp32
-19 
-20 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex3.subx.html b/html/examples/ex3.subx.html deleted file mode 100644 index 7c3da099..00000000 --- a/html/examples/ex3.subx.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - -Mu - examples/ex3.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex3.subx -
- 1 # Add the first 10 numbers, and return the result in the exit code.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex3.subx -o examples/ex3
- 5 #   $ ./subx run examples/ex3
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   55
- 9 
-10 == code
-11 #   instruction                     effective address                                                   register    displacement    immediate
-12 # . op          subop               mod             rm32          base        index         scale       r32
-13 # . 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
-14 
-15 Entry:
-16     # result: ebx = 0
-17     bb/copy-to-ebx  0/imm32
-18     # counter: ecx = 1
-19     b9/copy-to-ecx  1/imm32
-20 
-21 $loop:
-22     # if (counter > 10) break
-23     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xa/imm32         # compare ecx
-24     7f/jump-if-greater  $exit/disp8
-25     # result += counter
-26     01/add                          3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # add ecx to ebx
-27     # ++counter
-28     41/increment-ecx
-29     # loop
-30     eb/jump  $loop/disp8
-31 
-32 $exit:
-33     # exit(ebx)
-34     e8/call  syscall_exit/disp32
-35 
-36 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex4.subx.html b/html/examples/ex4.subx.html deleted file mode 100644 index 43f5c705..00000000 --- a/html/examples/ex4.subx.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - -Mu - examples/ex4.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex4.subx -
- 1 # Read a character from stdin, save it to a global, write it to stdout.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex4.subx -o examples/ex4
- 5 #   $ ./subx run examples/ex4
- 6 
- 7 == data
- 8 
- 9 # the global variable we save to
-10 X:
-11     0/imm32  # space for read() to write to
-12 
-13 == code
-14 
-15 Entry:
-16 # read(stdin, X, 1)
-17 # . fd = 0 (stdin)
-18 bb/copy-to-ebx  0/imm32
-19 # . data = X (location to write result to)
-20 b9/copy-to-ecx  X/imm32
-21 # . size = 1 character
-22 ba/copy-to-edx  1/imm32
-23 # . syscall
-24 e8/call  syscall_read/disp32
-25 
-26 # write(stdout, X, 1)
-27 # . fd = 1 (stdout)
-28 bb/copy-to-ebx  1/imm32
-29 # . initialize X (location to read from)
-30 b9/copy-to-ecx  X/imm32
-31 # . size = 1 character
-32 ba/copy-to-edx  1/imm32
-33 # . syscall
-34 e8/call  syscall_write/disp32
-35 
-36 # exit(ebx)
-37 e8/call  syscall_exit/disp32
-38 
-39 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex5.subx.html b/html/examples/ex5.subx.html deleted file mode 100644 index f5112fa7..00000000 --- a/html/examples/ex5.subx.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - -Mu - examples/ex5.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex5.subx -
- 1 # Read a character from stdin, save it to a local on the stack, write it to stdout.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex5.subx -o examples/ex5
- 5 #   $ ./subx run examples/ex5
- 6 
- 7 == code
- 8 #   instruction                     effective address                                                   register    displacement    immediate
- 9 # . op          subop               mod             rm32          base        index         scale       r32
-10 # . 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
-11 
-12 Entry:
-13 
-14     # allocate x on the stack
-15     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # subtract from esp
-16 
-17     # read(stdin, x, 1)
-18     # . fd = 0 (stdin)
-19     bb/copy-to-ebx  0/imm32
-20     # . data = x (location to write result to)
-21     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
-22     # . size = 1 character
-23     ba/copy-to-edx  1/imm32
-24     # . syscall
-25     e8/call  syscall_read/disp32
-26 
-27     # syscall(write, stdout, x, 1)
-28     # . fd = 1 (stdout)
-29     bb/copy-to-ebx  1/imm32
-30     # . data = x (location to read from)
-31     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
-32     # . size = 1 character
-33     ba/copy-to-edx  1/imm32
-34     # . syscall
-35     b8/copy-to-eax  4/imm32/write
-36     cd/syscall  0x80/imm8
-37 
-38     # exit(ebx)
-39     e8/call  syscall_exit/disp32
-40 
-41 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex6.subx.html b/html/examples/ex6.subx.html deleted file mode 100644 index c8bbdd21..00000000 --- a/html/examples/ex6.subx.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - -Mu - examples/ex6.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex6.subx -
- 1 # Print out a (global variable) string to stdout.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex6.subx -o examples/ex6
- 5 #   $ ./subx run examples/ex6
- 6 #   Hello, world!
- 7 
- 8 == code
- 9 
-10 # . op          subop               mod             rm32          base        index         scale       r32
-11 # . 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
-12 
-13 Entry:
-14     # write(stdout, X, Size)
-15     # . fd = 1 (stdout)
-16     bb/copy-to-ebx  1/imm32
-17     # . initialize X (location to write result to)
-18     b9/copy-to-ecx  X/imm32
-19     # . initialize Size
-20     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           2/r32/edx   Size/disp32     .                 # copy *Size to edx
-21     # . syscall
-22     e8/call  syscall_write/disp32
-23 
-24     # exit(ebx)
-25     e8/call  syscall_exit/disp32
-26 
-27 == data
-28 
-29 Size:  # size of string
-30     0x0e/imm32  # 14
-31 X:  # string to print
-32     48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a       00
-33 #   H  e  l  l  o  ,  ␣  w  o  r  l  d  !  newline  null
-34 
-35 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex7.subx.html b/html/examples/ex7.subx.html deleted file mode 100644 index 762bf7ec..00000000 --- a/html/examples/ex7.subx.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - -Mu - examples/ex7.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex7.subx -
- 1 # Example showing file syscalls.
- 2 #
- 3 # Create a file, open it for writing, write a character to it, close it, open
- 4 # it for reading, read a character from it, close it, delete it, and return
- 5 # the character read.
- 6 #
- 7 # To run:
- 8 #   $ ./subx translate init.linux examples/ex7.subx -o examples/ex7
- 9 #   $ ./subx run examples/ex7
-10 # Expected result:
-11 #   $ echo $?
-12 #   97
-13 
-14 == code
-15 #   instruction                     effective address                                                   register    displacement    immediate
-16 # . op          subop               mod             rm32          base        index         scale       r32
-17 # . 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
-18 
-19 Entry:
-20     # creat(Filename)
-21     bb/copy-to-ebx  Filename/imm32
-22     b9/copy-to-ecx  0x180/imm32/fixed-perms
-23     e8/call  syscall_creat/disp32
-24 
-25     # stream = open(Filename, O_WRONLY, 0)  # we can't use 'fd' because it looks like a hex byte
-26     bb/copy-to-ebx  Filename/imm32
-27     b9/copy-to-ecx  1/imm32/wronly
-28     ba/copy-to-edx  0x180/imm32/fixed-perms
-29     e8/call  syscall_open/disp32
-30     # save stream
-31     bb/copy-to-ebx  Stream/imm32
-32     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
-33 
-34     # write(Stream, "a", 1)
-35     # . load stream
-36     bb/copy-to-ebx  Stream/imm32
-37     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
-38     # .
-39     b9/copy-to-ecx  A/imm32
-40     ba/copy-to-edx  1/imm32/size
-41     e8/call  syscall_write/disp32
-42 
-43     # close(Stream)
-44     # . load stream
-45     bb/copy-to-ebx  Stream/imm32
-46     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
-47     # .
-48     e8/call  syscall_close/disp32
-49 
-50     # stream = open(Filename, O_RDONLY, 0)
-51     bb/copy-to-ebx  Filename/imm32
-52     b9/copy-to-ecx  0/imm32/rdonly
-53     ba/copy-to-edx  0x180/imm32/fixed-perms
-54     e8/call  syscall_open/disp32
-55     # . save Stream
-56     bb/copy-to-ebx  Stream/imm32
-57     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
-58 
-59     # read(Stream, B, 1)
-60     # . load stream
-61     bb/copy-to-ebx  Stream/imm32
-62     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
-63     # .
-64     b9/copy-to-ecx  B/imm32
-65     ba/copy-to-edx  1/imm32/size
-66     e8/call  syscall_read/disp32
-67 
-68     # close(Stream)
-69     # . load stream
-70     bb/copy-to-ebx  Stream/imm32
-71     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
-72     #
-73     e8/call  syscall_close/disp32
-74 
-75     # unlink(filename)
-76     bb/copy-to-ebx  Filename/imm32
-77     e8/call  syscall_unlink/disp32
-78 
-79     # exit(b)
-80     # . load b
-81     bb/copy-to-ebx  B/imm32
-82     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
-83     #
-84     e8/call  syscall_exit/disp32
-85 
-86 == data
-87 
-88 Stream:
-89     0/imm32
-90 A:
-91     61/imm32/A
-92 B:
-93     0/imm32
-94 Filename:
-95     2e 66 6f 6f 00 00 00 00
-96 #   .  f  o  o  null
-97 
-98 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex8.subx.html b/html/examples/ex8.subx.html deleted file mode 100644 index 1f57fcdf..00000000 --- a/html/examples/ex8.subx.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - -Mu - examples/ex8.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex8.subx -
- 1 # Example reading commandline arguments: compute length of first arg.
- 2 #
- 3 # To run:
- 4 #   $ ./subx translate init.linux examples/ex8.subx -o examples/ex8
- 5 #   $ ./subx run examples/ex8 abc de fghi
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   3  # length of 'abc'
- 9 #
-10 # At the start of a SubX program:
-11 #   argc: *esp
-12 #   argv[0]: *(esp+4)
-13 #   argv[1]: *(esp+8)
-14 #   ...
-15 # Locals start from esp-4 downwards.
-16 
-17 == code
-18 #   instruction                     effective address                                                   register    displacement    immediate
-19 # . op          subop               mod             rm32          base        index         scale       r32
-20 # . 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
-21 
-22 Entry:
-23     # . prologue
-24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-25     # eax = ascii-length(argv[1])
-26     # . . push args
-27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-28     # . . call
-29     e8/call  ascii-length/disp32
-30     # . . discard args
-31     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-32 
-33     # exit(eax)
-34     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
-35     e8/call  syscall_exit/disp32
-36 
-37 ascii-length:  # s : (address array byte) -> n/eax
-38     # edx = s
-39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   4/disp8         .                 # copy *(esp+4) to edx
-40     # var result/eax = 0
-41     b8/copy-to-eax  0/imm32
-42 $ascii-length:loop:
-43     # var c/ecx = *s
-44     8a/copy-byte                    0/mod/*         2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
-45     # if (c == '\0') break
-46     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
-47     74/jump-if-equal  $ascii-length:end/disp8
-48     # ++s
-49     42/increment-edx
-50     # ++result
-51     40/increment-eax
-52     # loop
-53     eb/jump  $ascii-length:loop/disp8
-54 $ascii-length:end:
-55     # return eax
-56     c3/return
-57 
-58 == data
-59 
-60 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/examples/ex9.subx.html b/html/examples/ex9.subx.html deleted file mode 100644 index fbf7b76c..00000000 --- a/html/examples/ex9.subx.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - -Mu - examples/ex9.subx - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/examples/ex9.subx -
- 1 # Example showing arg order on the stack.
- 2 #
- 3 # Show difference between ascii codes of first letter of first arg and first
- 4 # letter of second arg.
- 5 #
- 6 # To run:
- 7 #   $ ./subx translate init.linux examples/ex9.subx -o examples/ex9
- 8 #   $ ./subx run examples/ex9 z x
- 9 # Expected result:
-10 #   $ echo $?
-11 #   2
-12 #
-13 # At the start of a SubX program:
-14 #   argc: *esp
-15 #   argv[0]: *(esp+4)
-16 #   argv[1]: *(esp+8)
-17 #   ...
-18 # Locals start from esp-4 downwards.
-19 
-20 == code
-21 #   instruction                     effective address                                                   register    displacement    immediate
-22 # . op          subop               mod             rm32          base        index         scale       r32
-23 # . 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
-24 
-25 Entry:
-26     # . prologue
-27     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-28     # ascii-difference(argv[1], argv[2])
-29     # . . push argv[2]
-30     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-31     # . . push argv[1]
-32     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-33     # . . call
-34     e8/call  ascii-difference/disp32
-35     # . . discard args
-36     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-37     # exit(eax)
-38     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
-39     e8/call  syscall_exit/disp32
-40 
-41 ascii-difference:  # (s1, s2) : null-terminated ascii strings
-42     # a = first letter of s1 (ecx)
-43     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              0/r32/eax   4/disp8         .                 # copy *(esp+4) to eax
-44     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
-45     # b = first letter of s2 (edx)
-46     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   8/disp8                           # copy *(esp+8) to ecx
-47     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # copy *ecx to ecx
-48     # a-b
-49     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
-50     c3/return
-51 
-52 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/test_apps b/test_apps index b9b22db1..eaf102e8 100755 --- a/test_apps +++ b/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. diff --git a/vimrc.vim b/vimrc.vim index 0200e01c..c01ab5c5 100644 --- a/vimrc.vim +++ b/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 -- cgit 1.4.1-2-gfad0