4808 - clean up comments in all subx files

This commit is contained in:
Kartik Agaram 2018-11-30 16:45:15 -08:00
parent 4cb6970d9d
commit 9d27e966b5
25 changed files with 394 additions and 384 deletions

View File

@ -7,14 +7,17 @@
# main: (manual test if this is the last file loaded)
# check-ints-equal(34, 34)
# . . push args
68/push "error in check-ints-equal"/imm32
68/push 34/imm32
68/push 34/imm32
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# syscall(exit, 0)
bb/copy-to-EBX 0/imm32
b8/copy-to-EAX 1/imm32
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8
# print msg to stderr if a != b, otherwise print "."
@ -28,10 +31,10 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
# load first 2 args into EAX and EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0x8/disp8 . # copy *(EBP+8) to EAX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX
# if EAX == b/EBX
# if EAX == EBX success
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(2/stderr, '.')
# . _write(2/stderr, '.')
# . . push args
68/push "."/imm32
68/push 2/imm32/stderr
@ -39,11 +42,11 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# return
# . return
eb/jump $check-ints-equal:end/disp8
# else:
# otherwise print error message
$check-ints-equal:else:
# _write(2/stderr, msg)
# . _write(2/stderr, msg)
# . . push args
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX
51/push-ECX
@ -52,7 +55,7 @@ $check-ints-equal:else:
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# _write(2/stderr, Newline)
# . _write(2/stderr, Newline)
# . . push args
68/push Newline/imm32
68/push 2/imm32/stderr

View File

@ -1,4 +1,4 @@
## Checking null-terminated ascii strings.
# Checking null-terminated 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
@ -21,7 +21,7 @@
# main:
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# exit(Num-test-failures)
# syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8
@ -109,7 +109,7 @@ $kernel-string-equal:end:
5d/pop-to-EBP
c3/return
## tests
# - tests
test-compare-null-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Null-kernel-string, "")
@ -120,7 +120,7 @@ test-compare-null-kernel-string-with-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# 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
@ -140,7 +140,7 @@ test-compare-null-kernel-string-with-non-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# 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
@ -160,7 +160,7 @@ test-compare-kernel-string-with-equal-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 1/imm32/true
@ -180,7 +180,7 @@ test-compare-kernel-string-with-inequal-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false
@ -200,7 +200,7 @@ test-compare-kernel-string-with-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false
@ -220,7 +220,7 @@ test-compare-kernel-string-with-shorter-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
68/push 0/imm32/false
@ -240,7 +240,7 @@ test-compare-kernel-string-with-longer-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-longer-array"/imm32
68/push 0/imm32/false

View File

@ -14,10 +14,10 @@
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# store to *EAX
# write to *EAX to check that we have access to the newly-allocated segment
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
# exit(EAX)
# syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8

View File

@ -6,8 +6,9 @@
# . 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
# main:
# run-tests()
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# exit(Num-test-failures)
# syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8
@ -84,7 +85,7 @@ $string-equal:end:
5d/pop-to-EBP
c3/return
## tests
# - tests
test-compare-empty-with-empty-string:
# EAX = string-equal("", "")
@ -95,7 +96,7 @@ test-compare-empty-with-empty-string:
e8/call string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-empty-with-empty-string"/imm32
68/push 1/imm32/true
@ -115,7 +116,7 @@ test-compare-empty-with-non-empty-string: # also checks length-mismatch code pa
e8/call string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-empty-with-non-empty-string"/imm32
68/push 0/imm32/false
@ -135,7 +136,7 @@ test-compare-equal-strings:
e8/call string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-equal-strings"/imm32
68/push 1/imm32/true
@ -155,7 +156,7 @@ test-compare-inequal-strings-equal-lengths:
e8/call string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-inequal-strings-equal-lengths"/imm32
68/push 0/imm32/false

View File

@ -43,6 +43,7 @@ _test-trace-stream:
# . 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
# main:
# run-tests()
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
@ -87,12 +88,12 @@ trace: # t : (address trace-stream), line : string
# EDX = t->length
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX
# EAX = _append-3(&t->data[t->write], &t->data[t->length], line)
# push line
# . . push line
56/push-ESI
# push &t->data[t->length]
# . . push &t->data[t->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX
53/push-EBX
# push &t->data[t->write]
# . . push &t->data[t->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX
53/push-EBX
# . . call
@ -107,12 +108,12 @@ trace: # t : (address trace-stream), line : string
# refresh ECX = t->write
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX
# EAX = _append-3(&t->data[t->write], &t->data[t->length], line)
# push line
# . . push line
68/push Newline/imm32
# push &t->data[t->length]
# . . push &t->data[t->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX
53/push-EBX
# push &t->data[t->write]
# . . push &t->data[t->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX
53/push-EBX
# . . call
@ -172,7 +173,7 @@ $clear-trace-stream:end:
5d/pop-to-EBP
c3/return
## tests
# - tests
test-trace-single:
# clear-trace-stream(_test-trace-stream)
@ -194,7 +195,7 @@ test-trace-single:
# . . push args
68/push "F - test-trace-single"/imm32
68/push 0x0a6241/imm32/Ab-newline
# push *_test-trace-stream.data
# . . push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -232,7 +233,7 @@ test-trace-appends:
# . . push args
68/push "F - test-trace-appends"/imm32
68/push 0x0a440a43/imm32/C-newline-D-newline
# push *_test-trace-stream.data
# . . push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -262,7 +263,7 @@ test-trace-empty-line:
# . . push args
68/push "F - test-trace-empty-line"/imm32
68/push 0/imm32
# push *_test-trace-stream.data
# . . push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -272,7 +273,7 @@ test-trace-empty-line:
# end
c3/return
## helpers
# - helpers
# 3-argument variant of _append
_append-3: # out : address, outend : address, s : (array byte) -> num_bytes_appended/EAX
@ -282,20 +283,17 @@ _append-3: # out : address, outend : address, s : (array byte) -> num_bytes_app
# . save registers
51/push-ECX
# _append-4(out, outend, &s.data[0], &s.data[s.length]) -> num_bytes_appended/EAX
# push &s.data[s.length]
# EAX = s
# . . push &s.data[s.length]
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX
# ECX = s.length
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
# ECX = &s.data[s.length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX
51/push-ECX
# push &s.data[0]
# . . push &s.data[0]
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX
51/push-ECX
# push outend
# . . push outend
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push out
# . . push out
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
# . . call
e8/call _append-4/disp32

View File

@ -58,12 +58,12 @@ $write:fake:
# EBX = f->length
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX
# EAX = _append-3(&f->data[f->write], &f->data[f->length], s)
# push s
# . . push s
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push &f->data[f->length]
# . . push &f->data[f->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX
53/push-EBX
# push &f->data[f->write]
# . . push &f->data[f->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX
53/push-EBX
# . . call
@ -149,7 +149,7 @@ test-write-single:
# . . push args
68/push "F - test-write-single"/imm32
68/push 0x006241/imm32/Ab
# push *_test-stream->data
# . . push *_test-stream->data
b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -187,7 +187,7 @@ test-write-appends:
# . . push args
68/push "F - test-write-appends"/imm32
68/push 0x00004443/imm32/C-D
# push *_test-stream->data
# . . push *_test-stream->data
b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call

View File

@ -65,7 +65,7 @@ tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void
# That's the value we need to return: X-nbytes-4
#
# However, we also need to account for the perturbance to ESP caused by the
# . . call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4
# call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4
# bytes for the return address and 4 bytes to push EBP above.
# So EBP at this point is X-16.
#
@ -139,12 +139,12 @@ test-stop-skips-returns-on-exit:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call _test-stop-1(ed)
# . _test-stop-1(ed)
# . . push args
50/push-EAX
# . . call
e8/call _test-stop-1/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# restore args
58/pop-to-EAX
# check that _test-stop-1 tried to call exit(1)
@ -152,7 +152,7 @@ test-stop-skips-returns-on-exit:
# . . push args
68/push "F - test-stop-skips-returns-on-exit"/imm32
68/push 2/imm32
# push ed->value
# . . push ed->value
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
# . . call
e8/call check-ints-equal/disp32
@ -173,7 +173,7 @@ _test-stop-1: # ed : (address exit-descriptor)
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call _test-stop-2/disp32
## should never get past this point
# should never get past this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# signal test failed: check-ints-equal(1, 0, msg)
@ -194,13 +194,13 @@ _test-stop-2: # ed : (address exit-descriptor)
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . . call stop(ed, 1)
# . stop(ed, 1)
# . . push args
68/push 1/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call stop/disp32
## should never get past this point
# should never get past this point
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP

View File

@ -56,7 +56,7 @@ read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor
# if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8)
7d/jump-if-greater-or-equal $read:fake/disp8
# . . push args
@ -69,7 +69,7 @@ read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX
# return
eb/jump $read:end/disp8
$read:fake:
## otherwise, treat 'f' as a stream to scan from
# otherwise, treat 'f' as a stream to scan from
# . save registers
56/push-ESI
57/push-EDI
@ -79,19 +79,19 @@ $read:fake:
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to ESI
# EAX = _append-4(out = &s->data[s->write], outend = &s->data[s->length],
# in = &f->data[f->read], inend = &f->data[f->write])
# push &f->data[f->write]
# . . push &f->data[f->write]
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
50/push-EAX
# push &f->data[f->read]
# . . push &f->data[f->read]
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
50/push-EAX
# push &s->data[s->length]
# . . push &s->data[s->length]
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 8/disp8 . # copy *(EDI+8) to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX
50/push-EAX
# push &s->data[s->write]
# . . push &s->data[s->write]
8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX
50/push-EAX
@ -112,7 +112,7 @@ $read:end:
5d/pop-to-EBP
c3/return
## helpers
# - helpers
# idea: a clear-if-empty method on streams that clears only if f.read == f.write
# Unclear how I'd use it, though. Callers seem to need the check anyway.
@ -134,13 +134,13 @@ _read: # fd : int, s : (address stream) -> num-bytes-read/EAX
# EDX = s->length
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX
# syscall(read, fd, &s->data[s->write], s->length - s->write)
# fd : EBX
# . . fd : EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
# data : ECX = &s->data[s->write]
# . . data : ECX = &s->data[s->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 1/r32/ECX 0xc/disp8 . # copy ESI+EAX+12 to ECX
# size : EDX = s->length - s->write
# . . size : EDX = s->length - s->write
29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX
# syscall
# . . syscall
b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8
# add the result EAX to s->write
@ -176,9 +176,10 @@ _read: # fd : int, s : (address stream) -> num-bytes-read/EAX
# use one less register, but doesn't increase the amount of spilling (ECX
# and EDX must be used, and EAX must be clobbered anyway).
## tests
# - tests
test-read-single:
# - write a single character into _test-stream, then read from its buffered-file
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
@ -222,7 +223,7 @@ test-read-single:
# . . push args
68/push "F - test-read-single"/imm32
68/push 0x006241/imm32/Ab
# push *_test-stream-buffer->data
# . . push *_test-stream-buffer->data
b8/copy-to-EAX _test-stream-buffer/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -233,7 +234,7 @@ test-read-single:
c3/return
test-read-is-stateful:
## make two consecutive reads, check that their results are appended
# - make two consecutive reads, check that their results are appended
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
@ -284,7 +285,7 @@ test-read-is-stateful:
# . . push args
68/push "F - test-read-is-stateful"/imm32
68/push 0x00004443/imm32/C-D
# push *_test-stream-buffer->data
# . push *_test-stream-buffer->data
b8/copy-to-EAX _test-stream-buffer/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# . . call
@ -295,22 +296,23 @@ test-read-is-stateful:
c3/return
test-read-returns-0-on-end-of-file:
## read after hitting end-of-file, check that result is 0
# clear-stream(_test-stream)
# - read after hitting end-of-file, check that result is 0
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-stream-buffer)
# . clear-stream(_test-stream-buffer)
# . . push args
68/push _test-stream-buffer/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# write(_test-stream, "Ab")
# . write(_test-stream, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream/imm32
@ -318,8 +320,8 @@ test-read-returns-0-on-end-of-file:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## first read gets to end-of-file
# read(_test-stream, _test-stream-buffer)
# first read gets to end-of-file
# . read(_test-stream, _test-stream-buffer)
# . . push args
68/push _test-stream-buffer/imm32
68/push _test-stream/imm32
@ -327,8 +329,8 @@ test-read-returns-0-on-end-of-file:
e8/call read/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## second read
# read(_test-stream, _test-stream-buffer)
# second read
# . read(_test-stream, _test-stream-buffer)
# . . push args
68/push _test-stream-buffer/imm32
68/push _test-stream/imm32

View File

@ -52,10 +52,11 @@ read-byte: # f : (address buffered-file) -> byte/EAX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
# ECX = f->read
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX
## if (f->read < f->write) read byte from stream
# if (f->read < f->write) read byte from stream
3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4)
7c/jump-if-lesser $read-byte:from-stream/disp8
# clear-stream(stream = f+4)
# otherwise first populate stream from file
# . clear-stream(stream = f+4)
# . . push args
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX
50/push-EAX
@ -63,7 +64,7 @@ read-byte: # f : (address buffered-file) -> byte/EAX
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# EAX = read(f->fd, stream = f+4)
# . EAX = read(f->fd, stream = f+4)
# . . push args
50/push-EAX
ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
@ -77,6 +78,7 @@ read-byte: # f : (address buffered-file) -> byte/EAX
b8/copy-to-EAX 0xffffffff/imm32
eb/jump $read-byte:end/disp8
$read-byte:from-stream:
# reading from stream
# AL = f->data[f->read]
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy *(ESI+ECX+16) to AL
@ -94,18 +96,19 @@ $read-byte:end:
# todo: how should write-byte look? What should it do when the output has no
# space remaining? Maybe return an error code.
## tests
# - tests
test-read-byte-single:
## check that read-byte returns first byte of 'file'
# clear-stream(_test-stream)
# - check that read-byte returns first byte of 'file'
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -114,7 +117,7 @@ test-read-byte-single:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# write(_test-stream, "Ab")
# . write(_test-stream, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream/imm32
@ -138,19 +141,20 @@ test-read-byte-single:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end
# . end
c3/return
test-read-byte-multiple:
## call read-byte twice, check that second call returns second byte
# clear-stream(_test-stream)
# - call read-byte twice, check that second call returns second byte
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -159,7 +163,7 @@ test-read-byte-multiple:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# write(_test-stream, "Ab")
# . write(_test-stream, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream/imm32
@ -190,19 +194,20 @@ test-read-byte-multiple:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end
# . end
c3/return
test-read-byte-end-of-file:
## call read-byte on an empty 'file', check that it returns -1
# clear-stream(_test-stream)
# - call read-byte on an empty 'file', check that it returns -1
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -227,7 +232,7 @@ test-read-byte-end-of-file:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end
# . end
c3/return
== data

View File

@ -45,19 +45,19 @@ $write-stream:fake:
# EDI = s
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
# EAX = _append-4(&f->data[f->write], &f->data[f->length], &s->data[s->read], &s->data[s->write])
# push &s->data[s->write]
# . . push &s->data[s->write]
8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX
50/push-EAX
# push &s->data[s->read]
# . . push &s->data[s->read]
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy *(EDI+4) to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX
50/push-EAX
# push &f->data[f->length]
# . . push &f->data[f->length]
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
50/push-EAX
# push &f->data[f->write]
# . . push &f->data[f->write]
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
50/push-EAX
@ -97,13 +97,13 @@ _write-stream: # fd : int, s : (address stream) -> <void>
# EDX = s->write
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
# syscall(write, fd, &s->data[s->read], s->write-s->read)
# fd : EBX
# . . fd : EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
# data : ECX = &s->data[s->read]
# . . data : ECX = &s->data[s->read]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 7/index/EDI . 1/r32/ECX 0xc/disp8 . # copy ESI+EDI+12 to ECX
# size : EDX = s->write - s->read
# . . size : EDX = s->write - s->read
29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX
# syscall
# . . syscall
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8
# . restore registers
@ -119,21 +119,22 @@ _write-stream: # fd : int, s : (address stream) -> <void>
c3/return
test-write-stream-single:
# clear-stream(_test-stream)
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-stream2)
# . clear-stream(_test-stream2)
# . . push args
68/push _test-stream2/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# write(_test-stream2, "Ab")
# . write(_test-stream2, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream2/imm32
@ -160,25 +161,26 @@ test-write-stream-single:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end
# . end
c3/return
test-write-stream-appends:
# clear-stream(_test-stream)
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-stream2)
# . clear-stream(_test-stream2)
# . . push args
68/push _test-stream2/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# write(_test-stream2, "C")
# . write(_test-stream2, "C")
# . . push args
68/push "C"/imm32
68/push _test-stream2/imm32
@ -186,7 +188,8 @@ test-write-stream-appends:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write-stream(_test-stream, _test-stream2)
# first write
# . write-stream(_test-stream, _test-stream2)
# . . push args
68/push _test-stream2/imm32
68/push _test-stream/imm32
@ -194,7 +197,8 @@ test-write-stream-appends:
e8/call write-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write(_test-stream2, "D")
# second write
# . write(_test-stream2, "D")
# . . push args
68/push "D"/imm32
68/push _test-stream2/imm32
@ -202,7 +206,7 @@ test-write-stream-appends:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write-stream(_test-stream, _test-stream2)
# . write-stream(_test-stream, _test-stream2)
# . . push args
68/push _test-stream2/imm32
68/push _test-stream/imm32
@ -221,7 +225,7 @@ test-write-stream-appends:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end
# . end
c3/return
== data

View File

@ -33,10 +33,11 @@
# main: run tests if necessary, call 'compile' if not
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# if (argc > 1)
# - if argc > 1 and argv[1] == "test" then return run_tests()
# . argc > 1
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP
7e/jump-if-lesser-or-equal $run-main/disp8
# and if (argv[1] == "test")
# . argv[1] == "test"
# . . push args
68/push "test"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
@ -47,19 +48,20 @@
# . check result
3d/compare-EAX 1/imm32
75/jump-if-not-equal $run-main/disp8
# then return run-tests()
# . run-tests()
e8/call run-tests/disp32
#? e8/call test-get-num-reads-multiple-digits/disp32
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
eb/jump $main:end/disp8
$run-main:
# allocate space for an exit-descriptor
# . var ed/EAX : (address exit-descriptor)
# - otherwise read a program from stdin and emit its translation to stdout
# var ed/EAX : exit-descriptor
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# . clear ed->target (so we really exit)
# configure ed to really exit()
# . ed->target = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# compile(Stdin, 1/stdout, 2/stderr, ed)
# return compile(Stdin, 1/stdout, 2/stderr, ed)
# . . push args
50/push-EAX/ed
68/push 2/imm32/stderr
@ -69,7 +71,7 @@ $run-main:
e8/call compile/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# syscall(exit, 0)
# . syscall(exit, 0)
bb/copy-to-EBX 0/imm32
$main:end:
b8/copy-to-EAX 1/imm32/exit
@ -83,7 +85,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
# . save registers
50/push-EAX
51/push-ECX
# Look = get-char(in)
# . Look = get-char(in)
# . . push args
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
@ -98,14 +100,15 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX
# num->length = 7
c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8)
# clear-stream(num)
# read a digit from 'in' into 'num'
# . clear-stream(num)
# . . push args
51/push-ECX
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# get-num(in, num, err, ed)
# . get-num(in, num, err, ed)
# . . push args
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20)
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16)
@ -115,15 +118,12 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call get-num/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# EAX = write(_test-stream, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "bb/copy-to-EBX ")
# render 'num' into the following template on 'out':
# bb/copy-to-EBX _num_
# b8/copy-to-EAX 1/imm32/exit
# cd/syscall 0x80/imm8
#
# . EAX = write(out, "bb/copy-to-EBX ")
# . . push args
68/push "bb/copy-to-EBX "/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -131,7 +131,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write-stream(out, num)
# . write-stream(out, num)
# . . push args
51/push-ECX/num
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -139,7 +139,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -147,7 +147,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "b8/copy-to-EAX 1/imm32/exit")
# . write(out, "b8/copy-to-EAX 1/imm32/exit")
# . . push args
68/push "b8/copy-to-EAX 1/imm32/exit"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -155,7 +155,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -163,7 +163,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "cd/syscall 0x80/imm8")
# . write(out, "cd/syscall 0x80/imm8")
# . . push args
68/push "cd/syscall 0x80/imm8"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -171,7 +171,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -179,7 +179,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . restore registers
# . restore registers
59/pop-to-ECX
58/pop-to-EAX
# . epilog
@ -200,7 +200,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a
# ++out.write
# Look = get-char(in)
#
# within the loop we'll try to keep things in registers:
# registers:
# ESI : in
# EDI : out
# EAX : temp
@ -214,14 +214,15 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# EAX = is-digit?(Look)
# - if is-digit?(Look) expected(ed, err, "integer")
# . EAX = is-digit?(Look)
# . . push args
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look
# . . call
e8/call is-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# if EAX == 0 error
# . if EAX == 0
3d/compare-EAX 0/imm32
75/jump-if-not-equal $get-num:main/disp8
# . expected(ed, err, "integer")
@ -234,6 +235,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
$get-num:main:
# - otherwise read a digit
# . save registers
50/push-EAX
51/push-ECX
@ -253,7 +255,7 @@ $get-num:main:
# if out->write >= out->length error
3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare EDX with ECX
7d/jump-if-lesser $get-num:stage2/disp8
# error(ed, err, "get-num: too many digits in number") # TODO: show full number
# . error(ed, err, msg) # TODO: show full number
# . . push args
68/push "get-num: too many digits in number"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16)
@ -296,15 +298,15 @@ test-get-num-reads-single-digit:
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# - clear all streams
# clear-stream(_test-stream)
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -313,22 +315,22 @@ test-get-num-reads-single-digit:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# - initialize 'in'
# write(_test-stream, "3")
# initialize 'in'
# . write(_test-stream, "3")
# . . push args
68/push "3"/imm32
68/push _test-stream/imm32
@ -336,13 +338,11 @@ test-get-num-reads-single-digit:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# - initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : exit-descriptor
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -350,15 +350,15 @@ test-get-num-reads-single-digit:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# - prime the pump
# get-char(_test-buffered-file)
# prime the pump
# . get-char(_test-buffered-file)
# . . push args
68/push _test-buffered-file/imm32
# . . call
e8/call get-char/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## get-num(in, out, err, ed)
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -366,7 +366,7 @@ test-get-num-reads-single-digit:
68/push _test-buffered-file/imm32
# . . call
e8/call get-num/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# check-ints-equal(*_test-output-stream.data, '3')
@ -379,7 +379,7 @@ test-get-num-reads-single-digit:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
@ -389,15 +389,15 @@ test-get-num-aborts-on-non-digit-in-Look:
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# - clear all streams
# clear-stream(_test-stream)
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -406,22 +406,22 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# - initialize 'in'
# write(_test-stream, "3")
# initialize 'in'
# . write(_test-stream, "3")
# . . push args
68/push "3"/imm32
68/push _test-stream/imm32
@ -429,13 +429,11 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# - initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : (address exit-descriptor)
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -443,8 +441,8 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# - don't initialize Look
# - get-num(in, out, err, ed)
# *don't* prime the pump
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -455,18 +453,18 @@ test-get-num-aborts-on-non-digit-in-Look:
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# - check that get-num tried to call exit(1)
# check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
# check that get-num tried to call exit(1)
# . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
# . . push args
68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
68/push 2/imm32
# . push ed->value
# . . push ed->value
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
@ -516,7 +514,7 @@ expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (ad
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call stop/disp32
## should never get past this point
# should never get past this point
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
@ -557,13 +555,13 @@ error: # ed : (address exit-descriptor), f : fd or (address stream), s : (addre
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call stop/disp32
## should never get past this point
# should never get past this point
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
# read a byte from 'f', and store it in 'Look'
# read a byte from 'f', and save it in 'Look'
get-char: # f : (address buffered-file) -> <void>
# . prolog
55/push-EBP

View File

@ -33,10 +33,11 @@
# main: run tests if necessary, call 'compile' if not
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# if (argc > 1)
# - if argc > 1 and argv[1] == "test" then return run_tests()
# . argc > 1
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP
7e/jump-if-lesser-or-equal $run-main/disp8
# and if (argv[1] == "test")
# . argv[1] == "test"
# . . push args
68/push "test"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
@ -44,22 +45,23 @@
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check result
# . check result
3d/compare-EAX 1/imm32
75/jump-if-not-equal $run-main/disp8
# then return run-tests()
# . run-tests()
e8/call run-tests/disp32
#? e8/call test-get-num-reads-multiple-digits/disp32
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
eb/jump $main:end/disp8
$run-main:
# allocate space for an exit-descriptor
# var ed/EAX : (address exit-descriptor)
# - otherwise read a program from stdin and emit its translation to stdout
# var ed/EAX : exit-descriptor
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# clear ed->target (so we really exit)
# configure ed to really exit()
# . ed->target = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# compile(Stdin, 1/stdout, 2/stderr, ed)
# return compile(Stdin, 1/stdout, 2/stderr, ed)
# . . push args
50/push-EAX/ed
68/push 2/imm32/stderr
@ -69,7 +71,7 @@ $run-main:
e8/call compile/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# syscall(exit, 0)
# . syscall(exit, 0)
bb/copy-to-EBX 0/imm32
$main:end:
b8/copy-to-EAX 1/imm32/exit
@ -83,7 +85,8 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
# . save registers
50/push-EAX
51/push-ECX
# Look = get-char(in)
# prime the pump
# . Look = get-char(in)
# . . push args
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
@ -98,14 +101,15 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX
# num->length = 7
c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8)
# clear-stream(num)
# read a digit from 'in' into 'num'
# . clear-stream(num)
# . . push args
51/push-ECX
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# get-num(in, num, err, ed)
# . get-num(in, num, err, ed)
# . . push args
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20)
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16)
@ -115,15 +119,12 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call get-num/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# EAX = write(_test-stream, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "bb/copy-to-EBX ")
# render 'num' into the following template on 'out':
# bb/copy-to-EBX _num_
# b8/copy-to-EAX 1/imm32/exit
# cd/syscall 0x80/imm8
#
# . EAX = write(out, "bb/copy-to-EBX ")
# . . push args
68/push "bb/copy-to-EBX "/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -131,7 +132,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write-stream(out, num)
# . write-stream(out, num)
# . . push args
51/push-ECX/num
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -139,7 +140,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -147,7 +148,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "b8/copy-to-EAX 1/imm32/exit")
# . write(out, "b8/copy-to-EAX 1/imm32/exit")
# . . push args
68/push "b8/copy-to-EAX 1/imm32/exit"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -155,7 +156,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -163,7 +164,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, "cd/syscall 0x80/imm8")
# . write(out, "cd/syscall 0x80/imm8")
# . . push args
68/push "cd/syscall 0x80/imm8"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -171,7 +172,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = write(out, Newline)
# . write(out, Newline)
# . . push args
68/push Newline/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
@ -219,17 +220,18 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# EAX = is-digit?(Look)
# - if is-digit?(Look) expected(ed, err, "integer")
# . EAX = is-digit?(Look)
# . . push args
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look
# . . call
e8/call is-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# if EAX == 0 error
# . if EAX == 0
3d/compare-EAX 0/imm32
75/jump-if-not-equal $get-num:main/disp8
# expected(ed, err, "integer")
# . expected(ed, err, "integer")
# . . push args
68/push "integer"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16)
@ -239,6 +241,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
$get-num:main:
# - otherwise read a digit
# . save registers
50/push-EAX
51/push-ECX
@ -259,7 +262,7 @@ $get-num:loop:
# if out->write >= out->length error
3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare EDX with ECX
7d/jump-if-lesser $get-num:loop-stage2/disp8
# error(ed, err, "get-num: too many digits in number") # TODO: show full number
# . error(ed, err, msg) # TODO: show full number
# . . push args
68/push "get-num: too many digits in number"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16)
@ -282,14 +285,15 @@ $get-num:loop-stage2:
e8/call get-char/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# EAX = is-digit?(Look)
# if is-digit?(Look) loop
# . EAX = is-digit?(Look)
# . . push args
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look
# . . call
e8/call is-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# if EAX loop
# . if EAX loop
3d/compare-EAX 0/imm32
0f 85/jump-if-not-equal $get-num:loop/disp32
$get-num:loop-end:
@ -308,19 +312,19 @@ $get-num:loop-end:
c3/return
test-get-num-reads-single-digit:
## check that get-num returns first character if it's a digit
# - check that get-num returns first character if it's a digit
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## clear all streams
# clear-stream(_test-stream)
# clear all streams
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -329,22 +333,22 @@ test-get-num-reads-single-digit:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## initialize 'in'
# write(_test-stream, "3")
# initialize 'in'
# . write(_test-stream, "3")
# . . push args
68/push "3"/imm32
68/push _test-stream/imm32
@ -352,13 +356,11 @@ test-get-num-reads-single-digit:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : exit-descriptor
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -366,15 +368,15 @@ test-get-num-reads-single-digit:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## prime the pump
# get-char(_test-buffered-file)
# prime the pump
# . get-char(_test-buffered-file)
# . . push args
68/push _test-buffered-file/imm32
# . . call
e8/call get-char/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## get-num(in, out, err, ed)
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -382,7 +384,7 @@ test-get-num-reads-single-digit:
68/push _test-buffered-file/imm32
# . . call
e8/call get-num/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# check-ints-equal(*_test-output-stream.data, '3')
@ -395,25 +397,25 @@ test-get-num-reads-single-digit:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
test-get-num-aborts-on-non-digit-in-Look:
## check that get-num returns first character if it's a digit
# - check that get-num returns first character if it's a digit
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## clear all streams
# clear-stream(_test-stream)
# clear all streams
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -422,22 +424,22 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## initialize 'in'
# write(_test-stream, "3")
# initialize 'in'
# . write(_test-stream, "3")
# . . push args
68/push "3"/imm32
68/push _test-stream/imm32
@ -445,13 +447,11 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : (address exit-descriptor)
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -459,8 +459,8 @@ test-get-num-aborts-on-non-digit-in-Look:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## don't initialize Look
## get-num(in, out, err, ed)
# *don't* prime the pump
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -468,39 +468,39 @@ test-get-num-aborts-on-non-digit-in-Look:
68/push _test-buffered-file/imm32
# . . call
e8/call get-num/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
## check that get-num tried to call exit(1)
# check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
# check that get-num tried to call exit(1)
# . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
# . . push args
68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
68/push 2/imm32
# push ed->value
# . . push ed->value
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
test-get-num-reads-multiple-digits:
## check that get-num returns all initial digits until it encounters a non-digit
# - check that get-num returns all initial digits until it encounters a non-digit
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## clear all streams
# clear-stream(_test-stream)
# clear all streams
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -509,22 +509,22 @@ test-get-num-reads-multiple-digits:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## initialize 'in'
# write(_test-stream, "3456 x")
# initialize 'in'
# . write(_test-stream, "3456 x")
# . . push args
68/push "3456"/imm32
68/push _test-stream/imm32
@ -532,13 +532,11 @@ test-get-num-reads-multiple-digits:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : (address exit-descriptor)
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -546,15 +544,15 @@ test-get-num-reads-multiple-digits:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## prime the pump
# get-char(_test-buffered-file)
# prime the pump
# . get-char(_test-buffered-file)
# . . push args
68/push _test-buffered-file/imm32
# . . call
e8/call get-char/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## get-num(in, out, err, ed)
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -562,7 +560,7 @@ test-get-num-reads-multiple-digits:
68/push _test-buffered-file/imm32
# . . call
e8/call get-num/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# check-ints-equal(*_test-output-stream.data, '3456')
@ -575,25 +573,25 @@ test-get-num-reads-multiple-digits:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
test-get-num-reads-multiple-digits-followed-by-nondigit:
## check that get-num returns all initial digits until it encounters a non-digit
# - check that get-num returns all initial digits until it encounters a non-digit
# This test uses exit-descriptors. Use EBP for setting up local variables.
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## clear all streams
# clear-stream(_test-stream)
# clear all streams
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-buffered-file+4)
# . clear-stream(_test-buffered-file+4)
# . . push args
b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32
@ -602,22 +600,22 @@ test-get-num-reads-multiple-digits-followed-by-nondigit:
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-output-stream)
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# clear-stream(_test-error-stream)
# . clear-stream(_test-error-stream)
# . . push args
68/push _test-error-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## initialize 'in'
# write(_test-stream, "3456 x")
# initialize 'in'
# . write(_test-stream, "3456 x")
# . . push args
68/push "3456 x"/imm32
68/push _test-stream/imm32
@ -625,13 +623,11 @@ test-get-num-reads-multiple-digits-followed-by-nondigit:
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## initialize exit-descriptor 'ed'
# allocate on stack
# var ed/EAX : (address exit-descriptor)
# initialize exit-descriptor 'ed' for the call to 'get-num' below
# . var ed/EAX : (address exit-descriptor)
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP
8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX
# size the exit-descriptor for the call to get-num below
# tailor-exit-descriptor(ed, 16)
# . tailor-exit-descriptor(ed, 16)
# . . push args
68/push 0x10/imm32/nbytes-of-args-for-get-num
50/push-EAX/ed
@ -639,15 +635,15 @@ test-get-num-reads-multiple-digits-followed-by-nondigit:
e8/call tailor-exit-descriptor/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
## prime the pump
# get-char(_test-buffered-file)
# prime the pump
# . get-char(_test-buffered-file)
# . . push args
68/push _test-buffered-file/imm32
# . . call
e8/call get-char/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
## get-num(in, out, err, ed)
# get-num(in, out, err, ed)
# . . push args
50/push-EAX/ed
68/push _test-error-stream/imm32
@ -655,7 +651,7 @@ test-get-num-reads-multiple-digits-followed-by-nondigit:
68/push _test-buffered-file/imm32
# . . call
e8/call get-num/disp32
## registers except ESP may be clobbered at this point
# registers except ESP may be clobbered at this point
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# check-ints-equal(*_test-output-stream.data, '3456')
@ -668,7 +664,7 @@ test-get-num-reads-multiple-digits-followed-by-nondigit:
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# reclaim locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
5d/pop-to-EBP
c3/return
@ -718,7 +714,7 @@ expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (ad
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call stop/disp32
## should never get past this point
# should never get past this point
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
@ -759,13 +755,13 @@ error: # ed : (address exit-descriptor), f : fd or (address stream), s : (addre
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call stop/disp32
## should never get past this point
# should never get past this point
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
# read a byte from 'f', and store it in 'Look'
# read a byte from 'f', and save it in 'Look'
get-char: # f : (address buffered-file) -> <void>
# . prolog
55/push-EBP

View File

@ -22,10 +22,11 @@
# main:
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# if (argc > 1)
# - if argc > 1 and argv[1] == "test" then return run_tests()
# . argc > 1
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP
7e/jump-if-lesser-or-equal $run-main/disp8
# and if (argv[1] == "test")
# . argv[1] == "test"
# . . push args
68/push "test"/imm32
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
@ -33,14 +34,14 @@
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check result
# . check result
3d/compare-EAX 1/imm32
75/jump-if-not-equal $run-main/disp8
# then return run-tests()
# . run-tests()
e8/call run-tests/disp32
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Num-test-failures/disp32 # copy *Num-test-failures to EAX
eb/jump $main:end/disp8 # where EAX will get copied to EBX
# else EAX = factorial(5)
# - otherwise return factorial(5)
$run-main:
# . . push args
68/push 5/imm32
@ -49,20 +50,19 @@ $run-main:
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
$main:end:
# exit(EAX)
# syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8
# factorial(n)
factorial:
factorial: # n : int -> int/EAX
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
53/push-EBX
# initialize EAX to 1 (base case)
# EAX = 1 (base case)
b8/copy-to-EAX 1/imm32
# if (n <= 1) jump exit
# if (n <= 1) return
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 1/imm32 # compare *(EBP+8)
7e/jump-if-<= $factorial:end/disp8
# EBX = n-1

View File

@ -1,4 +1,4 @@
## first program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
# First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
# Just return 42.
#
# To run (from the subx directory):
@ -10,8 +10,8 @@
== code
# syscall(exit, 42)
bb/copy-to-EBX 2a/imm32 # 42 in hex
# exit(EBX)
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## String comparison: return 1 iff the two args passed in at the commandline are equal.
# String comparison: return 1 iff the two args passed in at the commandline are equal.
#
# To run (from the subx directory):
# $ subx translate examples/ex10.subx -o examples/ex10
@ -20,15 +20,14 @@
# ...
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . . call argv-equal(argv[1], argv[2])
# push argv[2]
# argv-equal(argv[1], argv[2])
# . . push argv[2]
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push argv[1]
# . . push argv[1]
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
# . . call
e8/call argv-equal/disp32
# exit(EAX)
$exit:
# syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## Null-terminated vs length-prefixed ascii strings.
# 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
@ -108,7 +108,7 @@ $kernel-string-equal:end:
5d/pop-to-EBP
c3/return
## tests
# - tests
test-compare-null-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Null-kernel-string, "")
@ -119,7 +119,7 @@ test-compare-null-kernel-string-with-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# 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
@ -139,7 +139,7 @@ test-compare-null-kernel-string-with-non-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# 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
@ -159,7 +159,7 @@ test-compare-kernel-string-with-equal-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 1, msg)
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 1/imm32/true
@ -179,7 +179,7 @@ test-compare-kernel-string-with-inequal-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0, msg)
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false
@ -199,7 +199,7 @@ test-compare-kernel-string-with-empty-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false
@ -219,7 +219,7 @@ test-compare-kernel-string-with-shorter-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
68/push 0/imm32/false
@ -239,7 +239,7 @@ test-compare-kernel-string-with-longer-array:
e8/call kernel-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . . call check-ints-equal(EAX, 0)
# check-ints-equal(EAX, 0)
# . . push args
68/push "F - test-compare-kernel-string-with-longer-array"/imm32
68/push 0/imm32/false
@ -250,7 +250,7 @@ test-compare-kernel-string-with-longer-array:
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
## helpers
# - helpers
# print msg to stderr if a != b, otherwise print "."
check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
@ -263,19 +263,19 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
# load args into EAX, EBX and ECX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0x8/disp8 . # copy *(EBP+8) to EAX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX
# if EAX == b/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
# print('.')
# . 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
# . return
eb/jump $check-ints-equal:end/disp8
# else:
# otherwise print(msg)
$check-ints-equal:else:
# copy msg into ECX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX
@ -312,15 +312,15 @@ write-stderr: # s : (address array byte) -> <void>
52/push-EDX
53/push-EBX
# syscall(write, 2/stderr, (data) s+4, (size) *s)
# fd = 2 (stderr)
# . . fd = 2 (stderr)
bb/copy-to-EBX 2/imm32
# x = s+4
# . . x = s+4
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
# . . size = *s
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
# . . syscall
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8
# . restore registers
@ -328,7 +328,7 @@ write-stderr: # s : (address array byte) -> <void>
5a/pop-to-EDX
59/pop-to-ECX
58/pop-to-EAX
# end
# . end
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return

View File

@ -1,4 +1,4 @@
## example showing mmap syscall
# Example showing mmap syscall.
# Create a new segment using mmap, save the address, write to it.
#
# To run (from the subx directory):
@ -16,7 +16,7 @@
b8/copy-to-EAX 0x5a/imm32/mmap
cd/syscall 0x80/imm8
# store to *EAX
# write to *EAX to check that we have access to the newly-allocated segment
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
# syscall(exit, EAX)

View File

@ -1,4 +1,4 @@
## add 1 and 1, and return the result in the exit code
# Add 1 and 1, and return the result in the exit code.
#
# To run (from the subx directory):
# $ subx translate examples/ex2.subx -o examples/ex2
@ -9,9 +9,11 @@
== code
# EBX = 1
bb/copy-to-EBX 1/imm32
# increment EBX
43/inc-EBX
# exit(EBX)
# syscall(exit, EBX)
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## add the first 10 numbers, and return the result in the exit code
# Add the first 10 numbers, and return the result in the exit code.
#
# To run (from the subx directory):
# $ subx translate examples/ex3.subx -o examples/ex3
@ -29,7 +29,7 @@ $loop:
eb/jump $loop/disp8
$exit:
# exit(EBX)
# syscall(exit, EBX)
b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## read a character from stdin, save it to a global, write it to stdout
# Read a character from stdin, save it to a global, write it to stdout.
#
# To run (from the subx directory):
# $ subx translate examples/ex4.subx -o examples/ex4
@ -7,24 +7,24 @@
== code
# syscall(read, stdin, X, 1)
# fd = 0 (stdin)
# . fd = 0 (stdin)
bb/copy-to-EBX 0/imm32
# initialize X (location to write result to)
# . data = X (location to write result to)
b9/copy-to-ECX X/imm32
# size = 1 character
# . size = 1 character
ba/copy-to-EDX 1/imm32
# syscall
# . syscall
b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8
# syscall(write, stdout, X, 1)
# fd = 1 (stdout)
# . fd = 1 (stdout)
bb/copy-to-EBX 1/imm32
# initialize X (location to read from)
# . initialize X (location to read from)
b9/copy-to-ECX X/imm32
# size = 1 character
# . size = 1 character
ba/copy-to-EDX 1/imm32
# syscall
# . syscall
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## read a character from stdin, save it to a local on the stack, write it to stdout
# Read a character from stdin, save it to a local on the stack, write it to stdout.
#
# To run (from the subx directory):
# $ subx translate examples/ex5.subx -o examples/ex5
@ -14,24 +14,24 @@
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # subtract from ESP
# syscall(read, stdin, x, 1)
# fd = 0 (stdin)
# . fd = 0 (stdin)
bb/copy-to-EBX 0/imm32
# initialize x (location to write result to)
# . 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
# . size = 1 character
ba/copy-to-EDX 1/imm32
# syscall
# . syscall
b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8
# syscall(write, stdout, x, 1)
# fd = 1 (stdout)
# . fd = 1 (stdout)
bb/copy-to-EBX 1/imm32
# initialize x (location to read from)
# . 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
# . size = 1 character
ba/copy-to-EDX 1/imm32
# syscall
# . syscall
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8

View File

@ -1,4 +1,4 @@
## print out a (global variable) string to stdout
# Print out a (global variable) string to stdout.
#
# To run (from the subx directory):
# $ subx translate examples/ex6.subx -o examples/ex6
@ -10,14 +10,14 @@
# . 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
# syscall(write, stdout, X, size)
# fd = 1 (stdout)
# syscall(write, stdout, X, Size)
# . fd = 1 (stdout)
bb/copy-to-EBX 1/imm32
# initialize X (location to write result to)
# . 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
# . initialize Size
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/EDX Size/disp32 . # copy *Size to EDX
# . syscall
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8

View File

@ -1,4 +1,5 @@
## example showing file syscalls
# 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.
@ -32,20 +33,20 @@
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
# syscall(write, Stream, "a", 1)
# load stream
# . 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
b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8
# syscall(close, Stream)
# load stream
# . load stream
bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
#
# .
b8/copy-to-EAX 6/imm32/close
cd/syscall 0x80/imm8
@ -55,22 +56,22 @@
ba/copy-to-EDX 0x180/imm32/fixed-perms
b8/copy-to-EAX 5/imm32/open
cd/syscall 0x80/imm8
# save Stream
# . save Stream
bb/copy-to-EBX Stream/imm32
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
# syscall(read, Stream, B, 1)
# load stream
# . 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
b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8
# syscall(close, Stream)
# load stream
# . load stream
bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
#
@ -83,7 +84,7 @@
cd/syscall 0x80/imm8
# syscall(exit, b)
# load b
# . load b
bb/copy-to-EBX B/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
#

View File

@ -1,4 +1,4 @@
## Example reading commandline arguments: compute length of first arg.
# Example reading commandline arguments: compute length of first arg.
#
# To run (from the subx directory):
# $ subx translate examples/ex8.subx -o examples/ex8
@ -21,7 +21,7 @@
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . . call ascii-length(argv[1])
# EAX = ascii-length(argv[1])
# . . push args
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
# . . call
@ -34,13 +34,13 @@
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8
ascii-length: # (s)
# initialize s (EDX)
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 = 0 (EAX)
# var result/EAX = 0
b8/copy-to-EAX 0/imm32
$ascii-length-loop:
# var c = *s (ECX)
# var c/ECX = *s
8a/copy 0/mod/* 2/rm32/EDX . . . 1/r32/ECX . . # copy byte at *EDX to lower byte of ECX
# if c == '\0' break
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX
@ -52,7 +52,7 @@ $ascii-length-loop:
# loop
eb/jump $ascii-length-loop/disp8
$ascii-length-ret:
# return (result in EAX)
# return EAX
c3/return
# . . vim:nowrap:textwidth=0

View File

@ -1,4 +1,5 @@
## Example showing arg order on the stack.
# Example showing arg order on the stack.
#
# Show difference between ascii codes of first letter of first arg and first
# letter of second arg.
#
@ -23,16 +24,16 @@
# . prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . . call ascii-difference(argv[1], argv[2])
# push argv[2]
# ascii-difference(argv[1], argv[2])
# . . push argv[2]
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push argv[1]
# . . push argv[1]
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/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)
# syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8