4801
Reindent all SubX code to make some room for the new comment style.
This commit is contained in:
parent
e9661581f0
commit
6030d7e2e5
|
@ -1,45 +1,45 @@
|
|||
# _write: write to a file descriptor
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
# syscall(exit, 0) -- can't test _write just yet
|
||||
bb/copy-to-EBX 0/imm32
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(exit, 0) -- can't test _write just yet
|
||||
bb/copy-to-EBX 0/imm32
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
_write: # fd : int, s : (address array byte) -> <void>
|
||||
# prolog
|
||||
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, fd, (data) s+4, (size) *s)
|
||||
# prolog
|
||||
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, fd, (data) s+4, (size) *s)
|
||||
# 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
|
||||
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+4
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX
|
||||
81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX
|
||||
81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
|
||||
# size : EDX = *s
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# syscall
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -1,85 +1,85 @@
|
|||
# Rudimentary test harness
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main: (manual test if this is the last file loaded)
|
||||
# check-ints-equal(34, 34)
|
||||
68/push "error in check-ints-equal"/imm32
|
||||
68/push 34/imm32
|
||||
68/push 34/imm32
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
cd/syscall 0x80/imm8
|
||||
# check-ints-equal(34, 34)
|
||||
68/push "error in check-ints-equal"/imm32
|
||||
68/push 34/imm32
|
||||
68/push 34/imm32
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# print msg to stderr if a != b, otherwise print "."
|
||||
check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
|
||||
# prolog
|
||||
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 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
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
|
||||
75/jump-if-unequal $check-ints-equal:else/disp8
|
||||
# prolog
|
||||
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 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
|
||||
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, '.')
|
||||
# push args
|
||||
68/push "."/imm32
|
||||
68/push 2/imm32/stderr
|
||||
68/push "."/imm32
|
||||
68/push 2/imm32/stderr
|
||||
# call
|
||||
e8/call _write/disp32
|
||||
e8/call _write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# return
|
||||
eb/jump $check-ints-equal:end/disp8
|
||||
# else:
|
||||
eb/jump $check-ints-equal:end/disp8
|
||||
# else:
|
||||
$check-ints-equal:else:
|
||||
# _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
|
||||
68/push 2/imm32/stderr
|
||||
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
|
||||
68/push 2/imm32/stderr
|
||||
# call
|
||||
e8/call _write/disp32
|
||||
e8/call _write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# _write(2/stderr, Newline)
|
||||
# push args
|
||||
68/push Newline/imm32
|
||||
68/push 2/imm32/stderr
|
||||
68/push Newline/imm32
|
||||
68/push 2/imm32/stderr
|
||||
# call
|
||||
e8/call _write/disp32
|
||||
e8/call _write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# increment Num-test-failures
|
||||
ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Num-test-failures/disp32 # increment *Num-test-failures
|
||||
ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Num-test-failures/disp32 # increment *Num-test-failures
|
||||
$check-ints-equal:end:
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
Newline:
|
||||
# size
|
||||
01 00 00 00
|
||||
# data
|
||||
0a/newline
|
||||
# size
|
||||
01 00 00 00
|
||||
# data
|
||||
0a/newline
|
||||
|
||||
Num-test-failures:
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -15,247 +15,247 @@
|
|||
# would cause tests to not run, rather than to fail as we'd like.)
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# 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)
|
||||
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
|
||||
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)
|
||||
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
|
||||
|
||||
# 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
|
||||
# prolog
|
||||
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
|
||||
# prolog
|
||||
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
|
||||
|
||||
# pseudocode:
|
||||
# initialize n = b.length
|
||||
# initialize s1 = s
|
||||
# initialize s2 = b.data
|
||||
# i = 0
|
||||
# for (i = 0; i < n; ++n)
|
||||
# c1 = *s1
|
||||
# c2 = *s2
|
||||
# if c1 == 0
|
||||
# return false
|
||||
# if c1 != c2
|
||||
# return false
|
||||
# return *s1 == 0
|
||||
#
|
||||
# initialize s into EDI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# initialize benchmark length n into EDX
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize benchmark data into ESI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize loop counter i into ECX
|
||||
b9/copy-to-ECX 0/imm32/exit
|
||||
# while (i/ECX < n/EDX)
|
||||
# pseudocode:
|
||||
# initialize n = b.length
|
||||
# initialize s1 = s
|
||||
# initialize s2 = b.data
|
||||
# i = 0
|
||||
# for (i = 0; i < n; ++n)
|
||||
# c1 = *s1
|
||||
# c2 = *s2
|
||||
# if c1 == 0
|
||||
# return false
|
||||
# if c1 != c2
|
||||
# return false
|
||||
# return *s1 == 0
|
||||
#
|
||||
# initialize s into EDI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# initialize benchmark length n into EDX
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize benchmark data into ESI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize loop counter i into ECX
|
||||
b9/copy-to-ECX 0/imm32/exit
|
||||
# while (i/ECX < n/EDX)
|
||||
$kernel-string-equal:loop:
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
74/jump-if-equal $kernel-string-equal:break/disp8
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
74/jump-if-equal $kernel-string-equal:break/disp8
|
||||
# c1/EAX, c2/EBX = *s, *benchmark
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX
|
||||
# if (c1 == 0) return false
|
||||
3d/compare-EAX 0/imm32
|
||||
74/jump-if-equal $kernel-string-equal:false/disp8
|
||||
3d/compare-EAX 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 with EBX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
# ++s1, ++s2, ++i
|
||||
41/inc-ECX
|
||||
46/inc-ESI
|
||||
47/inc-EDI
|
||||
# end while
|
||||
eb/jump $kernel-string-equal:loop/disp8
|
||||
41/inc-ECX
|
||||
46/inc-ESI
|
||||
47/inc-EDI
|
||||
# end while
|
||||
eb/jump $kernel-string-equal:loop/disp8
|
||||
$kernel-string-equal:break:
|
||||
# if (*s/EDI == 0) return true
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
3d/compare-EAX 0/imm32
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
# if (*s/EDI == 0) return true
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
3d/compare-EAX 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
|
||||
# return false
|
||||
b8/copy-to-EAX 1/imm32
|
||||
eb/jump $kernel-string-equal:end/disp8
|
||||
# return false
|
||||
$kernel-string-equal:false:
|
||||
b8/copy-to-EAX 0/imm32
|
||||
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
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
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, "")
|
||||
# EAX = kernel-string-equal(Null-kernel-string, "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
68/push ""/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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")
|
||||
# EAX = kernel-string-equal(Null-kernel-string, "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Abc")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Adc")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Adc")
|
||||
# push args
|
||||
68/push "Adc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Adc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push ""/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Ab")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Abcd")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Abcd")
|
||||
# push args
|
||||
68/push "Abcd"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Abcd"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-longer-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
Null-kernel-string:
|
||||
00/null
|
||||
00/null
|
||||
Abc-kernel-string:
|
||||
41/A 62/b 63/c 00/null
|
||||
41/A 62/b 63/c 00/null
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
# Create a new segment (for data) using mmap().
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main: (manual test if this is the last file loaded)
|
||||
# EAX = new-segment(0x1000)
|
||||
# EAX = new-segment(0x1000)
|
||||
# push args
|
||||
68/push 0x1000/imm32
|
||||
68/push 0x1000/imm32
|
||||
# call
|
||||
e8/call new-segment/disp32
|
||||
e8/call new-segment/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
|
||||
# store to *EAX
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
|
||||
# store to *EAX
|
||||
c7/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
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# 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
|
||||
|
||||
new-segment: # len : int -> address
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
53/push-EBX
|
||||
# copy len to mmap-new-segment.len
|
||||
# TODO: compute mmap-new-segment+4 before runtime
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
bb/copy-to-EBX mmap-new-segment/imm32
|
||||
89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4)
|
||||
# mmap(mmap-new-segment)
|
||||
bb/copy-to-EBX mmap-new-segment/imm32
|
||||
b8/copy-to-EAX 0x5a/imm32/mmap
|
||||
cd/syscall 0x80/imm8
|
||||
# epilog
|
||||
5b/pop-to-EBX
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
53/push-EBX
|
||||
# copy len to mmap-new-segment.len
|
||||
# TODO: compute mmap-new-segment+4 before runtime
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
bb/copy-to-EBX mmap-new-segment/imm32
|
||||
89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4)
|
||||
# mmap(mmap-new-segment)
|
||||
bb/copy-to-EBX mmap-new-segment/imm32
|
||||
b8/copy-to-EAX 0x5a/imm32/mmap
|
||||
cd/syscall 0x80/imm8
|
||||
# epilog
|
||||
5b/pop-to-EBX
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
== 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
|
||||
00 00 00 00 # null
|
||||
# len
|
||||
00 00 00 00 # 0x1000
|
||||
# protection flags
|
||||
03 00 00 00 # PROT_READ | PROT_WRITE
|
||||
# sharing flags
|
||||
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
|
||||
# fd
|
||||
ff ff ff ff # -1 since MAP_ANONYMOUS is specified
|
||||
# offset
|
||||
00 00 00 00 # 0 since MAP_ANONYMOUS is specified
|
||||
# addr
|
||||
00 00 00 00 # null
|
||||
# len
|
||||
00 00 00 00 # 0x1000
|
||||
# protection flags
|
||||
03 00 00 00 # PROT_READ | PROT_WRITE
|
||||
# sharing flags
|
||||
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
|
||||
# fd
|
||||
ff ff ff ff # -1 since MAP_ANONYMOUS is specified
|
||||
# offset
|
||||
00 00 00 00 # 0 since MAP_ANONYMOUS is specified
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -1,169 +1,169 @@
|
|||
# Comparing 'regular' length-prefixed strings.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# 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)
|
||||
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
|
||||
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)
|
||||
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
|
||||
|
||||
string-equal: # s : string, benchmark : string -> EAX : boolean
|
||||
# prolog
|
||||
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
|
||||
# pseudocode:
|
||||
# if s.length != b.length return false
|
||||
# for i = 0; i < s.length; ++i
|
||||
# if s[i] != b[i] return false
|
||||
# return true
|
||||
# registers:
|
||||
# i: ECX
|
||||
# s.length: EDX
|
||||
# b.length: EBX
|
||||
# b[i]: EBX
|
||||
# s[i]: EAX
|
||||
#
|
||||
# var s/EAX : (address array byte)
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# var benchmark/EBX : (address array byte)
|
||||
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 s.length != b.length return false
|
||||
# prolog
|
||||
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
|
||||
# pseudocode:
|
||||
# if s.length != b.length return false
|
||||
# for i = 0; i < s.length; ++i
|
||||
# if s[i] != b[i] return false
|
||||
# return true
|
||||
# registers:
|
||||
# i: ECX
|
||||
# s.length: EDX
|
||||
# b.length: EBX
|
||||
# b[i]: EBX
|
||||
# s[i]: EAX
|
||||
#
|
||||
# var s/EAX : (address array byte)
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# var benchmark/EBX : (address array byte)
|
||||
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 s.length != b.length return false
|
||||
# EDX = s.length
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX
|
||||
# compare s.length and b.length
|
||||
39/compare 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # compare *EBX with EDX
|
||||
75/jump-if-not-equal $string-equal:false/disp8
|
||||
39/compare 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # compare *EBX with EDX
|
||||
75/jump-if-not-equal $string-equal:false/disp8
|
||||
$string-equal:lengths:
|
||||
# var i/ECX : int = 0
|
||||
b9/copy-to-ECX 0/imm32
|
||||
# EBX = &b[i]
|
||||
43/inc-EBX
|
||||
# EAX = &s[i]
|
||||
40/inc-EAX
|
||||
# var i/ECX : int = 0
|
||||
b9/copy-to-ECX 0/imm32
|
||||
# EBX = &b[i]
|
||||
43/inc-EBX
|
||||
# EAX = &s[i]
|
||||
40/inc-EAX
|
||||
$string-equal:loop:
|
||||
# if i >= s.length return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $string-equal:true/disp8
|
||||
# if b[i] != s[i] return false
|
||||
# if i >= s.length return true
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
7d/jump-if-greater-or-equal $string-equal:true/disp8
|
||||
# if b[i] != s[i] return false
|
||||
# ESI = s[i]
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy *EAX to ESI
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy *EAX to ESI
|
||||
# compare b[i] with ESI
|
||||
39/compare 0/mod/indirect 3/rm32/EBX . . . 6/r32/ESI . . # compare *EBX with ESI
|
||||
75/jump-if-not-equal $string-equal:false/disp8
|
||||
# ++i
|
||||
41/inc-ECX
|
||||
40/inc-EAX
|
||||
43/inc-EBX
|
||||
# loop
|
||||
eb/jump $string-equal:loop/disp8
|
||||
39/compare 0/mod/indirect 3/rm32/EBX . . . 6/r32/ESI . . # compare *EBX with ESI
|
||||
75/jump-if-not-equal $string-equal:false/disp8
|
||||
# ++i
|
||||
41/inc-ECX
|
||||
40/inc-EAX
|
||||
43/inc-EBX
|
||||
# loop
|
||||
eb/jump $string-equal:loop/disp8
|
||||
$string-equal:true:
|
||||
# return true
|
||||
b8/copy-to-EAX 1/imm32
|
||||
eb/jump $string-equal:end/disp8
|
||||
# return true
|
||||
b8/copy-to-EAX 1/imm32
|
||||
eb/jump $string-equal:end/disp8
|
||||
$string-equal:false:
|
||||
# return false
|
||||
b8/copy-to-EAX 0/imm32
|
||||
# return false
|
||||
b8/copy-to-EAX 0/imm32
|
||||
$string-equal:end:
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
## tests
|
||||
|
||||
test-compare-empty-with-empty-string:
|
||||
# EAX = string-equal("", "")
|
||||
# EAX = string-equal("", "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push ""/imm32
|
||||
68/push ""/imm32
|
||||
68/push ""/imm32
|
||||
# call
|
||||
e8/call string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 1, msg)
|
||||
# push args
|
||||
68/push "F - test-compare-empty-with-empty-string"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
68/push "F - test-compare-empty-with-empty-string"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-compare-empty-with-non-empty-string: # also checks length-mismatch code path
|
||||
# EAX = string-equal("", "Abc")
|
||||
# EAX = string-equal("", "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push ""/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push ""/imm32
|
||||
# call
|
||||
e8/call string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0, msg)
|
||||
# push args
|
||||
68/push "F - test-compare-empty-with-non-empty-string"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
68/push "F - test-compare-empty-with-non-empty-string"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-compare-equal-strings:
|
||||
# EAX = string-equal("Abc", "Abc")
|
||||
# EAX = string-equal("Abc", "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
# call
|
||||
e8/call string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 1, msg)
|
||||
# push args
|
||||
68/push "F - test-compare-equal-strings"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
68/push "F - test-compare-equal-strings"/imm32
|
||||
68/push 1/imm32/true
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
test-compare-inequal-strings-equal-lengths:
|
||||
# EAX = string-equal("Abc", "Adc")
|
||||
# EAX = string-equal("Abc", "Adc")
|
||||
# push args
|
||||
68/push "Adc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push "Adc"/imm32
|
||||
68/push "Abc"/imm32
|
||||
# call
|
||||
e8/call string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0, msg)
|
||||
# push args
|
||||
68/push "F - test-compare-inequal-strings-equal-lengths"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
68/push "F - test-compare-inequal-strings-equal-lengths"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
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
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -23,337 +23,337 @@
|
|||
|
||||
# We'll save the address of the trace segment here.
|
||||
Trace-stream:
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
|
||||
# Fake trace-stream for tests.
|
||||
# Also illustrates the layout of the real trace-stream (segment).
|
||||
_test-trace-stream:
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream.
|
||||
# The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
|
||||
initialize-trace-stream:
|
||||
# EAX = new-segment(0x1000)
|
||||
# EAX = new-segment(0x1000)
|
||||
# push args
|
||||
68/push 0x1000/imm32/N
|
||||
68/push 0x1000/imm32/N
|
||||
# call
|
||||
e8/call new-segment/disp32
|
||||
e8/call new-segment/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# copy EAX to *Trace-stream
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# Trace-stream.length = 0x1000/N - 12
|
||||
c7 0/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8)
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# copy EAX to *Trace-stream
|
||||
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream
|
||||
# Trace-stream.length = 0x1000/N - 12
|
||||
c7 0/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8)
|
||||
c3/return
|
||||
|
||||
# Append a string to the given trace stream.
|
||||
# Silently give up if it's already full. Or truncate the string if there isn't enough room.
|
||||
trace: # t : (address trace-stream), line : string
|
||||
# prolog
|
||||
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
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# EDI = t
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# ESI = line
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# ECX = t->write
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX
|
||||
# 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)
|
||||
# prolog
|
||||
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
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# EDI = t
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# ESI = line
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# ECX = t->write
|
||||
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX
|
||||
# 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
|
||||
56/push-ESI
|
||||
56/push-ESI
|
||||
# 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
|
||||
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]
|
||||
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
|
||||
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
|
||||
e8/call _append-3/disp32
|
||||
e8/call _append-3/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# if EAX == 0 return
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EDX
|
||||
74/jump-if-equal $trace:end/disp8
|
||||
# t->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
# 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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# if EAX == 0 return
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EDX
|
||||
74/jump-if-equal $trace:end/disp8
|
||||
# t->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
# 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
|
||||
68/push Newline/imm32
|
||||
68/push Newline/imm32
|
||||
# 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
|
||||
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]
|
||||
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
|
||||
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
|
||||
e8/call _append-3/disp32
|
||||
e8/call _append-3/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# t->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# t->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
$trace:end:
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
clear-trace-stream: # t : (address trace-stream)
|
||||
# prolog
|
||||
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
|
||||
# EAX = t
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# ECX = t->length
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||
# ECX = &t->data[t->length]
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EAX+ECX+12 to ECX
|
||||
# t->write = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# t->read = 0
|
||||
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
|
||||
# EAX = t->data
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
|
||||
# while (true)
|
||||
# prolog
|
||||
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
|
||||
# EAX = t
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# ECX = t->length
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||
# ECX = &t->data[t->length]
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EAX+ECX+12 to ECX
|
||||
# t->write = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# t->read = 0
|
||||
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
|
||||
# EAX = t->data
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
|
||||
# while (true)
|
||||
$clear-trace-stream:loop:
|
||||
# if EAX >= ECX break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-trace-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# EAX += 4
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
||||
eb/jump $clear-trace-stream:loop/disp8
|
||||
# if EAX >= ECX break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-trace-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# EAX += 4
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
||||
eb/jump $clear-trace-stream:loop/disp8
|
||||
$clear-trace-stream:end:
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
## tests
|
||||
|
||||
test-trace-single:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# push args
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call clear-trace-stream/disp32
|
||||
e8/call clear-trace-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "Ab")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call trace/disp32
|
||||
e8/call trace/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 41/A 62/b 0a/newline 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 41/A 62/b 0a/newline 00, msg)
|
||||
# push args
|
||||
68/push "F - test-trace-single"/imm32
|
||||
68/push 0x0a6241/imm32/Ab-newline
|
||||
68/push "F - test-trace-single"/imm32
|
||||
68/push 0x0a6241/imm32/Ab-newline
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-appends:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# push args
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call clear-trace-stream/disp32
|
||||
e8/call clear-trace-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "C")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "C")
|
||||
# push args
|
||||
68/push "C"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push "C"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call trace/disp32
|
||||
e8/call trace/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "D")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "D")
|
||||
# push args
|
||||
68/push "D"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push "D"/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call trace/disp32
|
||||
e8/call trace/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 43/C 0a/newline 44/D 0a/newline, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 43/C 0a/newline 44/D 0a/newline, msg)
|
||||
# push args
|
||||
68/push "F - test-trace-appends"/imm32
|
||||
68/push 0x0a440a43/imm32/C-newline-D-newline
|
||||
68/push "F - test-trace-appends"/imm32
|
||||
68/push 0x0a440a43/imm32/C-newline-D-newline
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-trace-empty-line:
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# clear-trace-stream(_test-trace-stream)
|
||||
# push args
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call clear-trace-stream/disp32
|
||||
e8/call clear-trace-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# trace(_test-trace-stream, "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-trace-stream/imm32
|
||||
# call
|
||||
e8/call trace/disp32
|
||||
e8/call trace/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 0, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-trace-stream.data, 0, msg)
|
||||
# push args
|
||||
68/push "F - test-trace-empty-line"/imm32
|
||||
68/push 0/imm32
|
||||
68/push "F - test-trace-empty-line"/imm32
|
||||
68/push 0/imm32
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-trace-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
## helpers
|
||||
|
||||
# 3-argument variant of _append
|
||||
_append-3: # out : address, outend : address, s : (array byte) -> num_bytes_appended/EAX
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# save registers
|
||||
51/push-ECX
|
||||
# _append-4(out, outend, &s.data[0], &s.data[s.length]) -> num_bytes_appended/EAX
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# 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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX
|
||||
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
|
||||
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
|
||||
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]
|
||||
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX
|
||||
51/push-ECX
|
||||
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX
|
||||
51/push-ECX
|
||||
# push outend
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
# push out
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
|
||||
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
|
||||
e8/call _append-4/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# 4-argument variant of _append
|
||||
_append-4: # out : address, outend : address, in : address, inend : address -> num_bytes_appended/EAX
|
||||
# prolog
|
||||
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
|
||||
# EAX/num_bytes_appended = 0
|
||||
b8/copy-to-EAX 0/imm32
|
||||
# EDI = out
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 0x8/disp8 . # copy *(EBP+8) to EDI
|
||||
# EDX = outend
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX
|
||||
# ESI = in
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0x10/disp8 . # copy *(EBP+16) to ESI
|
||||
# ECX = inend
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX
|
||||
# prolog
|
||||
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
|
||||
# EAX/num_bytes_appended = 0
|
||||
b8/copy-to-EAX 0/imm32
|
||||
# EDI = out
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 0x8/disp8 . # copy *(EBP+8) to EDI
|
||||
# EDX = outend
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX
|
||||
# ESI = in
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0x10/disp8 . # copy *(EBP+16) to ESI
|
||||
# ECX = inend
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX
|
||||
$_append-4:loop:
|
||||
# if ESI/src >= ECX/srcend break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
7d/jump-if-greater-or-equal $_append-4:end/disp8
|
||||
# if EDI/out >= EDX/outend break (for now silently ignore filled up buffer)
|
||||
39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI with EDX
|
||||
7d/jump-if-greater-or-equal $_append-4:end/disp8
|
||||
# copy one byte from ESI/src to EDI/out
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 3/r32/BL . . # copy byte at *ESI to BL
|
||||
88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI
|
||||
# updates
|
||||
40/increment-EAX
|
||||
46/increment-ESI
|
||||
47/increment-EDI
|
||||
eb/jump $_append-4:loop/disp8
|
||||
# if ESI/src >= ECX/srcend break
|
||||
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX
|
||||
7d/jump-if-greater-or-equal $_append-4:end/disp8
|
||||
# if EDI/out >= EDX/outend break (for now silently ignore filled up buffer)
|
||||
39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI with EDX
|
||||
7d/jump-if-greater-or-equal $_append-4:end/disp8
|
||||
# copy one byte from ESI/src to EDI/out
|
||||
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 3/r32/BL . . # copy byte at *ESI to BL
|
||||
88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI
|
||||
# updates
|
||||
40/increment-EAX
|
||||
46/increment-ESI
|
||||
47/increment-EDI
|
||||
eb/jump $_append-4:loop/disp8
|
||||
$_append-4:end:
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -16,197 +16,197 @@
|
|||
# data: (array byte) # prefixed by length as usual
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
write: # f : fd or (address stream), s : (address array byte) -> bytes_written/EAX
|
||||
# (If we ever leave the Linux kernel behind, it may be better to return
|
||||
# the number of bytes *not* written. Success would then be signaled by
|
||||
# returning 0.)
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (f < 0x08000000) _write(f, s), return # 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 $write:fake/disp8
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (f < 0x08000000) _write(f, s), return # 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 $write:fake/disp8
|
||||
# push args
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
# call
|
||||
e8/call _write/disp32
|
||||
e8/call _write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
eb/jump $write:end/disp8
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
eb/jump $write:end/disp8
|
||||
$write:fake:
|
||||
# otherwise, treat 'f' as a stream to append to
|
||||
# save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
# ECX = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
# EDX = f->write
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
|
||||
# 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)
|
||||
# otherwise, treat 'f' as a stream to append to
|
||||
# save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
# ECX = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
# EDX = f->write
|
||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
|
||||
# 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
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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
|
||||
e8/call _append-3/disp32
|
||||
e8/call _append-3/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# f->write += EAX
|
||||
01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# f->write += EAX
|
||||
01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX
|
||||
# restore registers
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
$write:end:
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
clear-stream: # f : (address stream) -> <void>
|
||||
# prolog
|
||||
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
|
||||
# EAX = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# ECX = f->length
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||
# ECX = &f->data[f->length]
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EAX+ECX+12 to ECX
|
||||
# f->write = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# f->read = 0
|
||||
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
|
||||
# EAX = f->data
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
|
||||
# while (true)
|
||||
# prolog
|
||||
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
|
||||
# EAX = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||
# ECX = f->length
|
||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||
# ECX = &f->data[f->length]
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EAX+ECX+12 to ECX
|
||||
# f->write = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# f->read = 0
|
||||
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
|
||||
# EAX = f->data
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
|
||||
# while (true)
|
||||
$clear-stream:loop:
|
||||
# if EAX >= ECX break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# EAX += 4
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
||||
eb/jump $clear-stream:loop/disp8
|
||||
# if EAX >= ECX break
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||
7d/jump-if-greater-or-equal $clear-stream:end/disp8
|
||||
# *EAX = 0
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||
# EAX += 4
|
||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
||||
eb/jump $clear-stream:loop/disp8
|
||||
$clear-stream:end:
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-write-single:
|
||||
# clear-stream(_test-stream)
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 2)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 2)
|
||||
# push args
|
||||
68/push "F - test-read-single: return EAX"/imm32
|
||||
68/push 2/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-single: return EAX"/imm32
|
||||
68/push 2/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream->data, 41/A 62/b 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream->data, 41/A 62/b 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-write-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
68/push "F - test-write-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-write-appends:
|
||||
# clear-stream(_test-stream)
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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, "C")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "C")
|
||||
# push args
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write(_test-stream, "D")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write(_test-stream, "D")
|
||||
# push args
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-write-appends"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
68/push "F - test-write-appends"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-stream:
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -33,177 +33,177 @@
|
|||
# Its value is its output, computed during stop and available to the test.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
#? e8/call test-stop-skips-returns-on-exit/disp32
|
||||
# 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
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
#? e8/call test-stop-skips-returns-on-exit/disp32
|
||||
# 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
|
||||
|
||||
# Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to
|
||||
# the stack.
|
||||
# Ugly that we need to know the size of args, but so it goes.
|
||||
tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void>
|
||||
# prolog
|
||||
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
|
||||
# EAX = nbytes
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX
|
||||
# Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor.
|
||||
# The return address for a call in the caller's body will be at:
|
||||
# X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address)
|
||||
# X-12 if the caller takes 8 bytes of args
|
||||
# ..and so on
|
||||
# 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
|
||||
# bytes for the return address and 4 bytes to push EBP above.
|
||||
# So EBP at this point is X-16.
|
||||
#
|
||||
# So the return address for the next call in the caller is:
|
||||
# EBP+8 if the caller takes 4 bytes of args
|
||||
# EBP+4 if the caller takes 8 bytes of args
|
||||
# EBP if the caller takes 12 bytes of args
|
||||
# EBP-4 if the caller takes 16 bytes of args
|
||||
# ..and so on
|
||||
# That's EBP+12-nbytes.
|
||||
# prolog
|
||||
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
|
||||
# EAX = nbytes
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX
|
||||
# Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor.
|
||||
# The return address for a call in the caller's body will be at:
|
||||
# X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address)
|
||||
# X-12 if the caller takes 8 bytes of args
|
||||
# ..and so on
|
||||
# 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
|
||||
# bytes for the return address and 4 bytes to push EBP above.
|
||||
# So EBP at this point is X-16.
|
||||
#
|
||||
# So the return address for the next call in the caller is:
|
||||
# EBP+8 if the caller takes 4 bytes of args
|
||||
# EBP+4 if the caller takes 8 bytes of args
|
||||
# EBP if the caller takes 12 bytes of args
|
||||
# EBP-4 if the caller takes 16 bytes of args
|
||||
# ..and so on
|
||||
# That's EBP+12-nbytes.
|
||||
# option 1: 6 + 3 bytes
|
||||
#? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX
|
||||
#? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX
|
||||
#? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX
|
||||
#? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX
|
||||
# option 2: 2 + 4 bytes
|
||||
f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX
|
||||
# copy EAX to ed->target
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX
|
||||
# initialize ed->value
|
||||
c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4)
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX
|
||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX
|
||||
# copy EAX to ed->target
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
|
||||
89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX
|
||||
# initialize ed->value
|
||||
c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4)
|
||||
# restore registers
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
stop: # ed : (address exit-descriptor), value : int
|
||||
# no prolog; one way or another, we're going to clobber registers
|
||||
# EAX = ed
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX
|
||||
# exit(value) if ed->target == 0
|
||||
81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX
|
||||
75/jump-if-not-equal $stop:fake/disp8
|
||||
# syscall(exit, value)
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
# no prolog; one way or another, we're going to clobber registers
|
||||
# EAX = ed
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX
|
||||
# exit(value) if ed->target == 0
|
||||
81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX
|
||||
75/jump-if-not-equal $stop:fake/disp8
|
||||
# syscall(exit, value)
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
$stop:fake:
|
||||
# ed->value = value+1
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX
|
||||
41/inc-ECX
|
||||
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4)
|
||||
# non-local jump to ed->target
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP
|
||||
c3/return # doesn't return to caller
|
||||
# ed->value = value+1
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX
|
||||
41/inc-ECX
|
||||
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4)
|
||||
# non-local jump to ed->target
|
||||
8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP
|
||||
c3/return # doesn't return to caller
|
||||
|
||||
test-stop-skips-returns-on-exit:
|
||||
# This looks like the standard prolog, but is here for different reasons.
|
||||
# A function calling 'stop' can't rely on EBP persisting past the call.
|
||||
#
|
||||
# Use EBP here as a stable base to refer to locals and arguments from in the
|
||||
# presence of push/pop/call instructions.
|
||||
# *Don't* use EBP as a way to restore ESP.
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# Make room for an exit descriptor on the stack. That's almost always the
|
||||
# right place for it, available only as long as it's legal to use. Once this
|
||||
# containing function returns we'll need a new exit descriptor.
|
||||
# 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 precisely for the next call below, to _test-stop-1.
|
||||
# tailor-exit-descriptor(ed, 4)
|
||||
# This looks like the standard prolog, but is here for different reasons.
|
||||
# A function calling 'stop' can't rely on EBP persisting past the call.
|
||||
#
|
||||
# Use EBP here as a stable base to refer to locals and arguments from in the
|
||||
# presence of push/pop/call instructions.
|
||||
# *Don't* use EBP as a way to restore ESP.
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# Make room for an exit descriptor on the stack. That's almost always the
|
||||
# right place for it, available only as long as it's legal to use. Once this
|
||||
# containing function returns we'll need a new exit descriptor.
|
||||
# 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 precisely for the next call below, to _test-stop-1.
|
||||
# tailor-exit-descriptor(ed, 4)
|
||||
# push args
|
||||
68/push 4/imm32/nbytes-of-args-for-_test-stop-1
|
||||
50/push-EAX
|
||||
68/push 4/imm32/nbytes-of-args-for-_test-stop-1
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call tailor-exit-descriptor/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call _test-stop-1(ed)
|
||||
# push args
|
||||
50/push-EAX
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call _test-stop-1/disp32
|
||||
## registers except ESP may be clobbered at this point
|
||||
e8/call _test-stop-1/disp32
|
||||
## 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)
|
||||
# check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
|
||||
58/pop-to-EAX
|
||||
# check that _test-stop-1 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-stop-skips-returns-on-exit"/imm32
|
||||
68/push 2/imm32
|
||||
68/push "F - test-stop-skips-returns-on-exit"/imm32
|
||||
68/push 2/imm32
|
||||
# push ed->value
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# epilog
|
||||
5d/pop-to-EBP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# epilog
|
||||
5d/pop-to-EBP
|
||||
# don't restore ESP from EBP; manually reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
c3/return
|
||||
|
||||
_test-stop-1: # ed : (address exit-descriptor)
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# _test-stop-2(ed)
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# _test-stop-2(ed)
|
||||
# push args
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
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
|
||||
e8/call _test-stop-2/disp32
|
||||
## 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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# signal test failed: check-ints-equal(1, 0, msg)
|
||||
# push args
|
||||
68/push "F - test-stop-skips-returns-on-exit"/imm32
|
||||
68/push 0/imm32
|
||||
68/push 1/imm32
|
||||
68/push "F - test-stop-skips-returns-on-exit"/imm32
|
||||
68/push 0/imm32
|
||||
68/push 1/imm32
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
_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)
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# call 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)
|
||||
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
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
e8/call stop/disp32
|
||||
## 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
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -41,76 +41,76 @@
|
|||
# data: (array byte) # prefixed by length as usual
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
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
|
||||
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
|
||||
# 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
|
||||
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
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
# call
|
||||
e8/call _read/disp32
|
||||
e8/call _read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# return
|
||||
eb/jump $read:end/disp8
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# return
|
||||
eb/jump $read:end/disp8
|
||||
$read:fake:
|
||||
## otherwise, treat 'f' as a stream to scan from
|
||||
# save registers
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# 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 ESI
|
||||
# EAX = _append-4(out = &s->data[s->write], outend = &s->data[s->length],
|
||||
# in = &f->data[f->read], inend = &f->data[f->write])
|
||||
## otherwise, treat 'f' as a stream to scan from
|
||||
# save registers
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# 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 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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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
|
||||
# call
|
||||
e8/call _append-4/disp32
|
||||
e8/call _append-4/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# s->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
# f.read += EAX
|
||||
01/add 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # add EAX to *(ESI+4)
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# s->write += EAX
|
||||
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
|
||||
# f.read += EAX
|
||||
01/add 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # add EAX to *(ESI+4)
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
$read:end:
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
## helpers
|
||||
|
||||
|
@ -119,245 +119,245 @@ $read:end:
|
|||
# Maybe a better helper would be 'empty-stream?'
|
||||
|
||||
_read: # fd : int, 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
|
||||
# save registers
|
||||
51/push-ECX
|
||||
52/push-EDX
|
||||
53/push-EBX
|
||||
56/push-ESI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# EAX = s->write
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to 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)
|
||||
# prolog
|
||||
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
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# EAX = s->write
|
||||
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to 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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to 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]
|
||||
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
|
||||
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
|
||||
29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX
|
||||
29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX
|
||||
# syscall
|
||||
b8/copy-to-EAX 3/imm32/read
|
||||
cd/syscall 0x80/imm8
|
||||
# add the result EAX to s->write
|
||||
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
b8/copy-to-EAX 3/imm32/read
|
||||
cd/syscall 0x80/imm8
|
||||
# add the result EAX to s->write
|
||||
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# Two options:
|
||||
# 1 (what we have above):
|
||||
# ECX = s
|
||||
# EAX = s->write
|
||||
# EDX = s->length
|
||||
# # syscall
|
||||
# ECX = lea ECX+EAX+12
|
||||
# EDX = sub EDX EAX
|
||||
#
|
||||
# 2:
|
||||
# ECX = s
|
||||
# EDX = s->length
|
||||
# ECX = &s->data
|
||||
# # syscall
|
||||
# ECX = add ECX, s->write
|
||||
# EDX = sub EDX, s->write
|
||||
#
|
||||
# Not much to choose between the two? Option 2 performs a duplicate load to
|
||||
# use one less register, but doesn't increase the amount of spilling (ECX
|
||||
# and EDX must be used, and EAX must be clobbered anyway).
|
||||
# Two options:
|
||||
# 1 (what we have above):
|
||||
# ECX = s
|
||||
# EAX = s->write
|
||||
# EDX = s->length
|
||||
# # syscall
|
||||
# ECX = lea ECX+EAX+12
|
||||
# EDX = sub EDX EAX
|
||||
#
|
||||
# 2:
|
||||
# ECX = s
|
||||
# EDX = s->length
|
||||
# ECX = &s->data
|
||||
# # syscall
|
||||
# ECX = add ECX, s->write
|
||||
# EDX = sub EDX, s->write
|
||||
#
|
||||
# Not much to choose between the two? Option 2 performs a duplicate load to
|
||||
# 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
|
||||
|
||||
test-read-single:
|
||||
# clear-stream(_test-stream)
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call read/disp32
|
||||
e8/call read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 2)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 2)
|
||||
# push args
|
||||
68/push "F - test-read-single: return EAX"/imm32
|
||||
68/push 2/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-single: return EAX"/imm32
|
||||
68/push 2/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream-buffer->data, 41/A 62/b 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream-buffer->data, 41/A 62/b 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-read-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
68/push "F - test-read-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream-buffer/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-read-is-stateful:
|
||||
## make two consecutive reads, check that their results are appended
|
||||
# clear-stream(_test-stream)
|
||||
## make two consecutive reads, check that their results are appended
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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, "C")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "C")
|
||||
# push args
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call read/disp32
|
||||
e8/call read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write(_test-stream, "D")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write(_test-stream, "D")
|
||||
# push args
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call read/disp32
|
||||
e8/call read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream-buffer->data, 43/C 44/D 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream-buffer->data, 43/C 44/D 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-read-is-stateful"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
68/push "F - test-read-is-stateful"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream-buffer/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
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
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
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)
|
||||
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)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call read/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
## second read
|
||||
# read(_test-stream, _test-stream-buffer)
|
||||
# push args
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream-buffer/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call read/disp32
|
||||
e8/call read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 0)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-read-returns-0-on-end-of-file"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-returns-0-on-end-of-file"/imm32
|
||||
68/push 0/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-stream-buffer:
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -13,83 +13,83 @@
|
|||
# buffered-file.
|
||||
|
||||
Stdin:
|
||||
# file descriptor or (address stream)
|
||||
00 00 00 00 # 0 = standard input
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
# file descriptor or (address stream)
|
||||
00 00 00 00 # 0 = standard input
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
# TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
#? e8/call test-read-byte-multiple/disp32
|
||||
# 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
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
#? e8/call test-read-byte-multiple/disp32
|
||||
# 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
|
||||
|
||||
# return next byte value in EAX, with top 3 bytes cleared.
|
||||
# On EOF, return 0xffffffff.
|
||||
read-byte: # f : (address buffered-file) -> byte/EAX
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# save registers
|
||||
51/push-ECX
|
||||
56/push-ESI
|
||||
# ESI = f
|
||||
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
|
||||
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)
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# save registers
|
||||
51/push-ECX
|
||||
56/push-ESI
|
||||
# ESI = f
|
||||
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
|
||||
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)
|
||||
# push args
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX
|
||||
50/push-EAX
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# EAX = read(f->fd, stream = f+4)
|
||||
# push args
|
||||
50/push-EAX
|
||||
ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
|
||||
50/push-EAX
|
||||
ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
|
||||
# call
|
||||
e8/call read/disp32
|
||||
e8/call read/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# if EAX = 0 return 0xffffffff
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
|
||||
75/jump-if-not-equal $read-byte:from-stream/disp8
|
||||
b8/copy-to-EAX 0xffffffff/imm32
|
||||
eb/jump $read-byte:end/disp8
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# if EAX = 0 return 0xffffffff
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
|
||||
75/jump-if-not-equal $read-byte:from-stream/disp8
|
||||
b8/copy-to-EAX 0xffffffff/imm32
|
||||
eb/jump $read-byte:end/disp8
|
||||
$read-byte: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
|
||||
# ++f->read
|
||||
ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8)
|
||||
# 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
|
||||
# ++f->read
|
||||
ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8)
|
||||
$read-byte:end:
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5e/pop-to-ESI
|
||||
59/pop-to-ECX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
# todo: how should write-byte look? What should it do when the output has no
|
||||
# space remaining? Maybe return an error code.
|
||||
|
@ -97,151 +97,151 @@ $read-byte:end:
|
|||
## 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'
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-buffered-file+4)
|
||||
# push args
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
# push args
|
||||
68/push _test-buffered-file/imm32
|
||||
68/push _test-buffered-file/imm32
|
||||
# call
|
||||
e8/call read-byte/disp32
|
||||
e8/call read-byte/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 'A')
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 'A')
|
||||
# push args
|
||||
68/push "F - test-read-byte-single"/imm32
|
||||
68/push 0x41/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-byte-single"/imm32
|
||||
68/push 0x41/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# 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
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-buffered-file+4)
|
||||
# push args
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
e8/call write/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
# push args
|
||||
68/push _test-buffered-file/imm32
|
||||
68/push _test-buffered-file/imm32
|
||||
# call
|
||||
e8/call read-byte/disp32
|
||||
e8/call read-byte/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
# push args
|
||||
68/push _test-buffered-file/imm32
|
||||
68/push _test-buffered-file/imm32
|
||||
# call
|
||||
e8/call read-byte/disp32
|
||||
e8/call read-byte/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 'b')
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 'b')
|
||||
# push args
|
||||
68/push "F - test-read-byte-multiple"/imm32
|
||||
68/push 0x62/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-byte-multiple"/imm32
|
||||
68/push 0x62/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# 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
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-buffered-file+4)
|
||||
# push args
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
b8/copy-to-EAX _test-buffered-file/imm32
|
||||
05/add-to-EAX 4/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
e8/call clear-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# read-byte(_test-buffered-file)
|
||||
# push args
|
||||
68/push _test-buffered-file/imm32
|
||||
68/push _test-buffered-file/imm32
|
||||
# call
|
||||
e8/call read-byte/disp32
|
||||
e8/call read-byte/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, -1)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, -1)
|
||||
# push args
|
||||
68/push "F - test-read-byte-end-of-file"/imm32
|
||||
68/push -1/imm32
|
||||
50/push-EAX
|
||||
68/push "F - test-read-byte-end-of-file"/imm32
|
||||
68/push -1/imm32
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-buffered-file:
|
||||
# file descriptor or (address stream)
|
||||
_test-stream/imm32
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
# file descriptor or (address stream)
|
||||
_test-stream/imm32
|
||||
# current write index
|
||||
00 00 00 00
|
||||
# current read index
|
||||
00 00 00 00
|
||||
# length (8)
|
||||
08 00 00 00
|
||||
# data
|
||||
00 00 00 00 00 00 00 00 # 8 bytes
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -1,239 +1,239 @@
|
|||
# write-stream: like write, but write streams rather than strings
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
# manual test
|
||||
#? # write-stream(stdout, _test-stream2)
|
||||
#? 68/push _test-stream2/imm32
|
||||
#? 68/push 1/imm32/stdout
|
||||
#? e8/call write-stream/disp32
|
||||
# automatic test
|
||||
#? e8/call test-write-stream-appends/disp32
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
# manual test
|
||||
#? # write-stream(stdout, _test-stream2)
|
||||
#? 68/push _test-stream2/imm32
|
||||
#? 68/push 1/imm32/stdout
|
||||
#? e8/call write-stream/disp32
|
||||
# automatic test
|
||||
#? e8/call test-write-stream-appends/disp32
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
write-stream: # f : fd or (address stream), s : (address stream) -> <void>
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (f < 0x08000000) _write-stream(f, s), return # 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 $write-stream:fake/disp8
|
||||
# prolog
|
||||
55/push-EBP
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (f < 0x08000000) _write-stream(f, s), return # 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 $write-stream:fake/disp8
|
||||
# push args
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
|
||||
# call
|
||||
e8/call _write-stream/disp32
|
||||
e8/call _write-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
eb/jump $write-stream:end/disp8
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
eb/jump $write-stream:end/disp8
|
||||
$write-stream:fake:
|
||||
# otherwise, treat 'f' as a stream to append to
|
||||
# save registers
|
||||
50/push-EAX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# 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])
|
||||
# otherwise, treat 'f' as a stream to append to
|
||||
# save registers
|
||||
50/push-EAX
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = f
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
||||
# 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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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]
|
||||
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
|
||||
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
|
||||
# call
|
||||
e8/call _append-4/disp32
|
||||
e8/call _append-4/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# f->write += EAX
|
||||
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
|
||||
# s->read += EAX
|
||||
01/add 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # add EAX to *(EDI+4)
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
58/pop-to-EAX
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
||||
# f->write += EAX
|
||||
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
|
||||
# s->read += EAX
|
||||
01/add 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # add EAX to *(EDI+4)
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
58/pop-to-EAX
|
||||
$write-stream:end:
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
_write-stream: # fd : int, s : (address stream) -> <void>
|
||||
# prolog
|
||||
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
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# EDI = s->read
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 7/r32/EDI 4/disp8 . # copy *(ESI+4) to EDI
|
||||
# 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)
|
||||
# prolog
|
||||
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
|
||||
56/push-ESI
|
||||
57/push-EDI
|
||||
# ESI = s
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
||||
# EDI = s->read
|
||||
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 7/r32/EDI 4/disp8 . # copy *(ESI+4) to EDI
|
||||
# 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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to 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]
|
||||
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
|
||||
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
|
||||
29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX
|
||||
29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX
|
||||
# syscall
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
59/pop-to-ECX
|
||||
58/pop-to-EAX
|
||||
# epilog
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-write-stream-single:
|
||||
# clear-stream(_test-stream)
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-stream2)
|
||||
# push args
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream2/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream2, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write-stream(_test-stream, _test-stream2)
|
||||
# push args
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write-stream/disp32
|
||||
e8/call write-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream.data, 41/A 62/b 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream.data, 41/A 62/b 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-write-stream-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
68/push "F - test-write-stream-single"/imm32
|
||||
68/push 0x006241/imm32/Ab
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
test-write-stream-appends:
|
||||
# clear-stream(_test-stream)
|
||||
# clear-stream(_test-stream)
|
||||
# push args
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# clear-stream(_test-stream2)
|
||||
# push args
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream2/imm32
|
||||
# call
|
||||
e8/call clear-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# write(_test-stream2, "C")
|
||||
# push args
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push "C"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write-stream(_test-stream, _test-stream2)
|
||||
# push args
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write-stream/disp32
|
||||
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")
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write(_test-stream2, "D")
|
||||
# push args
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push "D"/imm32
|
||||
68/push _test-stream2/imm32
|
||||
# call
|
||||
e8/call write/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# write-stream(_test-stream, _test-stream2)
|
||||
# push args
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
68/push _test-stream2/imm32
|
||||
68/push _test-stream/imm32
|
||||
# call
|
||||
e8/call write-stream/disp32
|
||||
e8/call write-stream/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream.data, 43/C 44/D 00 00, msg)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check-ints-equal(*_test-stream.data, 43/C 44/D 00 00, msg)
|
||||
# push args
|
||||
68/push "F - test-write-stream-appends"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
68/push "F - test-write-stream-appends"/imm32
|
||||
68/push 0x00004443/imm32/C-D
|
||||
# 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)
|
||||
b8/copy-to-EAX _test-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
_test-stream2:
|
||||
# current write index
|
||||
04 00 00 00
|
||||
# current read index
|
||||
01 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
41 42 43 44 00 00 00 00 # 8 bytes
|
||||
# current write index
|
||||
04 00 00 00
|
||||
# current read index
|
||||
01 00 00 00
|
||||
# length (= 8)
|
||||
08 00 00 00
|
||||
# data
|
||||
41 42 43 44 00 00 00 00 # 8 bytes
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -15,94 +15,94 @@
|
|||
# When running tests the exit status doesn't mean anything. Yet.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (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")
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# if (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")
|
||||
# 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)
|
||||
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)
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
e8/call kernel-string-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# check result
|
||||
3d/compare-EAX 1/imm32
|
||||
75/jump-if-not-equal $run-main/disp8
|
||||
# then return 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)
|
||||
3d/compare-EAX 1/imm32
|
||||
75/jump-if-not-equal $run-main/disp8
|
||||
# then return 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)
|
||||
$run-main:
|
||||
# push args
|
||||
68/push 5/imm32
|
||||
68/push 5/imm32
|
||||
# call
|
||||
e8/call factorial/disp32
|
||||
e8/call factorial/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
$main:end:
|
||||
# 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
|
||||
# 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:
|
||||
# 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)
|
||||
b8/copy-to-EAX 1/imm32
|
||||
# if (n <= 1) jump exit
|
||||
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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
|
||||
81 5/subop/subtract 3/mod/direct 3/rm32/EBX . . . . . 1/imm32 # subtract from EBX
|
||||
# EAX = factorial(n-1)
|
||||
# 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)
|
||||
b8/copy-to-EAX 1/imm32
|
||||
# if (n <= 1) jump exit
|
||||
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
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
|
||||
81 5/subop/subtract 3/mod/direct 3/rm32/EBX . . . . . 1/imm32 # subtract from EBX
|
||||
# EAX = factorial(n-1)
|
||||
# push args
|
||||
53/push-EBX
|
||||
53/push-EBX
|
||||
# call
|
||||
e8/call factorial/disp32
|
||||
e8/call factorial/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# return n * factorial(n-1)
|
||||
f7 4/subop/multiply 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 8/disp8 . # multiply *(EBP+8) into EAX
|
||||
# TODO: check for overflow
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# return n * factorial(n-1)
|
||||
f7 4/subop/multiply 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 8/disp8 . # multiply *(EBP+8) into EAX
|
||||
# TODO: check for overflow
|
||||
$factorial:end:
|
||||
# epilog
|
||||
5b/pop-to-EBX
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# epilog
|
||||
5b/pop-to-EBX
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
|
||||
test-factorial:
|
||||
# factorial(5)
|
||||
# factorial(5)
|
||||
# push args
|
||||
68/push 5/imm32
|
||||
68/push 5/imm32
|
||||
# call
|
||||
e8/call factorial/disp32
|
||||
e8/call factorial/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 120, failure message)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# check-ints-equal(EAX, 120, failure message)
|
||||
# push args
|
||||
68/push "F - test-factorial"/imm32
|
||||
68/push 0x78/imm32/expected-120
|
||||
50/push-EAX
|
||||
68/push "F - test-factorial"/imm32
|
||||
68/push 0x78/imm32/expected-120
|
||||
50/push-EAX
|
||||
# call
|
||||
e8/call check-ints-equal/disp32
|
||||
e8/call check-ints-equal/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
||||
# end
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
# 0 # false
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main: return argv-equal(argv[1], argv[2])
|
||||
# At the start of a SubX program:
|
||||
|
@ -18,55 +18,55 @@
|
|||
# argv[0]: *(ESP+4)
|
||||
# argv[1]: *(ESP+8)
|
||||
# ...
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# call argv-equal(argv[1], argv[2])
|
||||
# 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]
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
# push argv[1]
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
|
||||
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)
|
||||
e8/call argv-equal/disp32
|
||||
# exit(EAX)
|
||||
$exit:
|
||||
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
|
||||
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
|
||||
|
||||
# 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
|
||||
# while (true)
|
||||
# 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
|
||||
# while (true)
|
||||
$argv-equal:loop:
|
||||
# c1/EAX, c2/EBX = *s1, *s2
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy byte at *ECX to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy byte at *EDX to lower byte of EBX
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy byte at *ECX to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy byte at *EDX to lower byte of EBX
|
||||
# if (c1 == 0) break
|
||||
3d/compare-EAX 0/imm32
|
||||
74/jump-if-equal $argv-equal:break/disp8
|
||||
3d/compare-EAX 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 with EBX
|
||||
75/jump-if-not-equal $argv-equal:false/disp8
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX
|
||||
75/jump-if-not-equal $argv-equal:false/disp8
|
||||
# ++s1, ++s2
|
||||
41/inc-ECX
|
||||
42/inc-EDX
|
||||
# end while
|
||||
eb/jump $argv-equal:loop/disp8
|
||||
41/inc-ECX
|
||||
42/inc-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
|
||||
# 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
|
||||
b8/copy-to-EAX 1/imm32
|
||||
c3/return
|
||||
# return false
|
||||
$argv-equal:false:
|
||||
b8/copy-to-EAX 0/imm32
|
||||
c3/return
|
||||
b8/copy-to-EAX 0/imm32
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -15,336 +15,336 @@
|
|||
# would cause tests to not run, rather than to fail as we'd like.)
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
# 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
|
||||
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# prolog
|
||||
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
|
||||
# prolog
|
||||
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
|
||||
|
||||
# pseudocode:
|
||||
# initialize n = b.length
|
||||
# initialize s1 = s
|
||||
# initialize s2 = b.data
|
||||
# i = 0
|
||||
# for (i = 0; i < n; ++n)
|
||||
# c1 = *s1
|
||||
# c2 = *s2
|
||||
# if c1 == 0
|
||||
# return false
|
||||
# if c1 != c2
|
||||
# return false
|
||||
# return *s1 == 0
|
||||
# initialize s into EDI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# initialize benchmark length n into EDX
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize benchmark data into ESI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize loop counter i into ECX
|
||||
b9/copy-to-ECX 0/imm32/exit
|
||||
# while (i/ECX < n/EDX)
|
||||
# pseudocode:
|
||||
# initialize n = b.length
|
||||
# initialize s1 = s
|
||||
# initialize s2 = b.data
|
||||
# i = 0
|
||||
# for (i = 0; i < n; ++n)
|
||||
# c1 = *s1
|
||||
# c2 = *s2
|
||||
# if c1 == 0
|
||||
# return false
|
||||
# if c1 != c2
|
||||
# return false
|
||||
# return *s1 == 0
|
||||
# initialize s into EDI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI
|
||||
# initialize benchmark length n into EDX
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize benchmark data into ESI
|
||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 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
|
||||
# initialize loop counter i into ECX
|
||||
b9/copy-to-ECX 0/imm32/exit
|
||||
# while (i/ECX < n/EDX)
|
||||
$kernel-string-equal:loop:
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
74/jump-if-equal $kernel-string-equal:break/disp8
|
||||
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
||||
74/jump-if-equal $kernel-string-equal:break/disp8
|
||||
# c1/EAX, c2/EBX = *s, *benchmark
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
bb/copy-to-EBX 0/imm32
|
||||
8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX
|
||||
# if (c1 == 0) return false
|
||||
3d/compare-EAX 0/imm32
|
||||
74/jump-if-equal $kernel-string-equal:false/disp8
|
||||
3d/compare-EAX 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 with EBX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
# ++s1, ++s2, ++i
|
||||
41/inc-ECX
|
||||
46/inc-ESI
|
||||
47/inc-EDI
|
||||
# end while
|
||||
eb/jump $kernel-string-equal:loop/disp8
|
||||
41/inc-ECX
|
||||
46/inc-ESI
|
||||
47/inc-EDI
|
||||
# end while
|
||||
eb/jump $kernel-string-equal:loop/disp8
|
||||
$kernel-string-equal:break:
|
||||
# if (*s/EDI == 0) return true
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
b8/copy-to-EAX 1/imm32
|
||||
# if (*s/EDI == 0) return true
|
||||
b8/copy-to-EAX 0/imm32
|
||||
8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX
|
||||
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
|
||||
75/jump-if-not-equal $kernel-string-equal:false/disp8
|
||||
b8/copy-to-EAX 1/imm32
|
||||
$kernel-string-equal:true:
|
||||
eb/jump $kernel-string-equal:end/disp8
|
||||
# return false
|
||||
eb/jump $kernel-string-equal:end/disp8
|
||||
# return false
|
||||
$kernel-string-equal:false:
|
||||
b8/copy-to-EAX 0/imm32
|
||||
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
|
||||
# end
|
||||
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
||||
5d/pop-to-EBP
|
||||
c3/return
|
||||
# restore registers
|
||||
5f/pop-to-EDI
|
||||
5e/pop-to-ESI
|
||||
5b/pop-to-EBX
|
||||
5a/pop-to-EDX
|
||||
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
|
||||
|
||||
## tests
|
||||
|
||||
test-compare-null-kernel-string-with-empty-array:
|
||||
# EAX = kernel-string-equal(Null-kernel-string, "")
|
||||
# EAX = kernel-string-equal(Null-kernel-string, "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
68/push ""/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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")
|
||||
# EAX = kernel-string-equal(Null-kernel-string, "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push Null-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Abc")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Abc")
|
||||
# push args
|
||||
68/push "Abc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Abc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Adc")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Adc")
|
||||
# push args
|
||||
68/push "Adc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Adc"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call 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
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "")
|
||||
# push args
|
||||
68/push ""/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push ""/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-equal-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Ab")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Ab")
|
||||
# push args
|
||||
68/push "Ab"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Ab"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
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(Abc-kernel-string, "Abcd")
|
||||
# EAX = kernel-string-equal(Abc-kernel-string, "Abcd")
|
||||
# push args
|
||||
68/push "Abcd"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
68/push "Abcd"/imm32
|
||||
68/push Abc-kernel-string/imm32
|
||||
# call
|
||||
e8/call kernel-string-equal/disp32
|
||||
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)
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||
# call check-ints-equal(EAX, 0)
|
||||
# push args
|
||||
68/push "F - test-compare-kernel-string-with-longer-array"/imm32
|
||||
68/push 0/imm32/false
|
||||
50/push-EAX
|
||||
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
|
||||
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
|
||||
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
|
||||
# prolog
|
||||
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 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
|
||||
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
|
||||
75/jump-if-unequal $check-ints-equal:else/disp8
|
||||
# prolog
|
||||
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 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
|
||||
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('.')
|
||||
# push args
|
||||
68/push "."/imm32
|
||||
68/push "."/imm32
|
||||
# call
|
||||
e8/call write-stderr/disp32
|
||||
e8/call write-stderr/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# return
|
||||
eb/jump $check-ints-equal:end/disp8
|
||||
# else:
|
||||
eb/jump $check-ints-equal:end/disp8
|
||||
# else:
|
||||
$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
|
||||
# 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
|
||||
# print(ECX)
|
||||
# push args
|
||||
51/push-ECX
|
||||
51/push-ECX
|
||||
# call
|
||||
e8/call write-stderr/disp32
|
||||
e8/call write-stderr/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
# print newline
|
||||
# push args
|
||||
68/push Newline/imm32
|
||||
68/push Newline/imm32
|
||||
# call
|
||||
e8/call write-stderr/disp32
|
||||
e8/call write-stderr/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
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
|
||||
# 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) -> <void>
|
||||
# prolog
|
||||
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)
|
||||
# prolog
|
||||
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
|
||||
bb/copy-to-EBX 2/imm32
|
||||
# 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
|
||||
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
|
||||
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
|
||||
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
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# 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
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
# 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
|
||||
01 00 00 00
|
||||
# data
|
||||
0a/newline
|
||||
# size
|
||||
01 00 00 00
|
||||
# data
|
||||
0a/newline
|
||||
|
||||
# for kernel-string-equal tests
|
||||
Null-kernel-string:
|
||||
00/null
|
||||
00/null
|
||||
Abc-kernel-string:
|
||||
41/A 62/b 63/c 00/null
|
||||
41/A 62/b 63/c 00/null
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -7,38 +7,38 @@
|
|||
# You shouldn't get a segmentation fault.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# syscall(mmap, 0x1000)
|
||||
bb/copy-to-EBX Mmap-new-segment/imm32
|
||||
b8/copy-to-EAX 0x5a/imm32/mmap
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(mmap, 0x1000)
|
||||
bb/copy-to-EBX Mmap-new-segment/imm32
|
||||
b8/copy-to-EAX 0x5a/imm32/mmap
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# store to *EAX
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
|
||||
# store to *EAX
|
||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *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
|
||||
# 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
|
||||
|
||||
== 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
|
||||
00 00 00 00 # null
|
||||
# len
|
||||
00 01 00 00 # 0x1000
|
||||
# protection flags
|
||||
03 00 00 00 # PROT_READ | PROT_WRITE
|
||||
# sharing flags
|
||||
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
|
||||
# fd
|
||||
ff ff ff ff # -1 since MAP_ANONYMOUS is specified
|
||||
# offset
|
||||
00 00 00 00 # 0 since MAP_ANONYMOUS is specified
|
||||
# addr
|
||||
00 00 00 00 # null
|
||||
# len
|
||||
00 01 00 00 # 0x1000
|
||||
# protection flags
|
||||
03 00 00 00 # PROT_READ | PROT_WRITE
|
||||
# sharing flags
|
||||
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
|
||||
# fd
|
||||
ff ff ff ff # -1 since MAP_ANONYMOUS is specified
|
||||
# offset
|
||||
00 00 00 00 # 0 since MAP_ANONYMOUS is specified
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -8,29 +8,29 @@
|
|||
# 55
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# result: EBX = 0
|
||||
bb/copy-to-EBX 0/imm32
|
||||
# counter: ECX = 1
|
||||
b9/copy-to-ECX 1/imm32
|
||||
# result: EBX = 0
|
||||
bb/copy-to-EBX 0/imm32
|
||||
# counter: ECX = 1
|
||||
b9/copy-to-ECX 1/imm32
|
||||
|
||||
$loop:
|
||||
# while (counter <= 10)
|
||||
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/inc-ECX
|
||||
# loop
|
||||
eb/jump $loop/disp8
|
||||
# while (counter <= 10)
|
||||
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/inc-ECX
|
||||
# loop
|
||||
eb/jump $loop/disp8
|
||||
|
||||
$exit:
|
||||
# exit(EBX)
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
# exit(EBX)
|
||||
b8/copy-to-EAX 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -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)
|
||||
# initialize 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
|
||||
|
||||
|
@ -35,6 +35,6 @@ cd/syscall 0x80/imm8
|
|||
== data
|
||||
|
||||
X:
|
||||
00 00 00 00 # space for read() to write to
|
||||
00 00 00 00 # space for read() to write to
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -5,38 +5,38 @@
|
|||
# $ subx run examples/ex5
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# main:
|
||||
# allocate x on the stack
|
||||
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # subtract from ESP
|
||||
# allocate x on the stack
|
||||
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # subtract from ESP
|
||||
|
||||
# syscall(read, stdin, x, 1)
|
||||
# syscall(read, stdin, x, 1)
|
||||
# fd = 0 (stdin)
|
||||
bb/copy-to-EBX 0/imm32
|
||||
bb/copy-to-EBX 0/imm32
|
||||
# initialize 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
|
||||
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
|
||||
ba/copy-to-EDX 1/imm32
|
||||
# syscall
|
||||
b8/copy-to-EAX 3/imm32/read
|
||||
cd/syscall 0x80/imm8
|
||||
b8/copy-to-EAX 3/imm32/read
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# syscall(write, stdout, x, 1)
|
||||
# syscall(write, stdout, x, 1)
|
||||
# fd = 1 (stdout)
|
||||
bb/copy-to-EBX 1/imm32
|
||||
bb/copy-to-EBX 1/imm32
|
||||
# initialize 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
|
||||
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
|
||||
ba/copy-to-EDX 1/imm32
|
||||
# syscall
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# syscall(exit, EBX)
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(exit, EBX)
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -6,31 +6,31 @@
|
|||
# Hello, world!
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# syscall(write, stdout, X, size)
|
||||
# syscall(write, stdout, X, size)
|
||||
# fd = 1 (stdout)
|
||||
bb/copy-to-EBX 1/imm32
|
||||
bb/copy-to-EBX 1/imm32
|
||||
# initialize X (location to write result to)
|
||||
b9/copy-to-ECX X/imm32
|
||||
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
|
||||
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
|
||||
b8/copy-to-EAX 4/imm32/write
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# syscall(exit, EBX)
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(exit, EBX)
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
== data
|
||||
|
||||
Size: # size of string
|
||||
0e 00 00 00 # 14
|
||||
0e 00 00 00 # 14
|
||||
X: # string to print
|
||||
48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a 00
|
||||
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
|
||||
|
|
|
@ -11,94 +11,94 @@
|
|||
# 97
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# syscall(creat, Filename)
|
||||
bb/copy-to-EBX Filename/imm32
|
||||
b9/copy-to-ECX 0x180/imm32/fixed-perms
|
||||
b8/copy-to-EAX 8/imm32/creat
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(creat, Filename)
|
||||
bb/copy-to-EBX Filename/imm32
|
||||
b9/copy-to-ECX 0x180/imm32/fixed-perms
|
||||
b8/copy-to-EAX 8/imm32/creat
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# stream = syscall(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
|
||||
b8/copy-to-EAX 5/imm32/open
|
||||
cd/syscall 0x80/imm8
|
||||
# stream = syscall(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
|
||||
b8/copy-to-EAX 5/imm32/open
|
||||
cd/syscall 0x80/imm8
|
||||
# save stream
|
||||
bb/copy-to-EBX Stream/imm32
|
||||
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
|
||||
bb/copy-to-EBX Stream/imm32
|
||||
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
|
||||
|
||||
# syscall(write, Stream, "a", 1)
|
||||
# syscall(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
|
||||
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
|
||||
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)
|
||||
# syscall(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
|
||||
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
|
||||
b8/copy-to-EAX 6/imm32/close
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# stream = syscall(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
|
||||
b8/copy-to-EAX 5/imm32/open
|
||||
cd/syscall 0x80/imm8
|
||||
# stream = syscall(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
|
||||
b8/copy-to-EAX 5/imm32/open
|
||||
cd/syscall 0x80/imm8
|
||||
# save Stream
|
||||
bb/copy-to-EBX Stream/imm32
|
||||
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
|
||||
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)
|
||||
# syscall(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
|
||||
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
|
||||
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)
|
||||
# syscall(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
|
||||
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
|
||||
b8/copy-to-EAX 6/imm32/close
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# syscall(unlink, filename)
|
||||
bb/copy-to-EBX Filename/imm32
|
||||
b8/copy-to-EAX 0xa/imm32/unlink
|
||||
cd/syscall 0x80/imm8
|
||||
# syscall(unlink, filename)
|
||||
bb/copy-to-EBX Filename/imm32
|
||||
b8/copy-to-EAX 0xa/imm32/unlink
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# syscall(exit, b)
|
||||
# syscall(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
|
||||
bb/copy-to-EBX B/imm32
|
||||
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
|
||||
#
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
== data
|
||||
|
||||
Stream:
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
A:
|
||||
61 00 00 00
|
||||
61 00 00 00
|
||||
B:
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
Filename:
|
||||
2e 66 6f 6f 00 00 00 00
|
||||
2e 66 6f 6f 00 00 00 00
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -15,44 +15,44 @@
|
|||
# Locals start from ESP-4 downwards.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# call ascii-length(argv[1])
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# call 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)
|
||||
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-length/disp32
|
||||
e8/call ascii-length/disp32
|
||||
# discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
# 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
|
||||
|
||||
ascii-length: # (s)
|
||||
# initialize s (EDX)
|
||||
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)
|
||||
b8/copy-to-EAX 0/imm32
|
||||
# initialize s (EDX)
|
||||
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)
|
||||
b8/copy-to-EAX 0/imm32
|
||||
$ascii-length-loop:
|
||||
# var c = *s (ECX)
|
||||
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
|
||||
74/jump-if-equal $ascii-length-ret/disp8
|
||||
# ++s
|
||||
81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 1/imm32 # add to EDX
|
||||
# ++result
|
||||
40/inc-EAX
|
||||
# loop
|
||||
eb/jump $ascii-length-loop/disp8
|
||||
# var c = *s (ECX)
|
||||
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
|
||||
74/jump-if-equal $ascii-length-ret/disp8
|
||||
# ++s
|
||||
81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 1/imm32 # add to EDX
|
||||
# ++result
|
||||
40/inc-EAX
|
||||
# loop
|
||||
eb/jump $ascii-length-loop/disp8
|
||||
$ascii-length-ret:
|
||||
# return (result in EAX)
|
||||
c3/return
|
||||
# return (result in EAX)
|
||||
c3/return
|
||||
|
||||
# vim:nowrap:textwidth=0
|
||||
|
|
|
@ -17,35 +17,35 @@
|
|||
# Locals start from ESP-4 downwards.
|
||||
|
||||
== code
|
||||
# instruction effective address operand 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
|
||||
# instruction effective address operand 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
|
||||
|
||||
# prolog
|
||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||
# call ascii-difference(argv[1], argv[2])
|
||||
# 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]
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||
# push argv[1]
|
||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
|
||||
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
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
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
|
||||
b8/copy-to-EAX 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
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
|
||||
# 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
|
||||
|
|
Loading…
Reference in New Issue