Reindent all SubX code to make some room for the new comment style.
This commit is contained in:
Kartik Agaram 2018-11-30 10:54:42 -08:00
parent e9661581f0
commit 6030d7e2e5
24 changed files with 2963 additions and 2963 deletions

View File

@ -1,45 +1,45 @@
# _write: write to a file descriptor # _write: write to a file descriptor
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # main:
# syscall(exit, 0) -- can't test _write just yet # syscall(exit, 0) -- can't test _write just yet
bb/copy-to-EBX 0/imm32 bb/copy-to-EBX 0/imm32
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
_write: # fd : int, s : (address array byte) -> <void> _write: # fd : int, s : (address array byte) -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
# syscall(write, fd, (data) s+4, (size) *s) # syscall(write, fd, (data) s+4, (size) *s)
# fd : EBX # fd : EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX 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 # 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 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 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
# size : EDX = *s # 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 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 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX
# syscall # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# restore registers # restore registers
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -1,85 +1,85 @@
# Rudimentary test harness # Rudimentary test harness
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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) # main: (manual test if this is the last file loaded)
# check-ints-equal(34, 34) # check-ints-equal(34, 34)
68/push "error in check-ints-equal"/imm32 68/push "error in check-ints-equal"/imm32
68/push 34/imm32 68/push 34/imm32
68/push 34/imm32 68/push 34/imm32
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# syscall(exit, 0) # syscall(exit, 0)
bb/copy-to-EBX 0/imm32 bb/copy-to-EBX 0/imm32
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# print msg to stderr if a != b, otherwise print "." # print msg to stderr if a != b, otherwise print "."
check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
53/push-EBX 53/push-EBX
# load first 2 args into EAX and 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 . 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 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX
# if EAX == b/EBX # if EAX == b/EBX
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and 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 75/jump-if-unequal $check-ints-equal:else/disp8
# _write(2/stderr, '.') # _write(2/stderr, '.')
# push args # push args
68/push "."/imm32 68/push "."/imm32
68/push 2/imm32/stderr 68/push 2/imm32/stderr
# call # call
e8/call _write/disp32 e8/call _write/disp32
# discard args # 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 # return
eb/jump $check-ints-equal:end/disp8 eb/jump $check-ints-equal:end/disp8
# else: # else:
$check-ints-equal:else: $check-ints-equal:else:
# _write(2/stderr, msg) # _write(2/stderr, msg)
# push args # 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 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 51/push-ECX
68/push 2/imm32/stderr 68/push 2/imm32/stderr
# call # call
e8/call _write/disp32 e8/call _write/disp32
# discard args # 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) # _write(2/stderr, Newline)
# push args # push args
68/push Newline/imm32 68/push Newline/imm32
68/push 2/imm32/stderr 68/push 2/imm32/stderr
# call # call
e8/call _write/disp32 e8/call _write/disp32
# discard args # 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 # 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: $check-ints-equal:end:
# restore registers # restore registers
5b/pop-to-EBX 5b/pop-to-EBX
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
== data == data
Newline: Newline:
# size # size
01 00 00 00 01 00 00 00
# data # data
0a/newline 0a/newline
Num-test-failures: Num-test-failures:
00 00 00 00 00 00 00 00
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -15,247 +15,247 @@
# would cause tests to not run, rather than to fail as we'd like.) # would cause tests to not run, rather than to fail as we'd like.)
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# exit(Num-test-failures) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# compare a null-terminated ascii string with a more idiomatic length-prefixed byte array # 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 # 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 kernel-string-equal: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# pseudocode: # pseudocode:
# initialize n = b.length # initialize n = b.length
# initialize s1 = s # initialize s1 = s
# initialize s2 = b.data # initialize s2 = b.data
# i = 0 # i = 0
# for (i = 0; i < n; ++n) # for (i = 0; i < n; ++n)
# c1 = *s1 # c1 = *s1
# c2 = *s2 # c2 = *s2
# if c1 == 0 # if c1 == 0
# return false # return false
# if c1 != c2 # if c1 != c2
# return false # return false
# return *s1 == 0 # return *s1 == 0
# #
# initialize s into EDI # 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 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 # 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 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 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX
# initialize benchmark data into ESI # 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 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 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
# initialize loop counter i into ECX # initialize loop counter i into ECX
b9/copy-to-ECX 0/imm32/exit b9/copy-to-ECX 0/imm32/exit
# while (i/ECX < n/EDX) # while (i/ECX < n/EDX)
$kernel-string-equal:loop: $kernel-string-equal:loop:
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
74/jump-if-equal $kernel-string-equal:break/disp8 74/jump-if-equal $kernel-string-equal:break/disp8
# c1/EAX, c2/EBX = *s, *benchmark # c1/EAX, c2/EBX = *s, *benchmark
b8/copy-to-EAX 0/imm32 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 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 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 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 # if (c1 == 0) return false
3d/compare-EAX 0/imm32 3d/compare-EAX 0/imm32
74/jump-if-equal $kernel-string-equal:false/disp8 74/jump-if-equal $kernel-string-equal:false/disp8
# if (c1 != c2) return false # if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX 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 75/jump-if-not-equal $kernel-string-equal:false/disp8
# ++s1, ++s2, ++i # ++s1, ++s2, ++i
41/inc-ECX 41/inc-ECX
46/inc-ESI 46/inc-ESI
47/inc-EDI 47/inc-EDI
# end while # end while
eb/jump $kernel-string-equal:loop/disp8 eb/jump $kernel-string-equal:loop/disp8
$kernel-string-equal:break: $kernel-string-equal:break:
# if (*s/EDI == 0) return true # if (*s/EDI == 0) return true
b8/copy-to-EAX 0/imm32 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 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 3d/compare-EAX 0/imm32
75/jump-if-not-equal $kernel-string-equal:false/disp8 75/jump-if-not-equal $kernel-string-equal:false/disp8
$kernel-string-equal:true: $kernel-string-equal:true:
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
eb/jump $kernel-string-equal:end/disp8 eb/jump $kernel-string-equal:end/disp8
# return false # return false
$kernel-string-equal:false: $kernel-string-equal:false:
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
$kernel-string-equal:end: $kernel-string-equal:end:
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
## tests ## tests
test-compare-null-kernel-string-with-empty-array: test-compare-null-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Null-kernel-string, "") # EAX = kernel-string-equal(Null-kernel-string, "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push Null-kernel-string/imm32 68/push Null-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-null-kernel-string-with-non-empty-array: 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 # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push Null-kernel-string/imm32 68/push Null-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-equal-array: 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 # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-inequal-array: 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 # push args
68/push "Adc"/imm32 68/push "Adc"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-empty-array: test-compare-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Abc-kernel-string, "") # EAX = kernel-string-equal(Abc-kernel-string, "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-shorter-array: 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 # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-longer-array: 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 # push args
68/push "Abcd"/imm32 68/push "Abcd"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-longer-array"/imm32 68/push "F - test-compare-kernel-string-with-longer-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
== data == data
Null-kernel-string: Null-kernel-string:
00/null 00/null
Abc-kernel-string: Abc-kernel-string:
41/A 62/b 63/c 00/null 41/A 62/b 63/c 00/null
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -1,62 +1,62 @@
# Create a new segment (for data) using mmap(). # Create a new segment (for data) using mmap().
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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) # main: (manual test if this is the last file loaded)
# EAX = new-segment(0x1000) # EAX = new-segment(0x1000)
# push args # push args
68/push 0x1000/imm32 68/push 0x1000/imm32
# call # call
e8/call new-segment/disp32 e8/call new-segment/disp32
# discard args # 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 # store to *EAX
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
# exit(EAX) # exit(EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
new-segment: # len : int -> address new-segment: # len : int -> address
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
53/push-EBX 53/push-EBX
# copy len to mmap-new-segment.len # copy len to mmap-new-segment.len
# TODO: compute mmap-new-segment+4 before runtime # 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 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 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) 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4)
# mmap(mmap-new-segment) # mmap(mmap-new-segment)
bb/copy-to-EBX mmap-new-segment/imm32 bb/copy-to-EBX mmap-new-segment/imm32
b8/copy-to-EAX 0x5a/imm32/mmap b8/copy-to-EAX 0x5a/imm32/mmap
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# epilog # epilog
5b/pop-to-EBX 5b/pop-to-EBX
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
== data == data
# various constants used here were found in the Linux sources (search for file mman-common.h) # various constants used here were found in the Linux sources (search for file mman-common.h)
mmap-new-segment: # type mmap_arg_struct mmap-new-segment: # type mmap_arg_struct
# addr # addr
00 00 00 00 # null 00 00 00 00 # null
# len # len
00 00 00 00 # 0x1000 00 00 00 00 # 0x1000
# protection flags # protection flags
03 00 00 00 # PROT_READ | PROT_WRITE 03 00 00 00 # PROT_READ | PROT_WRITE
# sharing flags # sharing flags
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS 22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
# fd # fd
ff ff ff ff # -1 since MAP_ANONYMOUS is specified ff ff ff ff # -1 since MAP_ANONYMOUS is specified
# offset # offset
00 00 00 00 # 0 since MAP_ANONYMOUS is specified 00 00 00 00 # 0 since MAP_ANONYMOUS is specified
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -1,169 +1,169 @@
# Comparing 'regular' length-prefixed strings. # Comparing 'regular' length-prefixed strings.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# exit(Num-test-failures) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
string-equal: # s : string, benchmark : string -> EAX : boolean string-equal: # s : string, benchmark : string -> EAX : boolean
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
# pseudocode: # pseudocode:
# if s.length != b.length return false # if s.length != b.length return false
# for i = 0; i < s.length; ++i # for i = 0; i < s.length; ++i
# if s[i] != b[i] return false # if s[i] != b[i] return false
# return true # return true
# registers: # registers:
# i: ECX # i: ECX
# s.length: EDX # s.length: EDX
# b.length: EBX # b.length: EBX
# b[i]: EBX # b[i]: EBX
# s[i]: EAX # s[i]: EAX
# #
# var s/EAX : (address array byte) # 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 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) # 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 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 # if s.length != b.length return false
# EDX = s.length # 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 # compare s.length and b.length
39/compare 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # compare *EBX with EDX 39/compare 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # compare *EBX with EDX
75/jump-if-not-equal $string-equal:false/disp8 75/jump-if-not-equal $string-equal:false/disp8
$string-equal:lengths: $string-equal:lengths:
# var i/ECX : int = 0 # var i/ECX : int = 0
b9/copy-to-ECX 0/imm32 b9/copy-to-ECX 0/imm32
# EBX = &b[i] # EBX = &b[i]
43/inc-EBX 43/inc-EBX
# EAX = &s[i] # EAX = &s[i]
40/inc-EAX 40/inc-EAX
$string-equal:loop: $string-equal:loop:
# if i >= s.length return true # if i >= s.length return true
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX 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 7d/jump-if-greater-or-equal $string-equal:true/disp8
# if b[i] != s[i] return false # if b[i] != s[i] return false
# ESI = s[i] # 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 # compare b[i] with ESI
39/compare 0/mod/indirect 3/rm32/EBX . . . 6/r32/ESI . . # compare *EBX 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 75/jump-if-not-equal $string-equal:false/disp8
# ++i # ++i
41/inc-ECX 41/inc-ECX
40/inc-EAX 40/inc-EAX
43/inc-EBX 43/inc-EBX
# loop # loop
eb/jump $string-equal:loop/disp8 eb/jump $string-equal:loop/disp8
$string-equal:true: $string-equal:true:
# return true # return true
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
eb/jump $string-equal:end/disp8 eb/jump $string-equal:end/disp8
$string-equal:false: $string-equal:false:
# return false # return false
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
$string-equal:end: $string-equal:end:
# restore registers # restore registers
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
## tests ## tests
test-compare-empty-with-empty-string: test-compare-empty-with-empty-string:
# EAX = string-equal("", "") # EAX = string-equal("", "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push ""/imm32 68/push ""/imm32
# call # call
e8/call string-equal/disp32 e8/call string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-empty-with-empty-string"/imm32 68/push "F - test-compare-empty-with-empty-string"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-empty-with-non-empty-string: # also checks length-mismatch code path test-compare-empty-with-non-empty-string: # also checks length-mismatch code path
# EAX = string-equal("", "Abc") # EAX = string-equal("", "Abc")
# push args # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push ""/imm32 68/push ""/imm32
# call # call
e8/call string-equal/disp32 e8/call string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-empty-with-non-empty-string"/imm32 68/push "F - test-compare-empty-with-non-empty-string"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-equal-strings: test-compare-equal-strings:
# EAX = string-equal("Abc", "Abc") # EAX = string-equal("Abc", "Abc")
# push args # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push "Abc"/imm32 68/push "Abc"/imm32
# call # call
e8/call string-equal/disp32 e8/call string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-equal-strings"/imm32 68/push "F - test-compare-equal-strings"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-inequal-strings-equal-lengths: test-compare-inequal-strings-equal-lengths:
# EAX = string-equal("Abc", "Adc") # EAX = string-equal("Abc", "Adc")
# push args # push args
68/push "Adc"/imm32 68/push "Adc"/imm32
68/push "Abc"/imm32 68/push "Abc"/imm32
# call # call
e8/call string-equal/disp32 e8/call string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-inequal-strings-equal-lengths"/imm32 68/push "F - test-compare-inequal-strings-equal-lengths"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -23,337 +23,337 @@
# We'll save the address of the trace segment here. # We'll save the address of the trace segment here.
Trace-stream: Trace-stream:
00 00 00 00 00 00 00 00
# Fake trace-stream for tests. # Fake trace-stream for tests.
# Also illustrates the layout of the real trace-stream (segment). # Also illustrates the layout of the real trace-stream (segment).
_test-trace-stream: _test-trace-stream:
# current write index # current write index
00 00 00 00 00 00 00 00
# current read index # current read index
00 00 00 00 00 00 00 00
# length (= 8) # length (= 8)
08 00 00 00 08 00 00 00
# data # data
00 00 00 00 00 00 00 00 # 8 bytes 00 00 00 00 00 00 00 00 # 8 bytes
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 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) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream. # 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) # The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
initialize-trace-stream: initialize-trace-stream:
# EAX = new-segment(0x1000) # EAX = new-segment(0x1000)
# push args # push args
68/push 0x1000/imm32/N 68/push 0x1000/imm32/N
# call # call
e8/call new-segment/disp32 e8/call new-segment/disp32
# discard args # 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
# copy EAX to *Trace-stream # copy EAX to *Trace-stream
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # 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 # Trace-stream.length = 0x1000/N - 12
c7 0/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8) c7 0/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8)
c3/return c3/return
# Append a string to the given trace stream. # 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. # 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 trace: # t : (address trace-stream), line : string
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# EDI = t # 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 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 # 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 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 # ECX = t->write
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX
# EDX = t->length # EDX = t->length
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX 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) # EAX = _append-3(&t->data[t->write], &t->data[t->length], line)
# push line # push line
56/push-ESI 56/push-ESI
# push &t->data[t->length] # push &t->data[t->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 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 53/push-EBX
# push &t->data[t->write] # push &t->data[t->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 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 53/push-EBX
# call # call
e8/call _append-3/disp32 e8/call _append-3/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# if EAX == 0 return # if EAX == 0 return
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EDX 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EDX
74/jump-if-equal $trace:end/disp8 74/jump-if-equal $trace:end/disp8
# t->write += EAX # t->write += EAX
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI 01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
# refresh ECX = t->write # refresh ECX = t->write
8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX 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) # EAX = _append-3(&t->data[t->write], &t->data[t->length], line)
# push line # push line
68/push Newline/imm32 68/push Newline/imm32
# push &t->data[t->length] # push &t->data[t->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 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 53/push-EBX
# push &t->data[t->write] # push &t->data[t->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 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 53/push-EBX
# call # call
e8/call _append-3/disp32 e8/call _append-3/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# t->write += EAX # t->write += EAX
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI 01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
$trace:end: $trace:end:
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
clear-trace-stream: # t : (address trace-stream) clear-trace-stream: # t : (address trace-stream)
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
# EAX = t # 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 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 # ECX = t->length
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
# ECX = &t->data[t->length] # 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 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 # t->write = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# t->read = 0 # t->read = 0
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4) c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
# EAX = t->data # EAX = t->data
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
# while (true) # while (true)
$clear-trace-stream:loop: $clear-trace-stream:loop:
# if EAX >= ECX break # if EAX >= ECX break
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX 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 7d/jump-if-greater-or-equal $clear-trace-stream:end/disp8
# *EAX = 0 # *EAX = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# EAX += 4 # EAX += 4
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
eb/jump $clear-trace-stream:loop/disp8 eb/jump $clear-trace-stream:loop/disp8
$clear-trace-stream:end: $clear-trace-stream:end:
# restore registers # restore registers
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
## tests ## tests
test-trace-single: test-trace-single:
# clear-trace-stream(_test-trace-stream) # clear-trace-stream(_test-trace-stream)
# push args # push args
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call clear-trace-stream/disp32 e8/call clear-trace-stream/disp32
# discard args # 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
# trace(_test-trace-stream, "Ab") # trace(_test-trace-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call trace/disp32 e8/call trace/disp32
# discard args # 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-ints-equal(*_test-trace-stream.data, 41/A 62/b 0a/newline 00, msg) # check-ints-equal(*_test-trace-stream.data, 41/A 62/b 0a/newline 00, msg)
# push args # push args
68/push "F - test-trace-single"/imm32 68/push "F - test-trace-single"/imm32
68/push 0x0a6241/imm32/Ab-newline 68/push 0x0a6241/imm32/Ab-newline
# push *_test-trace-stream.data # push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32 b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-trace-appends: test-trace-appends:
# clear-trace-stream(_test-trace-stream) # clear-trace-stream(_test-trace-stream)
# push args # push args
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call clear-trace-stream/disp32 e8/call clear-trace-stream/disp32
# discard args # 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
# trace(_test-trace-stream, "C") # trace(_test-trace-stream, "C")
# push args # push args
68/push "C"/imm32 68/push "C"/imm32
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call trace/disp32 e8/call trace/disp32
# discard args # 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
# trace(_test-trace-stream, "D") # trace(_test-trace-stream, "D")
# push args # push args
68/push "D"/imm32 68/push "D"/imm32
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call trace/disp32 e8/call trace/disp32
# discard args # 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-ints-equal(*_test-trace-stream.data, 43/C 0a/newline 44/D 0a/newline, msg) # check-ints-equal(*_test-trace-stream.data, 43/C 0a/newline 44/D 0a/newline, msg)
# push args # push args
68/push "F - test-trace-appends"/imm32 68/push "F - test-trace-appends"/imm32
68/push 0x0a440a43/imm32/C-newline-D-newline 68/push 0x0a440a43/imm32/C-newline-D-newline
# push *_test-trace-stream.data # push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32 b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-trace-empty-line: test-trace-empty-line:
# clear-trace-stream(_test-trace-stream) # clear-trace-stream(_test-trace-stream)
# push args # push args
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call clear-trace-stream/disp32 e8/call clear-trace-stream/disp32
# discard args # 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
# trace(_test-trace-stream, "") # trace(_test-trace-stream, "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push _test-trace-stream/imm32 68/push _test-trace-stream/imm32
# call # call
e8/call trace/disp32 e8/call trace/disp32
# discard args # 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-ints-equal(*_test-trace-stream.data, 0, msg) # check-ints-equal(*_test-trace-stream.data, 0, msg)
# push args # push args
68/push "F - test-trace-empty-line"/imm32 68/push "F - test-trace-empty-line"/imm32
68/push 0/imm32 68/push 0/imm32
# push *_test-trace-stream.data # push *_test-trace-stream.data
b8/copy-to-EAX _test-trace-stream/imm32 b8/copy-to-EAX _test-trace-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
## helpers ## helpers
# 3-argument variant of _append # 3-argument variant of _append
_append-3: # out : address, outend : address, s : (array byte) -> num_bytes_appended/EAX _append-3: # out : address, outend : address, s : (array byte) -> num_bytes_appended/EAX
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
# _append-4(out, outend, &s.data[0], &s.data[s.length]) -> num_bytes_appended/EAX # _append-4(out, outend, &s.data[0], &s.data[s.length]) -> num_bytes_appended/EAX
# push &s.data[s.length] # push &s.data[s.length]
# EAX = s # 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 # 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] # 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 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 51/push-ECX
# push &s.data[0] # push &s.data[0]
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX
51/push-ECX 51/push-ECX
# push outend # push outend
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push out # push out
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
# call # call
e8/call _append-4/disp32 e8/call _append-4/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# restore registers # restore registers
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# 4-argument variant of _append # 4-argument variant of _append
_append-4: # out : address, outend : address, in : address, inend : address -> num_bytes_appended/EAX _append-4: # out : address, outend : address, in : address, inend : address -> num_bytes_appended/EAX
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# EAX/num_bytes_appended = 0 # EAX/num_bytes_appended = 0
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
# EDI = out # 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 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 # 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 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 # 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 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 # 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 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: $_append-4:loop:
# if ESI/src >= ECX/srcend break # if ESI/src >= ECX/srcend break
39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX 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 7d/jump-if-greater-or-equal $_append-4:end/disp8
# if EDI/out >= EDX/outend break (for now silently ignore filled up buffer) # 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 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 7d/jump-if-greater-or-equal $_append-4:end/disp8
# copy one byte from ESI/src to EDI/out # 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 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 88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI
# updates # updates
40/increment-EAX 40/increment-EAX
46/increment-ESI 46/increment-ESI
47/increment-EDI 47/increment-EDI
eb/jump $_append-4:loop/disp8 eb/jump $_append-4:loop/disp8
$_append-4:end: $_append-4:end:
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -16,197 +16,197 @@
# data: (array byte) # prefixed by length as usual # data: (array byte) # prefixed by length as usual
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 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) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
write: # f : fd or (address stream), s : (address array byte) -> bytes_written/EAX 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 # (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 # the number of bytes *not* written. Success would then be signaled by
# returning 0.) # returning 0.)
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to 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 # 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) 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 7d/jump-if-greater-or-equal $write:fake/disp8
# push args # 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 . . 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 . . 8/disp8 . # push *(EBP+8)
# call # call
e8/call _write/disp32 e8/call _write/disp32
# discard args # 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
eb/jump $write:end/disp8 eb/jump $write:end/disp8
$write:fake: $write:fake:
# otherwise, treat 'f' as a stream to append to # otherwise, treat 'f' as a stream to append to
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
# ECX = f # 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 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 # EDX = f->write
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
# EBX = f->length # EBX = f->length
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX 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) # EAX = _append-3(&f->data[f->write], &f->data[f->length], s)
# push s # push s
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
# push &f->data[f->length] # push &f->data[f->length]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX 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 53/push-EBX
# push &f->data[f->write] # push &f->data[f->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX 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 53/push-EBX
# call # call
e8/call _append-3/disp32 e8/call _append-3/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# f->write += EAX # f->write += EAX
01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX 01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX
# restore registers # restore registers
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
$write:end: $write:end:
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
clear-stream: # f : (address stream) -> <void> clear-stream: # f : (address stream) -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
# EAX = f # 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 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 # ECX = f->length
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
# ECX = &f->data[f->length] # 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 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 # f->write = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# f->read = 0 # f->read = 0
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4) c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
# EAX = f->data # EAX = f->data
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
# while (true) # while (true)
$clear-stream:loop: $clear-stream:loop:
# if EAX >= ECX break # if EAX >= ECX break
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX 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 7d/jump-if-greater-or-equal $clear-stream:end/disp8
# *EAX = 0 # *EAX = 0
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
# EAX += 4 # EAX += 4
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
eb/jump $clear-stream:loop/disp8 eb/jump $clear-stream:loop/disp8
$clear-stream:end: $clear-stream:end:
# restore registers # restore registers
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
test-write-single: test-write-single:
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "Ab") # write(_test-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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-ints-equal(EAX, 2) # check-ints-equal(EAX, 2)
# push args # push args
68/push "F - test-read-single: return EAX"/imm32 68/push "F - test-read-single: return EAX"/imm32
68/push 2/imm32 68/push 2/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 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) # check-ints-equal(*_test-stream->data, 41/A 62/b 00 00, msg)
# push args # push args
68/push "F - test-write-single"/imm32 68/push "F - test-write-single"/imm32
68/push 0x006241/imm32/Ab 68/push 0x006241/imm32/Ab
# push *_test-stream->data # push *_test-stream->data
b8/copy-to-EAX _test-stream/imm32 b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-write-appends: test-write-appends:
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "C") # write(_test-stream, "C")
# push args # push args
68/push "C"/imm32 68/push "C"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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(_test-stream, "D") # write(_test-stream, "D")
# push args # push args
68/push "D"/imm32 68/push "D"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg) # check-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg)
# push args # push args
68/push "F - test-write-appends"/imm32 68/push "F - test-write-appends"/imm32
68/push 0x00004443/imm32/C-D 68/push 0x00004443/imm32/C-D
# push *_test-stream->data # push *_test-stream->data
b8/copy-to-EAX _test-stream/imm32 b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
== data == data
_test-stream: _test-stream:
# current write index # current write index
00 00 00 00 00 00 00 00
# current read index # current read index
00 00 00 00 00 00 00 00
# length (= 8) # length (= 8)
08 00 00 00 08 00 00 00
# data # data
00 00 00 00 00 00 00 00 # 8 bytes 00 00 00 00 00 00 00 00 # 8 bytes
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -33,177 +33,177 @@
# Its value is its output, computed during stop and available to the test. # Its value is its output, computed during stop and available to the test.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 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 #? e8/call test-stop-skips-returns-on-exit/disp32
# syscall(exit, Num-test-failures) # syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to # Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to
# the stack. # the stack.
# Ugly that we need to know the size of args, but so it goes. # Ugly that we need to know the size of args, but so it goes.
tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void> tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
# EAX = nbytes # 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 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. # 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: # 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-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 # X-12 if the caller takes 8 bytes of args
# ..and so on # ..and so on
# That's the value we need to return: X-nbytes-4 # 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 # However, we also need to account for the perturbance to ESP caused by the
# call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4
# bytes for the return address and 4 bytes to push EBP above. # bytes for the return address and 4 bytes to push EBP above.
# So EBP at this point is X-16. # So EBP at this point is X-16.
# #
# So the return address for the next call in the caller is: # So the return address for the next call in the caller is:
# EBP+8 if the caller takes 4 bytes of args # EBP+8 if the caller takes 4 bytes of args
# EBP+4 if the caller takes 8 bytes of args # EBP+4 if the caller takes 8 bytes of args
# EBP if the caller takes 12 bytes of args # EBP if the caller takes 12 bytes of args
# EBP-4 if the caller takes 16 bytes of args # EBP-4 if the caller takes 16 bytes of args
# ..and so on # ..and so on
# That's EBP+12-nbytes. # That's EBP+12-nbytes.
# option 1: 6 + 3 bytes # option 1: 6 + 3 bytes
#? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from 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 #? 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 # option 2: 2 + 4 bytes
f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX 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 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 # 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 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 89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX
# initialize ed->value # initialize ed->value
c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4) c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4)
# restore registers # restore registers
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
stop: # ed : (address exit-descriptor), value : int stop: # ed : (address exit-descriptor), value : int
# no prolog; one way or another, we're going to clobber registers # no prolog; one way or another, we're going to clobber registers
# EAX = ed # 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 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 # exit(value) if ed->target == 0
81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX
75/jump-if-not-equal $stop:fake/disp8 75/jump-if-not-equal $stop:fake/disp8
# syscall(exit, value) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
$stop:fake: $stop:fake:
# ed->value = value+1 # 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 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 41/inc-ECX
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4)
# non-local jump to ed->target # non-local jump to ed->target
8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP
c3/return # doesn't return to caller c3/return # doesn't return to caller
test-stop-skips-returns-on-exit: test-stop-skips-returns-on-exit:
# This looks like the standard prolog, but is here for different reasons. # 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. # 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 # Use EBP here as a stable base to refer to locals and arguments from in the
# presence of push/pop/call instructions. # presence of push/pop/call instructions.
# *Don't* use EBP as a way to restore ESP. # *Don't* use EBP as a way to restore ESP.
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to 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 # 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 # 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. # containing function returns we'll need a new exit descriptor.
# var ed/EAX : (address exit-descriptor) # var ed/EAX : (address exit-descriptor)
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 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 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. # Size the exit-descriptor precisely for the next call below, to _test-stop-1.
# tailor-exit-descriptor(ed, 4) # tailor-exit-descriptor(ed, 4)
# push args # push args
68/push 4/imm32/nbytes-of-args-for-_test-stop-1 68/push 4/imm32/nbytes-of-args-for-_test-stop-1
50/push-EAX 50/push-EAX
# call # call
e8/call tailor-exit-descriptor/disp32 e8/call tailor-exit-descriptor/disp32
# discard args # 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
# call _test-stop-1(ed) # call _test-stop-1(ed)
# push args # push args
50/push-EAX 50/push-EAX
# call # call
e8/call _test-stop-1/disp32 e8/call _test-stop-1/disp32
## registers except ESP may be clobbered at this point ## registers except ESP may be clobbered at this point
# restore args # restore args
58/pop-to-EAX 58/pop-to-EAX
# check that _test-stop-1 tried to call exit(1) # 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 # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1
# push args # push args
68/push "F - test-stop-skips-returns-on-exit"/imm32 68/push "F - test-stop-skips-returns-on-exit"/imm32
68/push 2/imm32 68/push 2/imm32
# push ed->value # push ed->value
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# epilog # epilog
5d/pop-to-EBP 5d/pop-to-EBP
# don't restore ESP from EBP; manually reclaim locals # don't restore ESP from EBP; manually reclaim locals
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
c3/return c3/return
_test-stop-1: # ed : (address exit-descriptor) _test-stop-1: # ed : (address exit-descriptor)
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# _test-stop-2(ed) # _test-stop-2(ed)
# push args # 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 # call
e8/call _test-stop-2/disp32 e8/call _test-stop-2/disp32
## should never get past this point ## should never get past this point
# discard args # 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
# signal test failed: check-ints-equal(1, 0, msg) # signal test failed: check-ints-equal(1, 0, msg)
# push args # push args
68/push "F - test-stop-skips-returns-on-exit"/imm32 68/push "F - test-stop-skips-returns-on-exit"/imm32
68/push 0/imm32 68/push 0/imm32
68/push 1/imm32 68/push 1/imm32
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
_test-stop-2: # ed : (address exit-descriptor) _test-stop-2: # ed : (address exit-descriptor)
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# call stop(ed, 1) # call stop(ed, 1)
# push args # push args
68/push 1/imm32 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) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8)
# call # call
e8/call stop/disp32 e8/call stop/disp32
## should never get past this point ## should never get past this point
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -41,76 +41,76 @@
# data: (array byte) # prefixed by length as usual # data: (array byte) # prefixed by length as usual
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 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) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
## if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor ## if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor
81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) 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 7d/jump-if-greater-or-equal $read:fake/disp8
# push args # 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 . . 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 . . 8/disp8 . # push *(EBP+8)
# call # call
e8/call _read/disp32 e8/call _read/disp32
# discard args # 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 # return
eb/jump $read:end/disp8 eb/jump $read:end/disp8
$read:fake: $read:fake:
## otherwise, treat 'f' as a stream to scan from ## otherwise, treat 'f' as a stream to scan from
# save registers # save registers
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# ESI = f # 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 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 # 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 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], # EAX = _append-4(out = &s->data[s->write], outend = &s->data[s->length],
# in = &f->data[f->read], inend = &f->data[f->write]) # in = &f->data[f->read], inend = &f->data[f->write])
# push &f->data[f->write] # push &f->data[f->write]
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 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 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 50/push-EAX
# push &f->data[f->read] # push &f->data[f->read]
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX 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 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 50/push-EAX
# push &s->data[s->length] # push &s->data[s->length]
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 8/disp8 . # copy *(EDI+8) to EAX 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 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 50/push-EAX
# push &s->data[s->write] # push &s->data[s->write]
8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX 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 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 50/push-EAX
# call # call
e8/call _append-4/disp32 e8/call _append-4/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# s->write += EAX # s->write += EAX
01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI 01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI
# f.read += EAX # f.read += EAX
01/add 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # add EAX to *(ESI+4) 01/add 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # add EAX to *(ESI+4)
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
$read:end: $read:end:
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
## helpers ## helpers
@ -119,245 +119,245 @@ $read:end:
# Maybe a better helper would be 'empty-stream?' # Maybe a better helper would be 'empty-stream?'
_read: # fd : int, s : (address stream) -> num-bytes-read/EAX _read: # fd : int, s : (address stream) -> num-bytes-read/EAX
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
# ESI = s # 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 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 # EAX = s->write
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
# EDX = s->length # EDX = s->length
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX 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) # syscall(read, fd, &s->data[s->write], s->length - s->write)
# fd : EBX # fd : EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
# data : ECX = &s->data[s->write] # data : ECX = &s->data[s->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 1/r32/ECX 0xc/disp8 . # copy ESI+EAX+12 to ECX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 1/r32/ECX 0xc/disp8 . # copy ESI+EAX+12 to ECX
# size : EDX = s->length - s->write # size : EDX = s->length - s->write
29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX 29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX
# syscall # syscall
b8/copy-to-EAX 3/imm32/read b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# add the result EAX to s->write # add the result EAX to s->write
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
# restore registers # restore registers
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# Two options: # Two options:
# 1 (what we have above): # 1 (what we have above):
# ECX = s # ECX = s
# EAX = s->write # EAX = s->write
# EDX = s->length # EDX = s->length
# # syscall # # syscall
# ECX = lea ECX+EAX+12 # ECX = lea ECX+EAX+12
# EDX = sub EDX EAX # EDX = sub EDX EAX
# #
# 2: # 2:
# ECX = s # ECX = s
# EDX = s->length # EDX = s->length
# ECX = &s->data # ECX = &s->data
# # syscall # # syscall
# ECX = add ECX, s->write # ECX = add ECX, s->write
# EDX = sub EDX, s->write # EDX = sub EDX, s->write
# #
# Not much to choose between the two? Option 2 performs a duplicate load to # 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 # use one less register, but doesn't increase the amount of spilling (ECX
# and EDX must be used, and EAX must be clobbered anyway). # and EDX must be used, and EAX must be clobbered anyway).
## tests ## tests
test-read-single: test-read-single:
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-stream-buffer) # clear-stream(_test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "Ab") # write(_test-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
# read(_test-stream, _test-stream-buffer) # read(_test-stream, _test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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-ints-equal(EAX, 2) # check-ints-equal(EAX, 2)
# push args # push args
68/push "F - test-read-single: return EAX"/imm32 68/push "F - test-read-single: return EAX"/imm32
68/push 2/imm32 68/push 2/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 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) # check-ints-equal(*_test-stream-buffer->data, 41/A 62/b 00 00, msg)
# push args # push args
68/push "F - test-read-single"/imm32 68/push "F - test-read-single"/imm32
68/push 0x006241/imm32/Ab 68/push 0x006241/imm32/Ab
# push *_test-stream-buffer->data # push *_test-stream-buffer->data
b8/copy-to-EAX _test-stream-buffer/imm32 b8/copy-to-EAX _test-stream-buffer/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-read-is-stateful: test-read-is-stateful:
## make two consecutive reads, check that their results are appended ## make two consecutive reads, check that their results are appended
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-stream-buffer) # clear-stream(_test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "C") # write(_test-stream, "C")
# push args # push args
68/push "C"/imm32 68/push "C"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
# read(_test-stream, _test-stream-buffer) # read(_test-stream, _test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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(_test-stream, "D") # write(_test-stream, "D")
# push args # push args
68/push "D"/imm32 68/push "D"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
# read(_test-stream, _test-stream-buffer) # read(_test-stream, _test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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-ints-equal(*_test-stream-buffer->data, 43/C 44/D 00 00, msg) # check-ints-equal(*_test-stream-buffer->data, 43/C 44/D 00 00, msg)
# push args # push args
68/push "F - test-read-is-stateful"/imm32 68/push "F - test-read-is-stateful"/imm32
68/push 0x00004443/imm32/C-D 68/push 0x00004443/imm32/C-D
# push *_test-stream-buffer->data # push *_test-stream-buffer->data
b8/copy-to-EAX _test-stream-buffer/imm32 b8/copy-to-EAX _test-stream-buffer/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-read-returns-0-on-end-of-file: test-read-returns-0-on-end-of-file:
## read after hitting end-of-file, check that result is 0 ## read after hitting end-of-file, check that result is 0
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-stream-buffer) # clear-stream(_test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "Ab") # write(_test-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
## first read gets to end-of-file ## first read gets to end-of-file
# read(_test-stream, _test-stream-buffer) # read(_test-stream, _test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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
## second read ## second read
# read(_test-stream, _test-stream-buffer) # read(_test-stream, _test-stream-buffer)
# push args # push args
68/push _test-stream-buffer/imm32 68/push _test-stream-buffer/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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-ints-equal(EAX, 0) # check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-read-returns-0-on-end-of-file"/imm32 68/push "F - test-read-returns-0-on-end-of-file"/imm32
68/push 0/imm32 68/push 0/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
== data == data
_test-stream-buffer: _test-stream-buffer:
# current write index # current write index
00 00 00 00 00 00 00 00
# current read index # current read index
00 00 00 00 00 00 00 00
# length (= 8) # length (= 8)
08 00 00 00 08 00 00 00
# data # data
00 00 00 00 00 00 00 00 # 8 bytes 00 00 00 00 00 00 00 00 # 8 bytes
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -13,83 +13,83 @@
# buffered-file. # buffered-file.
Stdin: Stdin:
# file descriptor or (address stream) # file descriptor or (address stream)
00 00 00 00 # 0 = standard input 00 00 00 00 # 0 = standard input
# current write index # current write index
00 00 00 00 00 00 00 00
# current read index # current read index
00 00 00 00 00 00 00 00
# length (8) # length (8)
08 00 00 00 08 00 00 00
# data # data
00 00 00 00 00 00 00 00 # 8 bytes 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. # TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 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 #? e8/call test-read-byte-multiple/disp32
# syscall(exit, Num-test-failures) # syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# return next byte value in EAX, with top 3 bytes cleared. # return next byte value in EAX, with top 3 bytes cleared.
# On EOF, return 0xffffffff. # On EOF, return 0xffffffff.
read-byte: # f : (address buffered-file) -> byte/EAX read-byte: # f : (address buffered-file) -> byte/EAX
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
56/push-ESI 56/push-ESI
# ESI = f # 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 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 # ECX = f->read
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX
## if (f->read < f->write) read byte from stream ## if (f->read < f->write) read byte from stream
3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) 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 7c/jump-if-lesser $read-byte:from-stream/disp8
# clear-stream(stream = f+4) # clear-stream(stream = f+4)
# push args # push args
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX
50/push-EAX 50/push-EAX
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# EAX = read(f->fd, stream = f+4) # EAX = read(f->fd, stream = f+4)
# push args # push args
50/push-EAX 50/push-EAX
ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
# call # call
e8/call read/disp32 e8/call read/disp32
# discard args # 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
# if EAX = 0 return 0xffffffff # if EAX = 0 return 0xffffffff
81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
75/jump-if-not-equal $read-byte:from-stream/disp8 75/jump-if-not-equal $read-byte:from-stream/disp8
b8/copy-to-EAX 0xffffffff/imm32 b8/copy-to-EAX 0xffffffff/imm32
eb/jump $read-byte:end/disp8 eb/jump $read-byte:end/disp8
$read-byte:from-stream: $read-byte:from-stream:
# AL = f->data[f->read] # AL = f->data[f->read]
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 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 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 # ++f->read
ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8) ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8)
$read-byte:end: $read-byte:end:
# restore registers # restore registers
5e/pop-to-ESI 5e/pop-to-ESI
59/pop-to-ECX 59/pop-to-ECX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
# todo: how should write-byte look? What should it do when the output has no # todo: how should write-byte look? What should it do when the output has no
# space remaining? Maybe return an error code. # space remaining? Maybe return an error code.
@ -97,151 +97,151 @@ $read-byte:end:
## tests ## tests
test-read-byte-single: test-read-byte-single:
## check that read-byte returns first byte of 'file' ## check that read-byte returns first byte of 'file'
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-buffered-file+4) # clear-stream(_test-buffered-file+4)
# push args # push args
b8/copy-to-EAX _test-buffered-file/imm32 b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32 05/add-to-EAX 4/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "Ab") # write(_test-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
# read-byte(_test-buffered-file) # read-byte(_test-buffered-file)
# push args # push args
68/push _test-buffered-file/imm32 68/push _test-buffered-file/imm32
# call # call
e8/call read-byte/disp32 e8/call read-byte/disp32
# discard args # 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(EAX, 'A') # check-ints-equal(EAX, 'A')
# push args # push args
68/push "F - test-read-byte-single"/imm32 68/push "F - test-read-byte-single"/imm32
68/push 0x41/imm32 68/push 0x41/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-read-byte-multiple: test-read-byte-multiple:
## call read-byte twice, check that second call returns second byte ## call read-byte twice, check that second call returns second byte
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-buffered-file+4) # clear-stream(_test-buffered-file+4)
# push args # push args
b8/copy-to-EAX _test-buffered-file/imm32 b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32 05/add-to-EAX 4/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream, "Ab") # write(_test-stream, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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
# read-byte(_test-buffered-file) # read-byte(_test-buffered-file)
# push args # push args
68/push _test-buffered-file/imm32 68/push _test-buffered-file/imm32
# call # call
e8/call read-byte/disp32 e8/call read-byte/disp32
# discard args # 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
# read-byte(_test-buffered-file) # read-byte(_test-buffered-file)
# push args # push args
68/push _test-buffered-file/imm32 68/push _test-buffered-file/imm32
# call # call
e8/call read-byte/disp32 e8/call read-byte/disp32
# discard args # 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(EAX, 'b') # check-ints-equal(EAX, 'b')
# push args # push args
68/push "F - test-read-byte-multiple"/imm32 68/push "F - test-read-byte-multiple"/imm32
68/push 0x62/imm32 68/push 0x62/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-read-byte-end-of-file: test-read-byte-end-of-file:
## call read-byte on an empty 'file', check that it returns -1 ## call read-byte on an empty 'file', check that it returns -1
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-buffered-file+4) # clear-stream(_test-buffered-file+4)
# push args # push args
b8/copy-to-EAX _test-buffered-file/imm32 b8/copy-to-EAX _test-buffered-file/imm32
05/add-to-EAX 4/imm32 05/add-to-EAX 4/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# read-byte(_test-buffered-file) # read-byte(_test-buffered-file)
# push args # push args
68/push _test-buffered-file/imm32 68/push _test-buffered-file/imm32
# call # call
e8/call read-byte/disp32 e8/call read-byte/disp32
# discard args # 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(EAX, -1) # check-ints-equal(EAX, -1)
# push args # push args
68/push "F - test-read-byte-end-of-file"/imm32 68/push "F - test-read-byte-end-of-file"/imm32
68/push -1/imm32 68/push -1/imm32
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
== data == data
_test-buffered-file: _test-buffered-file:
# file descriptor or (address stream) # file descriptor or (address stream)
_test-stream/imm32 _test-stream/imm32
# current write index # current write index
00 00 00 00 00 00 00 00
# current read index # current read index
00 00 00 00 00 00 00 00
# length (8) # length (8)
08 00 00 00 08 00 00 00
# data # data
00 00 00 00 00 00 00 00 # 8 bytes 00 00 00 00 00 00 00 00 # 8 bytes
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -1,239 +1,239 @@
# write-stream: like write, but write streams rather than strings # write-stream: like write, but write streams rather than strings
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # main:
# manual test # manual test
#? # write-stream(stdout, _test-stream2) #? # write-stream(stdout, _test-stream2)
#? 68/push _test-stream2/imm32 #? 68/push _test-stream2/imm32
#? 68/push 1/imm32/stdout #? 68/push 1/imm32/stdout
#? e8/call write-stream/disp32 #? e8/call write-stream/disp32
# automatic test # automatic test
#? e8/call test-write-stream-appends/disp32 #? 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-'. 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) # 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 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 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
write-stream: # f : fd or (address stream), s : (address stream) -> <void> write-stream: # f : fd or (address stream), s : (address stream) -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to 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 # 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) 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 7d/jump-if-greater-or-equal $write-stream:fake/disp8
# push args # 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 . . 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 . . 8/disp8 . # push *(EBP+8)
# call # call
e8/call _write-stream/disp32 e8/call _write-stream/disp32
# discard args # 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
eb/jump $write-stream:end/disp8 eb/jump $write-stream:end/disp8
$write-stream:fake: $write-stream:fake:
# otherwise, treat 'f' as a stream to append to # otherwise, treat 'f' as a stream to append to
# save registers # save registers
50/push-EAX 50/push-EAX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# ESI = f # 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 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 # 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 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]) # EAX = _append-4(&f->data[f->write], &f->data[f->length], &s->data[s->read], &s->data[s->write])
# push &s->data[s->write] # push &s->data[s->write]
8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX 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 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 50/push-EAX
# push &s->data[s->read] # push &s->data[s->read]
8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy *(EDI+4) to EAX 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 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 50/push-EAX
# push &f->data[f->length] # push &f->data[f->length]
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX 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 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 50/push-EAX
# push &f->data[f->write] # push &f->data[f->write]
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 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 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 50/push-EAX
# call # call
e8/call _append-4/disp32 e8/call _append-4/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
# f->write += EAX # f->write += EAX
01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI
# s->read += EAX # s->read += EAX
01/add 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # add EAX to *(EDI+4) 01/add 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # add EAX to *(EDI+4)
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
58/pop-to-EAX 58/pop-to-EAX
$write-stream:end: $write-stream:end:
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
_write-stream: # fd : int, s : (address stream) -> <void> _write-stream: # fd : int, s : (address stream) -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# ESI = s # 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 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 # EDI = s->read
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 7/r32/EDI 4/disp8 . # copy *(ESI+4) to EDI 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 7/r32/EDI 4/disp8 . # copy *(ESI+4) to EDI
# EDX = s->write # EDX = s->write
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX 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) # syscall(write, fd, &s->data[s->read], s->write-s->read)
# fd : EBX # fd : EBX
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX
# data : ECX = &s->data[s->read] # data : ECX = &s->data[s->read]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 7/index/EDI . 1/r32/ECX 0xc/disp8 . # copy ESI+EDI+12 to ECX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 7/index/EDI . 1/r32/ECX 0xc/disp8 . # copy ESI+EDI+12 to ECX
# size : EDX = s->write - s->read # size : EDX = s->write - s->read
29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX 29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX
# syscall # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# epilog # epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
test-write-stream-single: test-write-stream-single:
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-stream2) # clear-stream(_test-stream2)
# push args # push args
68/push _test-stream2/imm32 68/push _test-stream2/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream2, "Ab") # write(_test-stream2, "Ab")
# push args # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push _test-stream2/imm32 68/push _test-stream2/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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-stream(_test-stream, _test-stream2) # write-stream(_test-stream, _test-stream2)
# push args # push args
68/push _test-stream2/imm32 68/push _test-stream2/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write-stream/disp32 e8/call write-stream/disp32
# discard args # 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-ints-equal(*_test-stream.data, 41/A 62/b 00 00, msg) # check-ints-equal(*_test-stream.data, 41/A 62/b 00 00, msg)
# push args # push args
68/push "F - test-write-stream-single"/imm32 68/push "F - test-write-stream-single"/imm32
68/push 0x006241/imm32/Ab 68/push 0x006241/imm32/Ab
# push *_test-stream.data # push *_test-stream.data
b8/copy-to-EAX _test-stream/imm32 b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
test-write-stream-appends: test-write-stream-appends:
# clear-stream(_test-stream) # clear-stream(_test-stream)
# push args # push args
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# clear-stream(_test-stream2) # clear-stream(_test-stream2)
# push args # push args
68/push _test-stream2/imm32 68/push _test-stream2/imm32
# call # call
e8/call clear-stream/disp32 e8/call clear-stream/disp32
# discard args # 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
# write(_test-stream2, "C") # write(_test-stream2, "C")
# push args # push args
68/push "C"/imm32 68/push "C"/imm32
68/push _test-stream2/imm32 68/push _test-stream2/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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-stream(_test-stream, _test-stream2) # write-stream(_test-stream, _test-stream2)
# push args # push args
68/push _test-stream2/imm32 68/push _test-stream2/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write-stream/disp32 e8/call write-stream/disp32
# discard args # 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(_test-stream2, "D") # write(_test-stream2, "D")
# push args # push args
68/push "D"/imm32 68/push "D"/imm32
68/push _test-stream2/imm32 68/push _test-stream2/imm32
# call # call
e8/call write/disp32 e8/call write/disp32
# discard args # 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-stream(_test-stream, _test-stream2) # write-stream(_test-stream, _test-stream2)
# push args # push args
68/push _test-stream2/imm32 68/push _test-stream2/imm32
68/push _test-stream/imm32 68/push _test-stream/imm32
# call # call
e8/call write-stream/disp32 e8/call write-stream/disp32
# discard args # 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-ints-equal(*_test-stream.data, 43/C 44/D 00 00, msg) # check-ints-equal(*_test-stream.data, 43/C 44/D 00 00, msg)
# push args # push args
68/push "F - test-write-stream-appends"/imm32 68/push "F - test-write-stream-appends"/imm32
68/push 0x00004443/imm32/C-D 68/push 0x00004443/imm32/C-D
# push *_test-stream.data # push *_test-stream.data
b8/copy-to-EAX _test-stream/imm32 b8/copy-to-EAX _test-stream/imm32
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
== data == data
_test-stream2: _test-stream2:
# current write index # current write index
04 00 00 00 04 00 00 00
# current read index # current read index
01 00 00 00 01 00 00 00
# length (= 8) # length (= 8)
08 00 00 00 08 00 00 00
# data # data
41 42 43 44 00 00 00 00 # 8 bytes 41 42 43 44 00 00 00 00 # 8 bytes
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,94 +15,94 @@
# When running tests the exit status doesn't mean anything. Yet. # When running tests the exit status doesn't mean anything. Yet.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # main:
# prolog # prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# if (argc > 1) # 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 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 7e/jump-if-lesser-or-equal $run-main/disp8
# and if (argv[1] == "test") # and if (argv[1] == "test")
# push args # push args
68/push "test"/imm32 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) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8)
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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 # check result
3d/compare-EAX 1/imm32 3d/compare-EAX 1/imm32
75/jump-if-not-equal $run-main/disp8 75/jump-if-not-equal $run-main/disp8
# then return run-tests() # then return run-tests()
e8/call run-tests/disp32 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 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 eb/jump $main:end/disp8 # where EAX will get copied to EBX
# else EAX = factorial(5) # else EAX = factorial(5)
$run-main: $run-main:
# push args # push args
68/push 5/imm32 68/push 5/imm32
# call # call
e8/call factorial/disp32 e8/call factorial/disp32
# discard args # 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: $main:end:
# exit(EAX) # exit(EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# factorial(n) # factorial(n)
factorial: factorial:
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
53/push-EBX 53/push-EBX
# initialize EAX to 1 (base case) # initialize EAX to 1 (base case)
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
# if (n <= 1) jump exit # 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) 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 7e/jump-if-<= $factorial:end/disp8
# EBX = n-1 # 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 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 81 5/subop/subtract 3/mod/direct 3/rm32/EBX . . . . . 1/imm32 # subtract from EBX
# EAX = factorial(n-1) # EAX = factorial(n-1)
# push args # push args
53/push-EBX 53/push-EBX
# call # call
e8/call factorial/disp32 e8/call factorial/disp32
# discard args # 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 n * factorial(n-1) # 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 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 # TODO: check for overflow
$factorial:end: $factorial:end:
# epilog # epilog
5b/pop-to-EBX 5b/pop-to-EBX
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
test-factorial: test-factorial:
# factorial(5) # factorial(5)
# push args # push args
68/push 5/imm32 68/push 5/imm32
# call # call
e8/call factorial/disp32 e8/call factorial/disp32
# discard args # 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(EAX, 120, failure message) # check-ints-equal(EAX, 120, failure message)
# push args # push args
68/push "F - test-factorial"/imm32 68/push "F - test-factorial"/imm32
68/push 0x78/imm32/expected-120 68/push 0x78/imm32/expected-120
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# end # end
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -8,9 +8,9 @@
# 0 # false # 0 # false
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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]) # main: return argv-equal(argv[1], argv[2])
# At the start of a SubX program: # At the start of a SubX program:
@ -18,55 +18,55 @@
# argv[0]: *(ESP+4) # argv[0]: *(ESP+4)
# argv[1]: *(ESP+8) # argv[1]: *(ESP+8)
# ... # ...
# prolog # prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# call argv-equal(argv[1], argv[2]) # call argv-equal(argv[1], argv[2])
# push 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] # 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 # call
e8/call argv-equal/disp32 e8/call argv-equal/disp32
# exit(EAX) # exit(EAX)
$exit: $exit:
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# compare two null-terminated ascii strings # compare two null-terminated ascii strings
# reason for the name: the only place we should have null-terminated ascii strings is from commandline args # 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 argv-equal: # (s1, s2) : null-terminated ascii strings -> EAX : boolean
# initialize s1 (ECX) and s2 (EDX) # 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 . 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 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) # while (true)
$argv-equal:loop: $argv-equal:loop:
# c1/EAX, c2/EBX = *s1, *s2 # c1/EAX, c2/EBX = *s1, *s2
b8/copy-to-EAX 0/imm32 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 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 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 8a/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy byte at *EDX to lower byte of EBX
# if (c1 == 0) break # if (c1 == 0) break
3d/compare-EAX 0/imm32 3d/compare-EAX 0/imm32
74/jump-if-equal $argv-equal:break/disp8 74/jump-if-equal $argv-equal:break/disp8
# if (c1 != c2) return false # if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX
75/jump-if-not-equal $argv-equal:false/disp8 75/jump-if-not-equal $argv-equal:false/disp8
# ++s1, ++s2 # ++s1, ++s2
41/inc-ECX 41/inc-ECX
42/inc-EDX 42/inc-EDX
# end while # end while
eb/jump $argv-equal:loop/disp8 eb/jump $argv-equal:loop/disp8
$argv-equal:break: $argv-equal:break:
# if (c2 == 0) return true # if (c2 == 0) return true
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX
75/jump-if-not-equal $argv-equal:false/disp8 75/jump-if-not-equal $argv-equal:false/disp8
$argv-equal:success: $argv-equal:success:
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
c3/return c3/return
# return false # return false
$argv-equal:false: $argv-equal:false:
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -15,336 +15,336 @@
# would cause tests to not run, rather than to fail as we'd like.) # would cause tests to not run, rather than to fail as we'd like.)
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # 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 run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# syscall(exit, EAX) # syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# compare a null-terminated ascii string with a more idiomatic length-prefixed byte array # 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 # 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 kernel-string-equal: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
56/push-ESI 56/push-ESI
57/push-EDI 57/push-EDI
# pseudocode: # pseudocode:
# initialize n = b.length # initialize n = b.length
# initialize s1 = s # initialize s1 = s
# initialize s2 = b.data # initialize s2 = b.data
# i = 0 # i = 0
# for (i = 0; i < n; ++n) # for (i = 0; i < n; ++n)
# c1 = *s1 # c1 = *s1
# c2 = *s2 # c2 = *s2
# if c1 == 0 # if c1 == 0
# return false # return false
# if c1 != c2 # if c1 != c2
# return false # return false
# return *s1 == 0 # return *s1 == 0
# initialize s into EDI # 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 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 # 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 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 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX
# initialize benchmark data into ESI # 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 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 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
# initialize loop counter i into ECX # initialize loop counter i into ECX
b9/copy-to-ECX 0/imm32/exit b9/copy-to-ECX 0/imm32/exit
# while (i/ECX < n/EDX) # while (i/ECX < n/EDX)
$kernel-string-equal:loop: $kernel-string-equal:loop:
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
74/jump-if-equal $kernel-string-equal:break/disp8 74/jump-if-equal $kernel-string-equal:break/disp8
# c1/EAX, c2/EBX = *s, *benchmark # c1/EAX, c2/EBX = *s, *benchmark
b8/copy-to-EAX 0/imm32 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 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 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 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 # if (c1 == 0) return false
3d/compare-EAX 0/imm32 3d/compare-EAX 0/imm32
74/jump-if-equal $kernel-string-equal:false/disp8 74/jump-if-equal $kernel-string-equal:false/disp8
# if (c1 != c2) return false # if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX 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 75/jump-if-not-equal $kernel-string-equal:false/disp8
# ++s1, ++s2, ++i # ++s1, ++s2, ++i
41/inc-ECX 41/inc-ECX
46/inc-ESI 46/inc-ESI
47/inc-EDI 47/inc-EDI
# end while # end while
eb/jump $kernel-string-equal:loop/disp8 eb/jump $kernel-string-equal:loop/disp8
$kernel-string-equal:break: $kernel-string-equal:break:
# if (*s/EDI == 0) return true # if (*s/EDI == 0) return true
b8/copy-to-EAX 0/imm32 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 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 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX
75/jump-if-not-equal $kernel-string-equal:false/disp8 75/jump-if-not-equal $kernel-string-equal:false/disp8
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
$kernel-string-equal:true: $kernel-string-equal:true:
eb/jump $kernel-string-equal:end/disp8 eb/jump $kernel-string-equal:end/disp8
# return false # return false
$kernel-string-equal:false: $kernel-string-equal:false:
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
$kernel-string-equal:end: $kernel-string-equal:end:
# restore registers # restore registers
5f/pop-to-EDI 5f/pop-to-EDI
5e/pop-to-ESI 5e/pop-to-ESI
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
# end # end
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
## tests ## tests
test-compare-null-kernel-string-with-empty-array: test-compare-null-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Null-kernel-string, "") # EAX = kernel-string-equal(Null-kernel-string, "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push Null-kernel-string/imm32 68/push Null-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-null-kernel-string-with-non-empty-array: 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 # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push Null-kernel-string/imm32 68/push Null-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-equal-array: 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 # push args
68/push "Abc"/imm32 68/push "Abc"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 1, msg) # call check-ints-equal(EAX, 1, msg)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 1/imm32/true 68/push 1/imm32/true
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-inequal-array: 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 # push args
68/push "Adc"/imm32 68/push "Adc"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0, msg) # call check-ints-equal(EAX, 0, msg)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-empty-array: test-compare-kernel-string-with-empty-array:
# EAX = kernel-string-equal(Abc-kernel-string, "") # EAX = kernel-string-equal(Abc-kernel-string, "")
# push args # push args
68/push ""/imm32 68/push ""/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push "F - test-compare-kernel-string-with-equal-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-shorter-array: 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 # push args
68/push "Ab"/imm32 68/push "Ab"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
test-compare-kernel-string-with-longer-array: 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 # push args
68/push "Abcd"/imm32 68/push "Abcd"/imm32
68/push Abc-kernel-string/imm32 68/push Abc-kernel-string/imm32
# call # call
e8/call kernel-string-equal/disp32 e8/call kernel-string-equal/disp32
# discard args # 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
# call check-ints-equal(EAX, 0) # call check-ints-equal(EAX, 0)
# push args # push args
68/push "F - test-compare-kernel-string-with-longer-array"/imm32 68/push "F - test-compare-kernel-string-with-longer-array"/imm32
68/push 0/imm32/false 68/push 0/imm32/false
50/push-EAX 50/push-EAX
# call # call
e8/call check-ints-equal/disp32 e8/call check-ints-equal/disp32
# discard args # discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return c3/return
## helpers ## helpers
# print msg to stderr if a != b, otherwise print "." # print msg to stderr if a != b, otherwise print "."
check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
51/push-ECX 51/push-ECX
53/push-EBX 53/push-EBX
# load args into EAX, EBX and ECX # 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 . 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 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX
# if EAX == b/EBX # if EAX == b/EBX
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and 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 75/jump-if-unequal $check-ints-equal:else/disp8
# print('.') # print('.')
# push args # push args
68/push "."/imm32 68/push "."/imm32
# call # call
e8/call write-stderr/disp32 e8/call write-stderr/disp32
# discard args # 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 # return
eb/jump $check-ints-equal:end/disp8 eb/jump $check-ints-equal:end/disp8
# else: # else:
$check-ints-equal:else: $check-ints-equal:else:
# copy msg into 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 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) # print(ECX)
# push args # push args
51/push-ECX 51/push-ECX
# call # call
e8/call write-stderr/disp32 e8/call write-stderr/disp32
# discard args # 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 # print newline
# push args # push args
68/push Newline/imm32 68/push Newline/imm32
# call # call
e8/call write-stderr/disp32 e8/call write-stderr/disp32
# discard args # 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: $check-ints-equal:end:
# restore registers # restore registers
5b/pop-to-EBX 5b/pop-to-EBX
59/pop-to-ECX 59/pop-to-ECX
# end # end
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
write-stderr: # s : (address array byte) -> <void> write-stderr: # s : (address array byte) -> <void>
# prolog # prolog
55/push-EBP 55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# save registers # save registers
50/push-EAX 50/push-EAX
51/push-ECX 51/push-ECX
52/push-EDX 52/push-EDX
53/push-EBX 53/push-EBX
# syscall(write, 2/stderr, (data) s+4, (size) *s) # syscall(write, 2/stderr, (data) s+4, (size) *s)
# fd = 2 (stderr) # fd = 2 (stderr)
bb/copy-to-EBX 2/imm32 bb/copy-to-EBX 2/imm32
# x = s+4 # x = s+4
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX 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 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX
# size = *s # size = *s
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 2/r32/EDX 8/disp8 . # copy *(EBP+8) to EDX 8b/copy 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 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX
# syscall # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# restore registers # restore registers
5b/pop-to-EBX 5b/pop-to-EBX
5a/pop-to-EDX 5a/pop-to-EDX
59/pop-to-ECX 59/pop-to-ECX
58/pop-to-EAX 58/pop-to-EAX
# end # end
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP 5d/pop-to-EBP
c3/return c3/return
== data == data
Newline: Newline:
# size # size
01 00 00 00 01 00 00 00
# data # data
0a/newline 0a/newline
# for kernel-string-equal tests # for kernel-string-equal tests
Null-kernel-string: Null-kernel-string:
00/null 00/null
Abc-kernel-string: Abc-kernel-string:
41/A 62/b 63/c 00/null 41/A 62/b 63/c 00/null
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -7,38 +7,38 @@
# You shouldn't get a segmentation fault. # You shouldn't get a segmentation fault.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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) # syscall(mmap, 0x1000)
bb/copy-to-EBX Mmap-new-segment/imm32 bb/copy-to-EBX Mmap-new-segment/imm32
b8/copy-to-EAX 0x5a/imm32/mmap b8/copy-to-EAX 0x5a/imm32/mmap
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# store to *EAX # store to *EAX
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX
# syscall(exit, EAX) # syscall(exit, EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
== data == data
# various constants used here were found in the Linux sources (search for file mman-common.h) # various constants used here were found in the Linux sources (search for file mman-common.h)
Mmap-new-segment: # type mmap_arg_struct Mmap-new-segment: # type mmap_arg_struct
# addr # addr
00 00 00 00 # null 00 00 00 00 # null
# len # len
00 01 00 00 # 0x1000 00 01 00 00 # 0x1000
# protection flags # protection flags
03 00 00 00 # PROT_READ | PROT_WRITE 03 00 00 00 # PROT_READ | PROT_WRITE
# sharing flags # sharing flags
22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS 22 00 00 00 # MAP_PRIVATE | MAP_ANONYMOUS
# fd # fd
ff ff ff ff # -1 since MAP_ANONYMOUS is specified ff ff ff ff # -1 since MAP_ANONYMOUS is specified
# offset # offset
00 00 00 00 # 0 since MAP_ANONYMOUS is specified 00 00 00 00 # 0 since MAP_ANONYMOUS is specified
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -8,29 +8,29 @@
# 55 # 55
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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 # result: EBX = 0
bb/copy-to-EBX 0/imm32 bb/copy-to-EBX 0/imm32
# counter: ECX = 1 # counter: ECX = 1
b9/copy-to-ECX 1/imm32 b9/copy-to-ECX 1/imm32
$loop: $loop:
# while (counter <= 10) # while (counter <= 10)
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0xa/imm32 # compare ECX 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0xa/imm32 # compare ECX
7f/jump-if-greater $exit/disp8 7f/jump-if-greater $exit/disp8
# result += counter # result += counter
01/add 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # add ECX to EBX 01/add 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # add ECX to EBX
# ++counter # ++counter
41/inc-ECX 41/inc-ECX
# loop # loop
eb/jump $loop/disp8 eb/jump $loop/disp8
$exit: $exit:
# exit(EBX) # exit(EBX)
b8/copy-to-EAX 1/imm32 b8/copy-to-EAX 1/imm32
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -7,24 +7,24 @@
== code == code
# syscall(read, stdin, X, 1) # syscall(read, stdin, X, 1)
# fd = 0 (stdin) # fd = 0 (stdin)
bb/copy-to-EBX 0/imm32 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 b9/copy-to-ECX X/imm32
# size = 1 character # size = 1 character
ba/copy-to-EDX 1/imm32 ba/copy-to-EDX 1/imm32
# syscall # syscall
b8/copy-to-EAX 3/imm32/read b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(write, stdout, X, 1) # syscall(write, stdout, X, 1)
# fd = 1 (stdout) # fd = 1 (stdout)
bb/copy-to-EBX 1/imm32 bb/copy-to-EBX 1/imm32
# initialize X (location to read from) # initialize X (location to read from)
b9/copy-to-ECX X/imm32 b9/copy-to-ECX X/imm32
# size = 1 character # size = 1 character
ba/copy-to-EDX 1/imm32 ba/copy-to-EDX 1/imm32
# syscall # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
@ -35,6 +35,6 @@ cd/syscall 0x80/imm8
== data == data
X: 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 # vim:nowrap:textwidth=0

View File

@ -5,38 +5,38 @@
# $ subx run examples/ex5 # $ subx run examples/ex5
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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: # main:
# allocate x on the stack # allocate x on the stack
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # subtract from ESP 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) # fd = 0 (stdin)
bb/copy-to-EBX 0/imm32 bb/copy-to-EBX 0/imm32
# initialize x (location to write result to) # 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 # size = 1 character
ba/copy-to-EDX 1/imm32 ba/copy-to-EDX 1/imm32
# syscall # syscall
b8/copy-to-EAX 3/imm32/read b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(write, stdout, x, 1) # syscall(write, stdout, x, 1)
# fd = 1 (stdout) # fd = 1 (stdout)
bb/copy-to-EBX 1/imm32 bb/copy-to-EBX 1/imm32
# initialize x (location to read from) # 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 # size = 1 character
ba/copy-to-EDX 1/imm32 ba/copy-to-EDX 1/imm32
# syscall # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(exit, EBX) # syscall(exit, EBX)
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -6,31 +6,31 @@
# Hello, world! # Hello, world!
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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) # fd = 1 (stdout)
bb/copy-to-EBX 1/imm32 bb/copy-to-EBX 1/imm32
# initialize X (location to write result to) # initialize X (location to write result to)
b9/copy-to-ECX X/imm32 b9/copy-to-ECX X/imm32
# initialize size # 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 # syscall
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(exit, EBX) # syscall(exit, EBX)
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
== data == data
Size: # size of string Size: # size of string
0e 00 00 00 # 14 0e 00 00 00 # 14
X: # string to print 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 # H e l l o , ␣ w o r l d ! newline null
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -11,94 +11,94 @@
# 97 # 97
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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) # syscall(creat, Filename)
bb/copy-to-EBX Filename/imm32 bb/copy-to-EBX Filename/imm32
b9/copy-to-ECX 0x180/imm32/fixed-perms b9/copy-to-ECX 0x180/imm32/fixed-perms
b8/copy-to-EAX 8/imm32/creat b8/copy-to-EAX 8/imm32/creat
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# stream = syscall(open, Filename, O_WRONLY, 0) # we can't use 'fd' because it looks like a hex byte # 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 bb/copy-to-EBX Filename/imm32
b9/copy-to-ECX 1/imm32/wronly b9/copy-to-ECX 1/imm32/wronly
ba/copy-to-EDX 0x180/imm32/fixed-perms ba/copy-to-EDX 0x180/imm32/fixed-perms
b8/copy-to-EAX 5/imm32/open b8/copy-to-EAX 5/imm32/open
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# save stream # save stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX 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 # load stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
# #
b9/copy-to-ECX A/imm32 b9/copy-to-ECX A/imm32
ba/copy-to-EDX 1/imm32/size ba/copy-to-EDX 1/imm32/size
b8/copy-to-EAX 4/imm32/write b8/copy-to-EAX 4/imm32/write
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(close, Stream) # syscall(close, Stream)
# load stream # load stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
# #
b8/copy-to-EAX 6/imm32/close b8/copy-to-EAX 6/imm32/close
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# stream = syscall(open, Filename, O_RDONLY, 0) # stream = syscall(open, Filename, O_RDONLY, 0)
bb/copy-to-EBX Filename/imm32 bb/copy-to-EBX Filename/imm32
b9/copy-to-ECX 0/imm32/rdonly b9/copy-to-ECX 0/imm32/rdonly
ba/copy-to-EDX 0x180/imm32/fixed-perms ba/copy-to-EDX 0x180/imm32/fixed-perms
b8/copy-to-EAX 5/imm32/open b8/copy-to-EAX 5/imm32/open
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# save Stream # save Stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX 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 # load stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
# #
b9/copy-to-ECX B/imm32 b9/copy-to-ECX B/imm32
ba/copy-to-EDX 1/imm32/size ba/copy-to-EDX 1/imm32/size
b8/copy-to-EAX 3/imm32/read b8/copy-to-EAX 3/imm32/read
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(close, Stream) # syscall(close, Stream)
# load stream # load stream
bb/copy-to-EBX Stream/imm32 bb/copy-to-EBX Stream/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
# #
b8/copy-to-EAX 6/imm32/close b8/copy-to-EAX 6/imm32/close
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(unlink, filename) # syscall(unlink, filename)
bb/copy-to-EBX Filename/imm32 bb/copy-to-EBX Filename/imm32
b8/copy-to-EAX 0xa/imm32/unlink b8/copy-to-EAX 0xa/imm32/unlink
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
# syscall(exit, b) # syscall(exit, b)
# load b # load b
bb/copy-to-EBX B/imm32 bb/copy-to-EBX B/imm32
8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX
# #
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
== data == data
Stream: Stream:
00 00 00 00 00 00 00 00
A: A:
61 00 00 00 61 00 00 00
B: B:
00 00 00 00 00 00 00 00
Filename: Filename:
2e 66 6f 6f 00 00 00 00 2e 66 6f 6f 00 00 00 00
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -15,44 +15,44 @@
# Locals start from ESP-4 downwards. # Locals start from ESP-4 downwards.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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 # prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# call ascii-length(argv[1]) # call ascii-length(argv[1])
# push args # 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 # call
e8/call ascii-length/disp32 e8/call ascii-length/disp32
# discard args # 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) # exit(EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
ascii-length: # (s) ascii-length: # (s)
# initialize s (EDX) # 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 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 2/r32/EDX 4/disp8 . # copy *(ESP+4) to EDX
# var result = 0 (EAX) # var result = 0 (EAX)
b8/copy-to-EAX 0/imm32 b8/copy-to-EAX 0/imm32
$ascii-length-loop: $ascii-length-loop:
# var c = *s (ECX) # var c = *s (ECX)
8a/copy 0/mod/* 2/rm32/EDX . . . 1/r32/ECX . . # copy byte at *EDX to lower byte of ECX 8a/copy 0/mod/* 2/rm32/EDX . . . 1/r32/ECX . . # copy byte at *EDX to lower byte of ECX
# if c == '\0' break # if c == '\0' break
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX
74/jump-if-equal $ascii-length-ret/disp8 74/jump-if-equal $ascii-length-ret/disp8
# ++s # ++s
81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 1/imm32 # add to EDX 81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 1/imm32 # add to EDX
# ++result # ++result
40/inc-EAX 40/inc-EAX
# loop # loop
eb/jump $ascii-length-loop/disp8 eb/jump $ascii-length-loop/disp8
$ascii-length-ret: $ascii-length-ret:
# return (result in EAX) # return (result in EAX)
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0

View File

@ -17,35 +17,35 @@
# Locals start from ESP-4 downwards. # Locals start from ESP-4 downwards.
== code == code
# instruction effective address operand displacement immediate # instruction effective address operand displacement immediate
# op subop mod rm32 base index scale r32 # 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 # 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 # prolog
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# call ascii-difference(argv[1], argv[2]) # call ascii-difference(argv[1], argv[2])
# push 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] # 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 # call
e8/call ascii-difference/disp32 e8/call ascii-difference/disp32
# discard args # 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
# exit(EAX) # exit(EAX)
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
b8/copy-to-EAX 1/imm32/exit b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8 cd/syscall 0x80/imm8
ascii-difference: # (s1, s2) : null-terminated ascii strings ascii-difference: # (s1, s2) : null-terminated ascii strings
# a = first letter of s1 (ECX) # 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 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 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX
# b = first letter of s2 (EDX) # 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 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 8b/copy 0/mod/indirect 1/rm32/ECX . . . 1/r32/ECX . . # copy *ECX to ECX
# a-b # a-b
29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX
c3/return c3/return
# vim:nowrap:textwidth=0 # vim:nowrap:textwidth=0