Bugfix fourteen: we need different address computation logic for code vs data labels. It's really about different categories of instructions having different address computation logic. This subtle distinction will make good error messages hard. But that's a problem for later. Now there's just one example program not translating.
4574 lines
228 KiB
Plaintext
4574 lines
228 KiB
Plaintext
# Assign addresses (co-ordinates) to instructions (landmarks) in a program
|
|
# (landscape).
|
|
# Use the addresses assigned to:
|
|
# a) replace labels
|
|
# b) add segment headers with addresses and offsets correctly filled in
|
|
#
|
|
# To build (from the subx/ directory):
|
|
# $ ./subx translate *.subx apps/survey.subx -o apps/survey
|
|
#
|
|
# The expected input is a stream of bytes with segment headers, comments and
|
|
# some interspersed labels.
|
|
# $ cat x
|
|
# == code 0x1
|
|
# l1:
|
|
# aa bb l1/imm8
|
|
# cc dd l2/disp32
|
|
# l2:
|
|
# ee foo/imm32
|
|
# == data 0x10
|
|
# foo:
|
|
# 00
|
|
#
|
|
# The output is the stream of bytes without segment headers or label definitions,
|
|
# and with label references replaced with numeric values/displacements.
|
|
#
|
|
# $ cat x |./subx run apps/assort
|
|
# ...ELF header bytes...
|
|
# # ELF header above will specify that code segment begins at this offset
|
|
# aa bb nn # some computed address
|
|
# cc dd nn nn nn nn # some computed displacement
|
|
# ee nn nn nn nn # some computed address
|
|
# # ELF header above will specify that data segment begins at this offset
|
|
# 00
|
|
#
|
|
# The ELF format has some persnickety constraints on the starting addresses of
|
|
# segments, so input headers are treated as guidelines and adjusted in the
|
|
# output.
|
|
|
|
== code
|
|
# instruction effective address register displacement immediate
|
|
# . op subop mod rm32 base index scale r32
|
|
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
|
|
|
Entry:
|
|
# Heap = new-segment(64KB)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
68/push 0x10000/imm32/64KB
|
|
# . . call
|
|
e8/call new-segment/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# initialize-trace-stream(256KB)
|
|
# . . push args
|
|
68/push 0x40000/imm32/256KB
|
|
# . . call
|
|
e8/call initialize-trace-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
|
|
# run tests if necessary, convert stdin if not
|
|
# . prolog
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# initialize heap
|
|
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
|
# . argc > 1
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP
|
|
7e/jump-if-lesser-or-equal $run-main/disp8
|
|
# . argv[1] == "test"
|
|
# . . push args
|
|
68/push "test"/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call kernel-string-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check result
|
|
3d/compare-EAX-and 1/imm32
|
|
75/jump-if-not-equal $run-main/disp8
|
|
# . run-tests()
|
|
e8/call run-tests/disp32
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
|
eb/jump $main:end/disp8
|
|
$run-main:
|
|
# - otherwise convert stdin
|
|
# convert(Stdin, Stdout)
|
|
# . . push args
|
|
68/push Stdout/imm32
|
|
68/push Stdin/imm32
|
|
# . . call
|
|
e8/call convert/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . syscall(exit, 0)
|
|
bb/copy-to-EBX 0/imm32
|
|
$main:end:
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
|
|
# data structures:
|
|
# segment-info: {address, file-offset, size} (12 bytes)
|
|
# segments: (address stream {string, segment-info}) (16 bytes per row)
|
|
# label-info: {segment-name, segment-offset, address} (12 bytes)
|
|
# labels: (address stream {string, label-info}) (16 bytes per row)
|
|
# these are all inefficient; use sequential scans for lookups
|
|
|
|
convert: # infile : (address buffered-file), out : (address buffered-file) -> <void>
|
|
# pseudocode
|
|
# var in : (address stream byte) = stream(4096)
|
|
# slurp(infile, in)
|
|
# var segments = new-stream(10 rows, 16 bytes each)
|
|
# var labels = new-stream(512 rows, 16 bytes each)
|
|
# compute-offsets(in, segments, labels)
|
|
# compute-addresses(segments, labels)
|
|
# rewind-stream(in)
|
|
# emit-output(in, out, segments, labels)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
51/push-ECX
|
|
52/push-EDX
|
|
56/push-ESI
|
|
# var segments/ECX = stream(10 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP
|
|
68/push 0xa0/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# var labels/EDX = stream(512 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP
|
|
68/push 0x2000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# var in/ESI = stream(4096 * 1)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x1000/imm32 # subtract from ESP
|
|
68/push 0x1000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI
|
|
#? # write(2/stderr, "slurp in\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "compute-offsets\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# slurp(infile, in)
|
|
# . . push args
|
|
56/push-ESI
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call slurp/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump in {{{
|
|
#? # . write(2/stderr, "in: ")
|
|
#? # . . push args
|
|
#? 68/push "in: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # write-stream(2/stderr, in)
|
|
#? # . . push args
|
|
#? 56/push-ESI
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(in)
|
|
#? # . . push args
|
|
#? 56/push-ESI
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
#? # write(2/stderr, "compute-offsets\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "compute-offsets\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# compute-offsets(in, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
56/push-ESI
|
|
# . . call
|
|
e8/call compute-offsets/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
#? # write(2/stderr, "compute-addresses\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "compute-addresses\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# compute-addresses(segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call compute-addresses/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x8/imm32 # add to ESP
|
|
# rewind-stream(in)
|
|
# . . push args
|
|
56/push-ESI
|
|
# . . call
|
|
e8/call rewind-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # write(2/stderr, "emit-output\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "emit-output\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
#? # dump labels->write {{{
|
|
#? # . write(2/stderr, "labels->write after rewinding input: ")
|
|
#? # . . push args
|
|
#? 68/push "labels->write after rewinding input: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . save EAX
|
|
#? 50/push-EAX
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . print-int32-buffered(Stderr, labels)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call print-int32-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "\n")
|
|
#? # . . push args
|
|
#? 68/push "\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# emit-output(in, out, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
56/push-ESI
|
|
# . . call
|
|
e8/call emit-output/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
# flush(out)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$convert:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x30a0/imm32 # add to ESP
|
|
# . restore registers
|
|
5e/pop-to-ESI
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-convert-computes-addresses:
|
|
# input:
|
|
# == code 0x1
|
|
# Entry:
|
|
# ab x/imm32
|
|
# == data 0x1000
|
|
# x:
|
|
# 01
|
|
#
|
|
# trace contains (in any order):
|
|
# label x is at address 0x1079
|
|
# segment code starts at address 0x74
|
|
# segment code has size 5
|
|
# segment data starts at address 0x1079
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-input-buffered-file+4)
|
|
# . . push args
|
|
b8/copy-to-EAX _test-input-buffered-file/imm32
|
|
05/add-to-EAX 4/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-buffered-file+4)
|
|
# . . push args
|
|
b8/copy-to-EAX _test-output-buffered-file/imm32
|
|
05/add-to-EAX 4/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "== code 0x1\n")
|
|
# . . push args
|
|
68/push "== code 0x1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "Entry:\n")
|
|
# . . push args
|
|
68/push "Entry:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ab x/imm32\n")
|
|
# . . push args
|
|
68/push "ab x/imm32\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "== data 0x1000\n")
|
|
# . . push args
|
|
68/push "== data 0x1000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "x:\n")
|
|
# . . push args
|
|
68/push "x:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "01\n")
|
|
# . . push args
|
|
68/push "01\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# convert(_test-input-buffered-file, _test-output-buffered-file)
|
|
# . . push args
|
|
68/push _test-output-buffered-file/imm32
|
|
68/push _test-input-buffered-file/imm32
|
|
# . . call
|
|
e8/call convert/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# check trace
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# . check-trace-contains("label 'x' is at address 0x00001079.", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-computes-addresses/0"/imm32
|
|
68/push "label 'x' is at address 0x00001079."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'code' starts at address 0x00000074.", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-computes-addresses/1"/imm32
|
|
68/push "segment 'code' starts at address 0x00000074."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'code' has size 0x00000005.", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-computes-addresses/2"/imm32
|
|
68/push "segment 'code' has size 0x00000005."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'data' starts at address 0x00001079.", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-computes-addresses/3"/imm32
|
|
68/push "segment 'data' starts at address 0x00001079."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
# global scratch space for compute-offsets in the data segment
|
|
== data
|
|
|
|
compute-offsets:file-offset: # int
|
|
0/imm32
|
|
compute-offsets:segment-offset: # int
|
|
0/imm32
|
|
compute-offsets:word-slice:
|
|
0/imm32/start
|
|
0/imm32/end
|
|
compute-offsets:segment-tmp: # slice
|
|
0/imm32/start
|
|
0/imm32/end
|
|
|
|
== code
|
|
|
|
compute-offsets: # in : (address stream), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# skeleton:
|
|
# for lines in 'in'
|
|
# for words in line
|
|
# switch word
|
|
# case 1
|
|
# case 2
|
|
# ...
|
|
# default
|
|
#
|
|
# pseudocode:
|
|
# curr-segment-name : (address string) = 0
|
|
# var line = new-stream(512, 1)
|
|
# while true # line loop
|
|
# clear-stream(line)
|
|
# read-line(in, line)
|
|
# if (line->write == 0) break # end of file
|
|
# while true # word loop
|
|
# word-slice = next-word(line)
|
|
# if slice-empty?(word-slice) # end of line
|
|
# break
|
|
# else if slice-starts-with?(word-slice, "#") # comment
|
|
# break # end of line
|
|
# else if slice-equal?(word-slice, "==")
|
|
# if curr-segment-name != 0
|
|
# seg = get-or-insert(segments, curr-segment-name)
|
|
# seg->size = *file-offset - seg->file-offset
|
|
# trace("segment '", curr-segment-name, "' has size ", seg->size)
|
|
# segment-tmp = next-word(line)
|
|
# curr-segment-name = slice-to-string(segment-tmp)
|
|
# if empty?(curr-segment-name)
|
|
# abort
|
|
# segment-tmp = next-word(line)
|
|
# if slice-empty?(segment-tmp)
|
|
# abort
|
|
# seg = get-or-insert(segments, curr-segment-name)
|
|
# seg->starting-address = parse-hex-int(segment-tmp)
|
|
# seg->file-offset = *file-offset
|
|
# trace("segment '", curr-segment-name, "' is at file offset ", seg->file-offset)
|
|
# segment-offset = 0
|
|
# break (next line)
|
|
# else if is-label?(word-slice)
|
|
# strip trailing ':' from word-slice
|
|
# x : (address label-info) = get-or-insert(labels, name)
|
|
# x->segment-name = curr-segment-name
|
|
# trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.")
|
|
# x->segment-offset = segment-offset
|
|
# trace("label '", word-slice, "' is at segment offset ", segment-offset, ".")
|
|
# # labels occupy no space, so no need to increment offsets
|
|
# else
|
|
# width = compute-width-of-slice(word-slice)
|
|
# *segment-offset += width
|
|
# *file-offset += width
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
52/push-EDX
|
|
53/push-EBX
|
|
56/push-ESI
|
|
57/push-EDI
|
|
# curr-segment-name/ESI = 0
|
|
31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI
|
|
# file-offset = 0
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:file-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice
|
|
# segment-offset = 0
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice
|
|
# line/ECX = new-stream(512, 1)
|
|
# . EAX = new-stream(512, 1)
|
|
# . . push args
|
|
68/push 1/imm32
|
|
68/push 0x200/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call new-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . line/ECX = EAX
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX
|
|
$compute-offsets:line-loop:
|
|
# clear-stream(line/ECX)
|
|
51/push-ECX
|
|
e8/call clear-stream/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# read-line(in, line/ECX)
|
|
51/push-ECX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
e8/call read-line/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# if (line->write == 0) break
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 84/jump-if-equal $compute-offsets:break-line-loop/disp32
|
|
#? # dump line {{{
|
|
#? # . write(2/stderr, "LL: ")
|
|
#? # . . push args
|
|
#? 68/push "LL: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # write-stream(2/stderr, line)
|
|
#? # . . push args
|
|
#? 51/push-ECX
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(line)
|
|
#? # . . push args
|
|
#? 51/push-ECX
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
$compute-offsets:word-loop:
|
|
# EDX = word-slice
|
|
ba/copy-to-EDX compute-offsets:word-slice/imm32
|
|
# next-word(line/ECX, word-slice/EDX)
|
|
52/push-EDX
|
|
51/push-ECX
|
|
e8/call next-word/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump word-slice and maybe curr-segment-name {{{
|
|
#? # . write(2/stderr, "w: ")
|
|
#? # . . push args
|
|
#? 68/push "w: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . save EAX
|
|
#? 50/push-EAX
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . write-slice-buffered(Stderr, word-slice)
|
|
#? # . . push args
|
|
#? 52/push-EDX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-slice-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . if (curr-segment-name == 0) print curr-segment-name
|
|
#? 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI
|
|
#? 74/jump-if-equal $compute-offsets:case-empty/disp8
|
|
#? # . write(2/stderr, "segment at start of word: ")
|
|
#? # . . push args
|
|
#? 68/push "segment at start of word: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-buffered(Stderr, curr-segment-name)
|
|
#? # . . push args
|
|
#? 56/push-ESI
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
$compute-offsets:case-empty:
|
|
# if slice-empty?(word/EDX) break
|
|
# . EAX = slice-empty?(word/EDX)
|
|
52/push-EDX
|
|
e8/call slice-empty?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32
|
|
$compute-offsets:case-comment:
|
|
# if slice-starts-with?(word-slice, "#") continue
|
|
68/push "#"/imm32
|
|
52/push-EDX
|
|
e8/call slice-starts-with?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32
|
|
$compute-offsets:case-segment-header:
|
|
# if (!slice-equal?(word-slice/EDX, "==")) goto next case
|
|
# . EAX = slice-equal?(word-slice/EDX, "==")
|
|
68/push "=="/imm32
|
|
52/push-EDX
|
|
e8/call slice-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX == 0) goto next case
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 84/jump-if-equal $compute-offsets:case-label/disp32
|
|
# if (curr-segment-name == 0) goto construct-next-segment
|
|
81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI
|
|
74/jump-if-equal $compute-offsets:construct-next-segment/disp8
|
|
# seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
56/push-ESI
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call get-or-insert/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# seg->size = file-offset - seg->file-offset
|
|
# . save ECX
|
|
51/push-ECX
|
|
# . EBX = *file-offset
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX
|
|
# . ECX = seg->file-offset
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX
|
|
# . EBX -= ECX
|
|
29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX
|
|
# . seg->size = EBX
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8)
|
|
# . restore ECX
|
|
59/pop-to-ECX
|
|
# trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-EBX
|
|
68/push "' has size "/imm32
|
|
56/push-ESI
|
|
68/push "segment '"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
$compute-offsets:construct-next-segment:
|
|
# next-word(line/ECX, segment-tmp)
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
51/push-ECX
|
|
e8/call next-word/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump curr-segment-name if not null (clobbering EAX) {{{
|
|
#? # . if (curr-segment-name == 0) goto update-curr-segment-name
|
|
#? 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI
|
|
#? 74/jump-if-equal $compute-offsets:update-curr-segment-name/disp8
|
|
#? # . write(2/stderr, "setting segment to: ")
|
|
#? # . . push args
|
|
#? 68/push "setting segment to: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . write-buffered(Stderr, curr-segment-name)
|
|
#? # . . push args
|
|
#? 56/push-ESI
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
$compute-offsets:update-curr-segment-name:
|
|
# curr-segment-name = slice-to-string(segment-tmp)
|
|
# . EAX = slice-to-string(Heap, segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call slice-to-string/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . curr-segment-name = EAX
|
|
89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI
|
|
# if empty?(curr-segment-name) abort
|
|
# . if (EAX == 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 84/jump-if-equal $compute-offsets:abort/disp32
|
|
# next-word(line/ECX, segment-tmp)
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
51/push-ECX
|
|
e8/call next-word/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# if slice-empty?(segment-tmp) abort
|
|
# . EAX = slice-empty?(segment-tmp)
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
e8/call slice-empty?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX != 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $compute-offsets:abort/disp32
|
|
# seg/EBX = get-or-insert(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
56/push-ESI
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call get-or-insert/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . EBX = EAX
|
|
89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX
|
|
# seg->address = parse-hex-int(segment-tmp)
|
|
# . EAX = parse-hex-int(segment-tmp)
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
e8/call parse-hex-int/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . seg->address = EAX
|
|
89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX
|
|
# seg->file-offset = *file-offset
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # copy *file-offset to EAX
|
|
89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4)
|
|
# trace-sssns("segment '", curr-segment-name, "' is at file offset ", seg->file-offset, "")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
50/push-EAX
|
|
68/push "' is at file offset "/imm32
|
|
56/push-ESI
|
|
68/push "segment '"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# segment-offset = 0
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *segment-offset
|
|
# break
|
|
e9/jump $compute-offsets:line-loop/disp32
|
|
$compute-offsets:case-label:
|
|
# if (!is-label?(word-slice/EDX)) goto next case
|
|
# . EAX = is-label?(word-slice/EDX)
|
|
# . . push args
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call is-label?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX == 0) goto next case
|
|
3d/compare-EAX-and 0/imm32
|
|
74/jump-if-equal $compute-offsets:case-default/disp8
|
|
# strip trailing ':' from word-slice
|
|
ff 1/subop/decrement 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # decrement *(EDX+4)
|
|
# x/EAX = leaky-get-or-insert-slice(labels, word-slice, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
52/push-EDX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
# . . call
|
|
e8/call leaky-get-or-insert-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
$compute-offsets:save-label-offset:
|
|
# x->segment-name = curr-segment-name
|
|
89/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to *EAX
|
|
# trace-slsss("label '" word-slice/EDX "' is in segment '" current-segment-name "'.")
|
|
# . . push args
|
|
68/push "'."/imm32
|
|
56/push-ESI
|
|
68/push "' is in segment '"/imm32
|
|
52/push-EDX
|
|
68/push "label '"/imm32
|
|
# . . call
|
|
e8/call trace-slsss/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# x->segment-offset = segment-offset
|
|
# . EBX = segment-offset
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:segment-offset/disp32 # copy *segment-offset to EBX
|
|
# . x->segment-offset = EBX
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EAX+4)
|
|
# trace-slsns("label '" word-slice/EDX "' is at segment offset " *segment-offset/EAX ".")
|
|
# . . EAX = file-offset
|
|
b8/copy-to-EAX compute-offsets:segment-offset/imm32
|
|
# . . EAX = *file-offset/EAX
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX
|
|
# . . push args
|
|
68/push "."/imm32
|
|
50/push-EAX
|
|
68/push "' is at segment offset "/imm32
|
|
52/push-EDX
|
|
68/push "label '"/imm32
|
|
# . . call
|
|
e8/call trace-slsns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $compute-offsets:word-loop/disp32
|
|
$compute-offsets:case-default:
|
|
# width/EAX = compute-width-of-slice(word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call compute-width-of-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# segment-offset += width
|
|
01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:segment-offset/disp32 # add EAX to *segment-offset
|
|
# file-offset += width
|
|
01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # add EAX to *file-offset
|
|
#? # dump segment-offset {{{
|
|
#? # . write(2/stderr, "segment-offset: ")
|
|
#? # . . push args
|
|
#? 68/push "segment-offset: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . save EAX
|
|
#? 50/push-EAX
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . print-int32-buffered(Stderr, segment-offset)
|
|
#? # . . push args
|
|
#? 52/push-EDX
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 # push *segment-offset
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call print-int32-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "\n")
|
|
#? # . . push args
|
|
#? 68/push "\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
e9/jump $compute-offsets:word-loop/disp32
|
|
$compute-offsets:break-line-loop:
|
|
# seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
56/push-ESI
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call get-or-insert/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# seg->size = file-offset - seg->file-offset
|
|
# . save ECX
|
|
51/push-ECX
|
|
# . EBX = *file-offset
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX
|
|
# . ECX = seg->file-offset
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX
|
|
# . EBX -= ECX
|
|
29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX
|
|
# . seg->size = EBX
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8)
|
|
# . restore ECX
|
|
59/pop-to-ECX
|
|
# trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".")
|
|
# . trace-sssns("segment '", curr-segment-name, "' has size ", EBX, ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-EBX
|
|
68/push "' has size "/imm32
|
|
56/push-ESI
|
|
68/push "segment '"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
$compute-offsets:end:
|
|
# . reclaim locals
|
|
# . restore registers
|
|
5f/pop-to-EDI
|
|
5e/pop-to-ESI
|
|
5b/pop-to-EBX
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
$compute-offsets:abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "'==' must be followed by segment name and segment-start\n"/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-EBX 1/imm32
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
test-compute-offsets:
|
|
# input:
|
|
# == code 0x1
|
|
# ab x/imm32 # skip comment
|
|
# == data 0x1000
|
|
# 00
|
|
# x:
|
|
# 34
|
|
#
|
|
# trace contains (in any order):
|
|
# segment 'code' is at file offset 0x0.
|
|
# segment 'code' has size 0x5.
|
|
# segment 'data' is at file offset 0x5.
|
|
# segment 'data' has size 0x2.
|
|
# label 'x' is in segment 'data'.
|
|
# label 'x' is at segment offset 0x1.
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# var segments/ECX = stream(2 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x20/imm32 # subtract from ESP
|
|
68/push 0x20/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# var labels/EDX = stream(2 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x20/imm32 # subtract from ESP
|
|
68/push 0x20/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# initialize input
|
|
# . write(_test-input-stream, "== code 0x1\n")
|
|
# . . push args
|
|
68/push "== code 0x1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ab x/imm32 # skip comment\n")
|
|
# . . push args
|
|
68/push "ab x/imm32 # skip comment\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "== data 0x1000\n")
|
|
# . . push args
|
|
68/push "== data 0x1000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "00\n")
|
|
# . . push args
|
|
68/push "00\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "x:\n")
|
|
# . . push args
|
|
68/push "x:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "34\n")
|
|
# . . push args
|
|
68/push "34\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# compute-offsets(_test-input-stream, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call compute-offsets/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check trace
|
|
# . check-trace-contains("segment 'code' is at file offset 0x00000000.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/0"/imm32
|
|
68/push "segment 'code' is at file offset 0x00000000."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'code' has size 0x00000005", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/1"/imm32
|
|
68/push "segment 'code' has size 0x00000005."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'data' is at file offset 0x00000005.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/2"/imm32
|
|
68/push "segment 'data' is at file offset 0x00000005."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'data' has size 0x00000002.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/3"/imm32
|
|
68/push "segment 'data' has size 0x00000002."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("label 'x' is in segment 'data'.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/4"/imm32
|
|
68/push "label 'x' is in segment 'data'."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("label 'x' is at segment offset 0x00000001.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets/5"/imm32
|
|
68/push "label 'x' is at segment offset 0x00000001."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-ints-equal(labels->write, 0x10, msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets-maintains-labels-write-index"/imm32
|
|
68/push 0x10/imm32/1-entry
|
|
ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
compute-addresses: # segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# pseudocode:
|
|
# srow : (address segment-info) = segments->data
|
|
# max = segments->data + segments->write
|
|
# num-segments = segments->write / 16
|
|
# starting-offset = 0x34 + (num-segments * 0x20)
|
|
# while true
|
|
# if (srow >= max) break
|
|
# s->file-offset += starting-offset
|
|
# s->address &= 0xfffff000 # clear last 12 bits for p_align
|
|
# s->address += (s->file-offset & 0x00000fff)
|
|
# trace-sssns("segment " s->key " starts at address " s->address)
|
|
# srow += 16 # row-size
|
|
# lrow : (address label-info) = labels->data
|
|
# max = labels->data + labels->write
|
|
# while true
|
|
# if (lrow >= max) break
|
|
# seg-name : (address string) = lrow->segment-name
|
|
# label-seg : (address segment-info) = get(segments, seg-name, row-size=16)
|
|
# lrow->address = label-seg->address + lrow->segment-offset
|
|
# trace-sssns("label " lrow->key " is at address " lrow->address)
|
|
# lrow += 16 # row-size
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
52/push-EDX
|
|
53/push-EBX
|
|
56/push-ESI
|
|
57/push-EDI
|
|
# ESI = segments
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
|
# starting-offset/EDI = 0x34 + (num-segments * 0x20) # make room for ELF headers
|
|
# . EDI = segments->write / 16 (row-size)
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 7/r32/EDI . . # copy *ESI to EDI
|
|
c1/shift 5/subop/logic-right 3/mod/direct 7/rm32/EDI . . . . . 4/imm8 # shift EDI right by 4 bits, while padding zeroes
|
|
# . EDI = (EDI * 0x20) + 0x34
|
|
c1/shift 4/subop/left 3/mod/direct 7/rm32/EDI . . . . . 5/imm8 # shift EDI left by 5 bits
|
|
81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 0x34/imm32 # add to EDI
|
|
# srow/EAX = segments->data
|
|
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX
|
|
# max/ECX = segments->data + segments->write
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX
|
|
01/add 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # add ESI to ECX
|
|
$compute-addresses:segment-loop:
|
|
# if (srow >= max) break
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
|
73/jump-if-greater-or-equal-unsigned $compute-addresses:segment-break/disp8
|
|
# srow->file-offset += starting-offset
|
|
01/add 1/mod/*+disp8 0/rm32/EAX . . . 7/r32/EDI 8/disp8 . # add EDI to *(EAX+8)
|
|
# clear last 12 bits of srow->address for p_align=0x1000
|
|
# . EDX = srow->address
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy *(EAX+4) to EDX
|
|
# . EDX &= 0xfffff000
|
|
81 4/subop/and 3/mod/direct 2/rm32/EDX . . . . . 0xfffff000/imm32 # bitwise and of EDX
|
|
# update last 12 bits from srow->file-offset
|
|
# . EBX = srow->file-offset
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy *(EAX+8) to EBX
|
|
# . EBX &= 0xfff
|
|
81 4/subop/and 3/mod/direct 3/rm32/EBX . . . . . 0x00000fff/imm32 # bitwise and of EBX
|
|
# . srow->address = EDX | EBX
|
|
09/or 3/mod/direct 2/rm32/EDX . . . 3/r32/EBX . . # EDX = bitwise OR with EBX
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy EDX to *(EAX+4)
|
|
# trace-sssns("segment " srow " starts at address " srow->address ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
52/push-EDX
|
|
68/push "' starts at address "/imm32
|
|
ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
|
68/push "segment '"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# srow += 16 # size of row
|
|
05/add-to-EAX 0x10/imm32
|
|
eb/jump $compute-addresses:segment-loop/disp8
|
|
$compute-addresses:segment-break:
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# ESI = labels
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
|
# lrow/EAX = labels->data
|
|
8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX
|
|
# max/ECX = labels->data + labels->write
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX
|
|
01/add 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # add ESI to ECX
|
|
$compute-addresses:label-loop:
|
|
# if (lrow >= max) break
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
|
0f 83/jump-if-greater-or-equal-unsigned $compute-addresses:end/disp32
|
|
#? # dump lrow->key {{{
|
|
#? # . write(2/stderr, "label: ")
|
|
#? # . . push args
|
|
#? 68/push "label: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, lrow->key)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# seg-name/EDX = lrow->segment-name
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy *EAX to EDX
|
|
#? # dump seg-name {{{
|
|
#? # . write(2/stderr, "compute-addresses: seg-name: ")
|
|
#? # . . push args
|
|
#? 68/push "seg-name: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, seg-name)
|
|
#? # . . push args
|
|
#? 52/push-EDX
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# label-seg/EDX : (address segment-info) = get(segments, seg-name, row-size=16)
|
|
# . save EAX
|
|
50/push-EAX
|
|
# . EAX = get(segments, seg-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
52/push-EDX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call get/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . EDX = EAX
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX
|
|
# . restore EAX
|
|
58/pop-to-EAX
|
|
# EBX = label-seg->address
|
|
8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX
|
|
# EBX += lrow->segment-offset
|
|
03/add 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # add *(EAX+8) to EBX
|
|
# lrow->address = EBX
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 0xc/disp8 . # copy EBX to *(EAX+12)
|
|
# trace-sssns("label " lrow->key " is at address " lrow->address ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-EBX
|
|
68/push "' is at address "/imm32
|
|
ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
|
68/push "label '"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# lrow += 16 # size of row
|
|
05/add-to-EAX 0x10/imm32
|
|
e9/jump $compute-addresses:label-loop/disp32
|
|
$compute-addresses:end:
|
|
# . restore registers
|
|
5f/pop-to-EDI
|
|
5e/pop-to-ESI
|
|
5b/pop-to-EBX
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-compute-addresses:
|
|
# input:
|
|
# segments:
|
|
# - 'a': {0x1000, 0, 5}
|
|
# - 'b': {0x2018, 5, 1}
|
|
# - 'c': {0x5444, 6, 12}
|
|
# labels:
|
|
# - 'l1': {'a', 3, 0}
|
|
# - 'l2': {'b', 0, 0}
|
|
#
|
|
# trace contains in any order (comments in parens):
|
|
# segment 'a' starts at address 0x00001094. (0x34 + 0x20 for each segment)
|
|
# segment 'b' starts at address 0x00002099. (0x018 discarded)
|
|
# segment 'c' starts at address 0x0000509a. (0x444 discarded)
|
|
# label 'l1' is at address 0x00001097. (0x1094 + segment-offset 3)
|
|
# label 'l2' is at address 0x00002099. (0x2099 + segment-offset 0)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . var segments/ECX = stream(10 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP
|
|
68/push 0xa0/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# . var labels/EDX = stream(512 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP
|
|
68/push 0x2000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# . stream-add4(segments, "a", 0x1000, 0, 5)
|
|
68/push 5/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1000/imm32/start-address
|
|
68/push "a"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(segments, "b", 0x2018, 5, 1)
|
|
68/push 1/imm32/segment-size
|
|
68/push 5/imm32/file-offset
|
|
68/push 0x2018/imm32/start-address
|
|
68/push "b"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(segments, "c", 0x5444, 6, 12)
|
|
68/push 0xc/imm32/segment-size
|
|
68/push 6/imm32/file-offset
|
|
68/push 0x5444/imm32/start-address
|
|
68/push "c"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(labels, "l1", "a", 3, 0)
|
|
68/push 0/imm32/label-address
|
|
68/push 3/imm32/segment-offset
|
|
68/push "a"/imm32/segment-name
|
|
68/push "l1"/imm32/label-name
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(labels, "l2", "b", 0, 0)
|
|
68/push 0/imm32/label-address
|
|
68/push 0/imm32/segment-offset
|
|
68/push "b"/imm32/segment-name
|
|
68/push "l2"/imm32/label-name
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# component under test
|
|
# . compute-addresses(segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call compute-addresses/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# checks
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# . check-trace-contains("segment 'a' starts at address 0x00001094.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/0"/imm32
|
|
68/push "segment 'a' starts at address 0x00001094."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'b' starts at address 0x00002099.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/1"/imm32
|
|
68/push "segment 'b' starts at address 0x00002099."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("segment 'c' starts at address 0x0000509a.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/2"/imm32
|
|
68/push "segment 'c' starts at address 0x0000509a."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("label 'l1' is at address 0x00001097.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/3"/imm32
|
|
68/push "label 'l1' is at address 0x00001097."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-trace-contains("label 'l2' is at address 0x00002099.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/4"/imm32
|
|
68/push "label 'l2' is at address 0x00002099."/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . check-ints-equal(labels->write, 0x20, msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses-maintains-labels-write-index"/imm32
|
|
68/push 0x20/imm32/2-entries
|
|
ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
emit-output: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# pseudocode:
|
|
# emit-headers(out, segments, labels)
|
|
# emit-segments(in, out, segments, labels)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
#? # write(2/stderr, "emit-headers\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "emit-headers\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# emit-headers(out, segments, labels)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call emit-headers/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
#? # write(2/stderr, "emit-segments\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "emit-segments\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# emit-segments(in, out, segments, labels)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call emit-segments/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
$emit-output:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
emit-segments: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# pseudocode:
|
|
# var offset-of-next-instruction = 0
|
|
# var line = new-stream(512, 1)
|
|
# line-loop:
|
|
# while true
|
|
# clear-stream(line)
|
|
# read-line(in, line)
|
|
# if (line->write == 0) break # end of file
|
|
# offset-of-next-instruction += num-bytes(line)
|
|
# while true
|
|
# var word-slice = next-word(line)
|
|
# if slice-empty?(word-slice) # end of line
|
|
# break
|
|
# if slice-starts-with?(word-slice, "#") # comment
|
|
# break
|
|
# if is-label?(word-slice) # no need for label declarations anymore
|
|
# goto line-loop # don't insert empty lines
|
|
# if slice-equal?(word-slice, "==") # no need for segment header lines
|
|
# goto line-loop # don't insert empty lines
|
|
# if length(word-slice) == 2
|
|
# write-slice-buffered(out, word-slice)
|
|
# write-buffered(out, " ")
|
|
# continue
|
|
# datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
|
|
# info = get-slice(labels, datum)
|
|
# if !string-equal?(info->segment-name, "code")
|
|
# if has-metadata?(word-slice, "disp8")
|
|
# abort
|
|
# if has-metadata?(word-slice, "imm8")
|
|
# abort
|
|
# emit(out, info->address, 4) # global variables always translate to absolute addresses
|
|
# # code segment cases
|
|
# else if has-metadata?(word-slice, "imm8")
|
|
# abort # label should never go to imm8
|
|
# else if has-metadata?(word-slice, "imm32")
|
|
# emit(out, info->address, 4)
|
|
# else if has-metadata?(word-slice, "disp8")
|
|
# value = info->offset - offset-of-next-instruction
|
|
# emit(out, value, 1)
|
|
# else if has-metadata?(word-slice, "disp32")
|
|
# value = info->offset - offset-of-next-instruction
|
|
# emit(out, value, 4)
|
|
# else
|
|
# abort
|
|
# write-buffered(out, "\n")
|
|
#
|
|
# registers:
|
|
# line: ECX
|
|
# word-slice: EDX
|
|
# offset-of-next-instruction: EBX
|
|
# datum: EDI
|
|
# info: ESI (inner loop only)
|
|
# temporaries: EAX, ESI (outer loop)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
52/push-EDX
|
|
53/push-EBX
|
|
56/push-ESI
|
|
57/push-EDI
|
|
# var line/ECX : (address stream byte) = stream(512)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP
|
|
68/push 0x200/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# var word-slice/EDX = {0, 0}
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# var datum/EDI = {0, 0}
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI
|
|
# offset-of-next-instruction/EBX = 0
|
|
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
|
$emit-segments:line-loop:
|
|
# clear-stream(line)
|
|
# . . push args
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# read-line(in, line)
|
|
# . . push args
|
|
51/push-ECX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call read-line/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump line {{{
|
|
#? # . write(2/stderr, "LL: ")
|
|
#? # . . push args
|
|
#? 68/push "LL: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # write-stream(2/stderr, line)
|
|
#? # . . push args
|
|
#? 51/push-ECX
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(line)
|
|
#? # . . push args
|
|
#? 51/push-ECX
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
$emit-segments:check-for-end-of-input:
|
|
# if (line->write == 0) break
|
|
81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX
|
|
0f 84/jump-if-equal $emit-segments:end/disp32
|
|
# offset-of-next-instruction += num-bytes(line)
|
|
# . EAX = num-bytes(line)
|
|
# . . push args
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . EBX += EAX
|
|
01/add 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # add EAX to EBX
|
|
$emit-segments:word-loop:
|
|
# next-word(line, word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump word-slice {{{
|
|
#? # . write(2/stderr, "w: ")
|
|
#? # . . push args
|
|
#? 68/push "w: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-slice-buffered(Stderr, word-slice)
|
|
#? # . . push args
|
|
#? 52/push-EDX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-slice-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
$emit-segments:check-for-end-of-line:
|
|
# if (slice-empty?(word-slice)) break
|
|
# . EAX = slice-empty?(word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call slice-empty?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:next-line/disp32
|
|
$emit-segments:check-for-comment:
|
|
# if (slice-starts-with?(word-slice, "#")) break
|
|
# . start/ESI = word-slice->start
|
|
8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI
|
|
# . c/EAX = *start
|
|
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
|
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL
|
|
# . if (EAX == '#') break
|
|
3d/compare-EAX-and 0x23/imm32/hash
|
|
0f 84/jump-if-equal $emit-segments:next-line/disp32
|
|
$emit-segments:check-for-label:
|
|
# if is-label?(word-slice) break
|
|
# . EAX = is-label?(word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call is-label?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:line-loop/disp32
|
|
$emit-segments:check-for-segment-header:
|
|
# if (slice-equal?(word-slice, "==")) break
|
|
# . EAX = slice-equal?(word-slice, "==")
|
|
# . . push args
|
|
68/push "=="/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call slice-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:line-loop/disp32
|
|
$emit-segments:2-character:
|
|
# if (length(word-slice) != 2) goto next check
|
|
# . EAX = length(word-slice)
|
|
8b/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy *(EDX+4) to EAX
|
|
2b/subtract 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # subtract *EDX from EAX
|
|
# . if (EAX != 2) goto next check
|
|
3d/compare-EAX-and 2/imm32
|
|
75/jump-if-not-equal $emit-segments:check-metadata/disp8
|
|
# write-slice-buffered(out, word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call write-slice-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write-buffered(out, " ")
|
|
# . . push args
|
|
68/push " "/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call write-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $emit-segments:word-loop/disp32
|
|
$emit-segments:check-metadata:
|
|
# - if we get here, 'word-slice' must be a label to be looked up
|
|
# datum/EDI = next-token-from-slice(word-slice->start, word-slice->end, "/")
|
|
# . . push args
|
|
57/push-EDI
|
|
68/push 0x2f/imm32/slash
|
|
ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4)
|
|
ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX
|
|
# . . call
|
|
e8/call next-token-from-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
#? # dump word-slice {{{
|
|
#? # . write(2/stderr, "datum: ")
|
|
#? # . . push args
|
|
#? 68/push "datum: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-slice-buffered(Stderr, word-slice)
|
|
#? # . . push args
|
|
#? 57/push-EDI
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-slice-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# info/ESI = get-slice(labels, datum, row-size=16)
|
|
# . EAX = get-slice(labels, datum, row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
57/push-EDI
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
# . . call
|
|
e8/call get-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . ESI = EAX
|
|
89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI
|
|
$emit-segments:check-global-variable:
|
|
#? # dump info->segment-name {{{
|
|
#? # . write(2/stderr, "aa: label segment: ")
|
|
#? # . . push args
|
|
#? 68/push "aa: label segment: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, info->segment-name)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# if string-equal?(info->segment-name, "code") goto code label checks
|
|
# . EAX = string-equal?(info->segment-name, "code")
|
|
# . . push args
|
|
68/push "code"/imm32
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI
|
|
# . . call
|
|
e8/call string-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) goto code label checks
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:check-code-label-for-imm8/disp32
|
|
$emit-segments:check-global-variable-for-disp8:
|
|
# if has-metadata?(word-slice, "disp8") abort
|
|
# . EAX = has-metadata?(word-slice, "disp8")
|
|
# . . push args
|
|
68/push "disp8"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32
|
|
$emit-segments:check-global-variable-for-imm8:
|
|
# if has-metadata?(word-slice, "imm8") abort
|
|
# . EAX = has-metadata?(word-slice, "imm8")
|
|
# . . push args
|
|
68/push "imm8"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32
|
|
$emit-segments:emit-global-variable:
|
|
# emit-hex(out, info->address, 4)
|
|
# . . push args
|
|
68/push 4/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call emit-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $emit-segments:word-loop/disp32
|
|
$emit-segments:check-code-label-for-imm8:
|
|
# if (has-metadata?(word-slice, "imm8")) abort
|
|
# . EAX = has-metadata?(EDX, "imm8")
|
|
# . . push args
|
|
68/push "imm8"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $emit-segments:imm8-abort/disp32
|
|
$emit-segments:check-code-label-for-imm32:
|
|
# if (!has-metadata?(word-slice, "imm32")) goto next check
|
|
# . EAX = has-metadata?(EDX, "imm32")
|
|
# . . push args
|
|
68/push "imm32"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX == 0) goto next check
|
|
3d/compare-EAX-and 0/imm32
|
|
74/jump-if-equal $emit-segments:check-code-label-for-disp8/disp8
|
|
#? # dump info->address {{{
|
|
#? # . write(2/stderr, "info->address: ")
|
|
#? # . . push args
|
|
#? 68/push "info->address: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . print-int32-buffered(Stderr, info->address)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8)
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call print-int32-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
$emit-segments:emit-code-label-imm32:
|
|
# emit-hex(out, info->address, 4)
|
|
# . . push args
|
|
68/push 4/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call emit-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $emit-segments:word-loop/disp32
|
|
$emit-segments:check-code-label-for-disp8:
|
|
# if (!has-metadata?(word-slice, "disp8")) goto next check
|
|
# . EAX = has-metadata?(EDX, "disp8")
|
|
# . . push args
|
|
68/push "disp8"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX == 0) goto next check
|
|
3d/compare-EAX-and 0/imm32
|
|
74/jump-if-equal $emit-segments:check-code-label-for-disp32/disp8
|
|
$emit-segments:emit-code-label-disp8:
|
|
# emit-hex(out, info->offset - offset-of-next-instruction, 1)
|
|
# . . push args
|
|
68/push 1/imm32
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
|
29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX
|
|
50/push-EAX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call emit-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $emit-segments:word-loop/disp32
|
|
$emit-segments:check-code-label-for-disp32:
|
|
# if (!has-metadata?(word-slice, "disp32")) abort
|
|
# . EAX = has-metadata?(EDX, "disp32")
|
|
# . . push args
|
|
68/push "disp32"/imm32
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call has-metadata?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX == 0) abort
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 84/jump-if-equal $emit-segments:abort/disp32
|
|
$emit-segments:emit-code-label-disp32:
|
|
# emit-hex(out, info->offset - offset-of-next-instruction, 4)
|
|
# . . push args
|
|
68/push 4/imm32
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
|
29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX
|
|
50/push-EAX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call emit-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# continue
|
|
e9/jump $emit-segments:word-loop/disp32
|
|
$emit-segments:next-line:
|
|
# write-buffered(out, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
# . . call
|
|
e8/call write-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# loop
|
|
e9/jump $emit-segments:line-loop/disp32
|
|
$emit-segments:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x21c/imm32 # add to ESP
|
|
# . restore registers
|
|
5f/pop-to-EDI
|
|
5e/pop-to-ESI
|
|
5b/pop-to-EBX
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
$emit-segments:global-variable-abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "emit-segments: must refer to global variables with /disp32 or /imm32"/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-EBX 1/imm32
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$emit-segments:imm8-abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "emit-segments: cannot refer to code labels with /imm8"/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-EBX 1/imm32
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$emit-segments:abort:
|
|
# print(stderr, "missing metadata in " word-slice)
|
|
# . _write(2/stderr, "missing metadata in word ")
|
|
# . . push args
|
|
68/push "emit-segments: missing metadata in "/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write-slice-buffered(Stderr, word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
68/push Stderr/imm32
|
|
# . . call
|
|
e8/call write-slice-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . flush(Stderr)
|
|
# . . push args
|
|
68/push Stderr/imm32
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-EBX 1/imm32
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
test-emit-segments-global-variable:
|
|
# global variables always convert to absolute addresses, regardless of metadata
|
|
#
|
|
# input:
|
|
# in:
|
|
# == code 0x1000
|
|
# ab cd ef gh
|
|
# ij x/disp32
|
|
# == data 0x2000
|
|
# 00
|
|
# x:
|
|
# 34
|
|
# segments:
|
|
# - 'code': {0x1074, 0, 9}
|
|
# - 'data': {0x2079, 5, 2}
|
|
# labels:
|
|
# - 'x': {'data', 1, 0x207a}
|
|
#
|
|
# output:
|
|
# ab cd ef gh
|
|
# ij 7a 20 00 00
|
|
# 00
|
|
# 34
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-buffered-file+4)
|
|
# . . push args
|
|
b8/copy-to-EAX _test-output-buffered-file/imm32
|
|
05/add-to-EAX 4/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . var segments/ECX = stream(10 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP
|
|
68/push 0xa0/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# . var labels/EDX = stream(512 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP
|
|
68/push 0x2000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# initialize input
|
|
# . write(_test-input-stream, "== code 0x1000\n")
|
|
# . . push args
|
|
68/push "== code 0x1000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ab cd ef gh\n")
|
|
# . . push args
|
|
68/push "ab cd ef gh\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ij x/disp32\n")
|
|
# . . push args
|
|
68/push "ij x/disp32\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "== data 0x2000\n")
|
|
# . . push args
|
|
68/push "== data 0x2000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "00\n")
|
|
# . . push args
|
|
68/push "00\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "x:\n")
|
|
# . . push args
|
|
68/push "x:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "34\n")
|
|
# . . push args
|
|
68/push "34\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . stream-add4(segments, "code", 0x1074, 0, 9)
|
|
68/push 9/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1074/imm32/start-address
|
|
68/push "code"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(segments, "data", 0x2079, 5, 2)
|
|
68/push 1/imm32/segment-size
|
|
68/push 5/imm32/file-offset
|
|
68/push 0x2079/imm32/start-address
|
|
68/push "data"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(labels, "x", "data", 1, 0x207a)
|
|
68/push 0x207a/imm32/label-address
|
|
68/push 1/imm32/segment-offset
|
|
68/push "data"/imm32/segment-name
|
|
68/push "x"/imm32/label-name
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
68/push _test-output-buffered-file/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call emit-segments/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
# checks
|
|
# . flush(_test-output-buffered-file)
|
|
# . . push args
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, _test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(_test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
# . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-global-variable/0"/imm32
|
|
68/push "ab cd ef gh "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "ij 7a 20 00 00 ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-global-variable/1"/imm32
|
|
68/push "ij 7a 20 00 00 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "00 ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-global-variable/2"/imm32
|
|
68/push "00 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "34 ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-global-variable/3"/imm32
|
|
68/push "34 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-emit-segments-code-label:
|
|
# labels usually convert to displacements
|
|
#
|
|
# input:
|
|
# in:
|
|
# == code 0x1000
|
|
# ab cd
|
|
# l1:
|
|
# ef gh
|
|
# ij l1/disp32
|
|
# segments:
|
|
# - 'code': {0x1054, 0, 9}
|
|
# labels:
|
|
# - 'l1': {'code', 2, 0x1056}
|
|
#
|
|
# output:
|
|
# ab cd
|
|
# ef gh
|
|
# ij f9 ff ff ff # -7
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-buffered-file+4)
|
|
# . . push args
|
|
b8/copy-to-EAX _test-output-buffered-file/imm32
|
|
05/add-to-EAX 4/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . var segments/ECX = stream(10 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP
|
|
68/push 0xa0/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# . var labels/EDX = stream(512 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP
|
|
68/push 0x2000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# initialize input
|
|
# . write(_test-input-stream, "== code 0x1000\n")
|
|
# . . push args
|
|
68/push "== code 0x1000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ab cd\n")
|
|
# . . push args
|
|
68/push "ab cd\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "l1:\n")
|
|
# . . push args
|
|
68/push "l1:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, " ef gh\n")
|
|
# . . push args
|
|
68/push " ef gh\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, " ij l1/disp32\n")
|
|
# . . push args
|
|
68/push " ij l1/disp32\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . stream-add4(segments, "code", 0x1054, 0, 9)
|
|
68/push 9/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1054/imm32/start-address
|
|
68/push "code"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(labels, "l1", "code", 2, 0x1056)
|
|
68/push 0x1056/imm32/label-address
|
|
68/push 2/imm32/segment-offset
|
|
68/push "code"/imm32/segment-name
|
|
68/push "l1"/imm32/label-name
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
68/push _test-output-buffered-file/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call emit-segments/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
# checks
|
|
# . flush(_test-output-buffered-file)
|
|
# . . push args
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, _test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(_test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
# . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label/0"/imm32
|
|
68/push "ab cd "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label/1"/imm32
|
|
68/push "ef gh "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label/2"/imm32
|
|
68/push "ij f9 ff ff ff "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-emit-segments-code-label-absolute:
|
|
# labels can also convert to absolute addresses
|
|
#
|
|
# input:
|
|
# in:
|
|
# == code 0x1000
|
|
# ab cd
|
|
# l1:
|
|
# ef gh
|
|
# ij l1/imm32
|
|
# segments:
|
|
# - 'code': {0x1054, 0, 9}
|
|
# labels:
|
|
# - 'l1': {'code', 2, 0x1056}
|
|
#
|
|
# output:
|
|
# ab cd
|
|
# ef gh
|
|
# ij 56 10 00 00
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-buffered-file+4)
|
|
# . . push args
|
|
b8/copy-to-EAX _test-output-buffered-file/imm32
|
|
05/add-to-EAX 4/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . var segments/ECX = stream(10 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP
|
|
68/push 0xa0/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
# . var labels/EDX = stream(512 * 16)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP
|
|
68/push 0x2000/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# initialize input
|
|
# . write(_test-input-stream, "== code 0x1000\n")
|
|
# . . push args
|
|
68/push "== code 0x1000\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "ab cd\n")
|
|
# . . push args
|
|
68/push "ab cd\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, "l1:\n")
|
|
# . . push args
|
|
68/push "l1:\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, " ef gh\n")
|
|
# . . push args
|
|
68/push " ef gh\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . write(_test-input-stream, " ij l1/imm32\n")
|
|
# . . push args
|
|
68/push " ij l1/imm32\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . stream-add4(segments, "code", 0x1054, 0, 9)
|
|
68/push 9/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1054/imm32/start-address
|
|
68/push "code"/imm32/segment-name
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# . stream-add4(labels, "l1", "code", 2, 0x1056)
|
|
68/push 0x1056/imm32/label-address
|
|
68/push 2/imm32/segment-offset
|
|
68/push "code"/imm32/segment-name
|
|
68/push "l1"/imm32/label-name
|
|
52/push-EDX
|
|
# . . call
|
|
e8/call stream-add4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
68/push _test-output-buffered-file/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call emit-segments/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP
|
|
# checks
|
|
# . flush(_test-output-buffered-file)
|
|
# . . push args
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, _test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . rewind-stream(_test-output-stream)
|
|
#? # . . push args
|
|
#? 68/push _test-output-stream/imm32
|
|
#? # . . call
|
|
#? e8/call rewind-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # }}}
|
|
# . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label-absolute/0"/imm32
|
|
68/push "ab cd "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label-absolute/1"/imm32
|
|
68/push "ef gh "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label-absolute/2"/imm32
|
|
68/push "ij 56 10 00 00 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
emit-headers: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# pseudocode:
|
|
# emit-elf-header(out, segments, labels)
|
|
# curr-segment = segments->data
|
|
# max = segments->data + segments->write
|
|
# while true
|
|
# if (curr-segment >= max) break
|
|
# emit-elf-program-header-entry(out, curr-segment)
|
|
# curr-segment += 16 # size of a row
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
#? # write(2/stderr, "emit-elf-header\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "emit-elf-header\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# emit-elf-header(out, segments, labels)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call emit-elf-header/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# EAX = segments
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX
|
|
# ECX = segments->write
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX
|
|
# curr-segment/EAX = segments->data
|
|
8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 0xc/disp8 . # copy EAX+12 to EAX
|
|
# max/ECX = segments->data + segments->write
|
|
01/add 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to ECX
|
|
$emit-headers:loop:
|
|
# if (curr-segment >= max) break
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
|
0f 83/jump-if-greater-or-equal-unsigned $emit-headers:end/disp32
|
|
#? # dump curr-segment->name {{{
|
|
#? # . write(2/stderr, "about to emit ph entry: segment->name: ")
|
|
#? # . . push args
|
|
#? 68/push "about to emit ph entry: segment->name: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . save EAX
|
|
#? 50/push-EAX
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . print-int32-buffered(Stderr, &curr-segment)
|
|
#? # . . push args
|
|
#? 50/push-EAX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call print-int32-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, " -> ")
|
|
#? # . . push args
|
|
#? 68/push " -> "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . print-int32-buffered(Stderr, curr-segment->name)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call print-int32-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "\n")
|
|
#? # . . push args
|
|
#? 68/push "\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
#? # write(2/stderr, "emit-segment-header\n") {{{
|
|
#? # . . push args
|
|
#? 68/push "emit-segment-header\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# emit-elf-program-header-entry(out, curr-segment)
|
|
# . . push args
|
|
50/push-EAX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call emit-elf-program-header-entry/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# curr-segment += 16 # size of a row
|
|
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0x10/imm32 # add to EAX
|
|
e9/jump $emit-headers:loop/disp32
|
|
$emit-headers:end:
|
|
# . restore registers
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
emit-elf-header: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info})
|
|
# pseudocode
|
|
# *Elf_e_entry = get(labels, "Entry")->address
|
|
# *Elf_e_phnum = segments->write / 16 # size of a row
|
|
# emit-hex-array(out, Elf_header)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
52/push-EDX # just because we need to call idiv
|
|
# *Elf_e_entry = get(labels, "Entry")->address
|
|
# . EAX = labels
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX
|
|
# . label-info/EAX = get(labels, "Entry", row-size=16)
|
|
# . . push args
|
|
68/push 0x10/imm32/row-size
|
|
68/push "Entry"/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call get/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . EAX = label-info->address
|
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 8/disp8 . # copy *(EAX+8) to EAX
|
|
# . *Elf_e_entry = EAX
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_entry/disp32 # copy EAX to *Elf_e_entry
|
|
# *Elf_e_phnum = segments->write / 0x10
|
|
# . EAX = segments
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX
|
|
# . len/EAX = segments->write
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX
|
|
# . EAX = len / 0x10 (destroying EDX)
|
|
b9/copy-to-ECX 0x10/imm32
|
|
31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX
|
|
f7 7/subop/idiv 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX
|
|
# . *Elf_e_phnum = EAX
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_phnum/disp32 # copy EAX to *Elf_e_phnum
|
|
# emit-hex-array(out, Elf_header)
|
|
# . . push args
|
|
68/push Elf_header/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call emit-hex-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
$emit-elf-header:end:
|
|
# . restore registers
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
emit-elf-program-header-entry: # out : (address buffered-file), curr-segment : (address {string, segment-info})
|
|
# pseudocode:
|
|
# *Elf_p_offset = curr-segment->file-offset
|
|
# *Elf_p_vaddr = curr-segment->address
|
|
# *Elf_p_paddr = curr-segment->address
|
|
# *Elf_p_filesz = curr-segment->size
|
|
# *Elf_p_memsz = curr-segment->size
|
|
# if curr-segment->name == "code"
|
|
# *Elf_p_flags = 5 # r-x
|
|
# else
|
|
# *Elf_p_flags = 6 # rw-
|
|
# emit-hex-array(out, Elf_program_header_entry)
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
56/push-ESI
|
|
# ESI = curr-segment
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
|
# *Elf_p_offset = curr-segment->file-offset
|
|
# . EAX = curr-segment->file-offset
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX
|
|
# . *Elf_p_offset = EAX
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_offset/disp32 # copy EAX to *Elf_p_offset
|
|
# *Elf_p_vaddr = curr-segment->address
|
|
# . EAX = curr-segment->address
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
|
# . *Elf_p_vaddr = EAX
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_vaddr/disp32 # copy EAX to *Elf_p_vaddr
|
|
# *Elf_p_paddr = curr-segment->address
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_paddr/disp32 # copy EAX to *Elf_p_paddr
|
|
# *Elf_p_filesz = curr-segment->size
|
|
# . EAX = curr-segment->size
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy *(ESI+12) to EAX
|
|
# . *Elf_p_filesz = EAX
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_filesz/disp32 # copy EAX to *Elf_p_filesz
|
|
# *Elf_p_memsz = curr-segment->size
|
|
89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_memsz/disp32 # copy EAX to *Elf_p_memsz
|
|
# if (!string-equal?(curr-segment->name, "code") goto next check
|
|
# . EAX = curr-segment->name
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
|
# . EAX = string-equal?(curr-segment->name, "code")
|
|
# . . push args
|
|
68/push "code"/imm32
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call string-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX == 0) goto next check
|
|
3d/compare-EAX-and 0/imm32
|
|
74/jump-if-equal $emit-elf-program-header-entry:data/disp8
|
|
# *Elf_p_flags = r-x
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 5/imm32 # copy to *Elf_p_flags
|
|
eb/jump $emit-elf-program-header-entry:really-emit/disp8
|
|
$emit-elf-program-header-entry:data:
|
|
# otherwise *Elf_p_flags = rw-
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 6/imm32 # copy to *Elf_p_flags
|
|
$emit-elf-program-header-entry:really-emit:
|
|
# emit-hex-array(out, Elf_program_header_entry)
|
|
# . . push args
|
|
68/push Elf_program_header_entry/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call emit-hex-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
$emit-elf-program-header-entry:end:
|
|
# . restore registers
|
|
5e/pop-to-ESI
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
# - some helpers for tests
|
|
|
|
stream-add4: # in : (address stream byte), key : address, val1 : address, val2 : address, val3 : address
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
50/push-EAX
|
|
51/push-ECX
|
|
52/push-EDX
|
|
56/push-ESI
|
|
# ESI = in
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
|
# curr/EAX = in->data + in->write
|
|
# . EAX = in->write
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
|
# . EAX = ESI+EAX+12
|
|
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
|
|
# max/EDX = in->data + in->length
|
|
# . EDX = in->length
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX
|
|
# . EDX = ESI+EDX+12
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ESI+EDX+12 to EDX
|
|
# if (curr >= max) abort
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX
|
|
73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8
|
|
# *curr = key
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX
|
|
89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX
|
|
# curr += 4
|
|
05/add-to-EAX 4/imm32
|
|
# if (curr >= max) abort
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX
|
|
73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8
|
|
# *curr = val1
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX
|
|
89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX
|
|
# curr += 4
|
|
05/add-to-EAX 4/imm32
|
|
# if (curr >= max) abort
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX
|
|
73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8
|
|
# *curr = val2
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX
|
|
89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX
|
|
# curr += 4
|
|
05/add-to-EAX 4/imm32
|
|
# if (curr >= max) abort
|
|
39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX
|
|
73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8
|
|
# *curr = val3
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x18/disp8 . # copy *(EBP+24) to ECX
|
|
89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX
|
|
# in->write += 16
|
|
81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 0x10/imm32 # add to *ESI
|
|
$stream-add4:end:
|
|
# . restore registers
|
|
5e/pop-to-ESI
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
$stream-add4:abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "overflow in stream-add4\n"/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-EBX 1/imm32
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
# some variants of 'trace' that take multiple arguments in different combinations of types:
|
|
# n: int
|
|
# c: character [4-bytes, will eventually be UTF-8]
|
|
# s: (address string)
|
|
# l: (address slice)
|
|
# one gotcha: 's5' must not be empty
|
|
|
|
trace-sssns: # s1 : (address string), s2 : (address string), s3 : (address string), n4 : int, s5 : (address string)
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# write(*Trace-stream, s1)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s2)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s3)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# print-int32(*Trace-stream, n4)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call print-int32/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# trace(s5) # implicitly adds a newline and finalizes the trace line
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24)
|
|
# . . call
|
|
e8/call trace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$trace-sssns:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-trace-sssns:
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . *Trace-stream->write = 0
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX
|
|
# trace-sssns("A" "b" "c " 3 " e")
|
|
# . . push args
|
|
68/push " e"/imm32
|
|
68/push 3/imm32
|
|
68/push "c "/imm32
|
|
68/push "b"/imm32
|
|
68/push "A"/imm32
|
|
# . . call
|
|
e8/call trace-sssns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check-trace-contains("Abc 0x00000003 e")
|
|
# . . push args
|
|
68/push "F - test-trace-sssns"/imm32
|
|
68/push "Abc 0x00000003 e"/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
trace-snsns: # s1 : (address string), n2 : int, s3 : (address string), n4 : int, s5 : (address string)
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# write(*Trace-stream, s1)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# print-int32(*Trace-stream, n2)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call print-int32/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s3)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# print-int32(*Trace-stream, n4)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call print-int32/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# trace(s5) # implicitly adds a newline and finalizes the trace line
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24)
|
|
# . . call
|
|
e8/call trace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$trace-snsns:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-trace-snsns:
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . *Trace-stream->write = 0
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX
|
|
# trace-snsns("A " 2 " c " 3 " e")
|
|
# . . push args
|
|
68/push " e"/imm32
|
|
68/push 3/imm32
|
|
68/push " c "/imm32
|
|
68/push 2/imm32
|
|
68/push "A "/imm32
|
|
# . . call
|
|
e8/call trace-snsns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check-trace-contains("Abc 0x00000003 e")
|
|
# . . push args
|
|
68/push "F - test-trace-snsns"/imm32
|
|
68/push "A 0x00000002 c 0x00000003 e"/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
trace-slsls: # s1 : (address string), l2 : (address slice), s3 : (address string), l4 : (address slice), s5 : (address string)
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# write(*Trace-stream, s1)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write-slice(*Trace-stream, l2)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s3)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write-slice(*Trace-stream, l4)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# trace(s5) # implicitly adds a newline and finalizes the trace line
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24)
|
|
# . . call
|
|
e8/call trace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$trace-slsls:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-trace-slsls:
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . *Trace-stream->write = 0
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX
|
|
# (EAX..ECX) = "b"
|
|
b8/copy-to-EAX "b"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX 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
|
|
05/add-to-EAX 4/imm32
|
|
# var b/EBX : (address slice) = {EAX, ECX}
|
|
51/push-ECX
|
|
50/push-EAX
|
|
89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX
|
|
# (EAX..ECX) = "d"
|
|
b8/copy-to-EAX "d"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX 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
|
|
05/add-to-EAX 4/imm32
|
|
# var d/EDX : (address slice) = {EAX, ECX}
|
|
51/push-ECX
|
|
50/push-EAX
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# trace-slsls("A" b "c" d "e")
|
|
# . . push args
|
|
68/push "e"/imm32
|
|
52/push-EDX
|
|
68/push "c"/imm32
|
|
53/push-EBX
|
|
68/push "A"/imm32
|
|
# . . call
|
|
e8/call trace-slsls/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check-trace-contains("Abcde")
|
|
# . . push args
|
|
68/push "F - test-trace-slsls"/imm32
|
|
68/push "Abcde"/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
trace-slsns: # s1 : (address string), l2 : (address slice), s3 : (address string), n4 : int, s5 : (address string)
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# write(*Trace-stream, s1)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write-slice(*Trace-stream, l2)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s3)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# print-int32(*Trace-stream, n4)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call print-int32/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# trace(s5) # implicitly adds a newline and finalizes the trace line
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24)
|
|
# . . call
|
|
e8/call trace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$trace-slsns:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-trace-slsns:
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . *Trace-stream->write = 0
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX
|
|
# (EAX..ECX) = "b"
|
|
b8/copy-to-EAX "b"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX 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
|
|
05/add-to-EAX 4/imm32
|
|
# var b/EBX : (address slice) = {EAX, ECX}
|
|
51/push-ECX
|
|
50/push-EAX
|
|
89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX
|
|
# trace-slsls("A" b "c " 3 " e")
|
|
# . . push args
|
|
68/push " e"/imm32
|
|
68/push 3/imm32
|
|
68/push "c "/imm32
|
|
53/push-EBX
|
|
68/push "A"/imm32
|
|
# . . call
|
|
e8/call trace-slsns/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check-trace-contains("Abc 0x00000003 e")
|
|
# . . push args
|
|
68/push "F - test-trace-slsls"/imm32
|
|
68/push "Abc 0x00000003 e"/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
trace-slsss: # s1 : (address string), l2 : (address slice), s3 : (address string), s4 : (address string), s5 : (address string)
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# write(*Trace-stream, s1)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write-slice(*Trace-stream, l2)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s3)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# write(*Trace-stream, s4)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20)
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# trace(s5) # implicitly adds a newline and finalizes the trace line
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24)
|
|
# . . call
|
|
e8/call trace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$trace-slsss:end:
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-trace-slsss:
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . *Trace-stream->write = 0
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX
|
|
# (EAX..ECX) = "b"
|
|
b8/copy-to-EAX "b"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX 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
|
|
05/add-to-EAX 4/imm32
|
|
# var b/EBX : (address slice) = {EAX, ECX}
|
|
51/push-ECX
|
|
50/push-EAX
|
|
89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX
|
|
# trace-slsss("A" b "c" "d" "e")
|
|
# . . push args
|
|
68/push "e"/imm32
|
|
68/push "d"/imm32
|
|
68/push "c"/imm32
|
|
53/push-EBX
|
|
68/push "A"/imm32
|
|
# . . call
|
|
e8/call trace-slsss/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP
|
|
#? # dump *Trace-stream {{{
|
|
#? # . write(2/stderr, "^")
|
|
#? # . . push args
|
|
#? 68/push "^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write-stream(2/stderr, *Trace-stream)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# check-trace-contains("Abcde")
|
|
# . . push args
|
|
68/push "F - test-trace-slsss"/imm32
|
|
68/push "Abcde"/imm32
|
|
# . . call
|
|
e8/call check-trace-contains/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
num-bytes: # line : (address stream) -> EAX : int
|
|
# pseudocode:
|
|
# result = 0
|
|
# while true
|
|
# var word-slice = next-word(line)
|
|
# if slice-empty?(word-slice) # end of line
|
|
# break
|
|
# if slice-starts-with?(word-slice, "#") # comment
|
|
# break
|
|
# if is-label?(word-slice) # no need for label declarations anymore
|
|
# break
|
|
# if slice-equal?(word-slice, "==")
|
|
# break # no need for segment header lines
|
|
# result += compute-width(word-slice)
|
|
# return result
|
|
#
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# . save registers
|
|
51/push-ECX
|
|
52/push-EDX
|
|
53/push-EBX
|
|
# var result/EAX = 0
|
|
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
|
# var word-slice/ECX = {0, 0}
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
|
|
#? # dump line {{{
|
|
#? # . write(2/stderr, "LL: ")
|
|
#? # . . push args
|
|
#? 68/push "LL: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # write-stream(2/stderr, line)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
# . rewind-stream(line)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call rewind-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
$num-bytes:loop:
|
|
# next-word(line, word-slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # dump word-slice {{{
|
|
#? # . write(2/stderr, "AA: ")
|
|
#? # . . push args
|
|
#? 68/push "AA: "/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . clear-stream(Stderr+4)
|
|
#? # . . save EAX
|
|
#? 50/push-EAX
|
|
#? # . . push args
|
|
#? b8/copy-to-EAX Stderr/imm32
|
|
#? 05/add-to-EAX 4/imm32
|
|
#? 50/push-EAX
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . . restore EAX
|
|
#? 58/pop-to-EAX
|
|
#? # . write-slice-buffered(Stderr, word-slice)
|
|
#? # . . push args
|
|
#? 51/push-ECX
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-slice-buffered/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . flush(Stderr)
|
|
#? # . . push args
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call flush/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
#? # . write(2/stderr, "$\n")
|
|
#? # . . push args
|
|
#? 68/push "$\n"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # }}}
|
|
$num-bytes:check0:
|
|
# if (slice-empty?(word-slice)) break
|
|
# . save result
|
|
50/push-EAX
|
|
# . EAX = slice-empty?(word-slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call slice-empty?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
# . restore result now that ZF is set
|
|
58/pop-to-EAX
|
|
75/jump-if-not-equal $num-bytes:end/disp8
|
|
$num-bytes:check-for-comment:
|
|
# if (slice-starts-with?(word-slice, "#")) break
|
|
# . start/EDX = word-slice->start
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
|
|
# . c/EBX = *start
|
|
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
|
8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 3/r32/BL . . # copy byte at *EDX to BL
|
|
# . if (EBX == '#') break
|
|
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x23/imm32/hash # compare EBX
|
|
74/jump-if-equal $num-bytes:end/disp8
|
|
$num-bytes:check-for-label:
|
|
# if (slice-ends-with?(word-slice, ":")) break
|
|
# . end/EDX = word-slice->end
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX
|
|
# . c/EBX = *(end-1)
|
|
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
|
|
8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 3/r32/BL -1/disp8 . # copy byte at *ECX to BL
|
|
# . if (EBX == ':') break
|
|
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x3a/imm32/colon # compare EBX
|
|
74/jump-if-equal $num-bytes:end/disp8
|
|
$num-bytes:check-for-segment-header:
|
|
# if (slice-equal?(word-slice, "==")) break
|
|
# . push result
|
|
50/push-EAX
|
|
# . EAX = slice-equal?(word-slice, "==")
|
|
# . . push args
|
|
68/push "=="/imm32
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call slice-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . if (EAX != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
# . restore result now that ZF is set
|
|
58/pop-to-EAX
|
|
75/jump-if-not-equal $num-bytes:end/disp8
|
|
$num-bytes:loop-body:
|
|
# result += compute-width-of-slice(word-slice)
|
|
# . copy result to EDX
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX
|
|
# . EAX = compute-width-of-slice(word-slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call compute-width-of-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . EAX += result
|
|
01/add 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to EAX
|
|
e9/jump $num-bytes:loop/disp32
|
|
$num-bytes:end:
|
|
# . rewind-stream(line)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call rewind-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# . restore registers
|
|
5b/pop-to-EBX
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-handles-empty-string:
|
|
# if a line starts with '#', return 0
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# no contents in input
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-handles-empty-string"/imm32
|
|
68/push 0/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-ignores-comments:
|
|
# if a line starts with '#', return 0
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "# abcd")
|
|
# . . push args
|
|
68/push "# abcd"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-ignores-comments"/imm32
|
|
68/push 0/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-ignores-labels:
|
|
# if the first word ends with ':', return 0
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "ab: # cd")
|
|
# . . push args
|
|
68/push "ab: # cd"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-ignores-labels"/imm32
|
|
68/push 0/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-ignores-segment-headers:
|
|
# if the first word is '==', return 0
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "== ab cd")
|
|
# . . push args
|
|
68/push "== ab cd"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-ignores-segment-headers"/imm32
|
|
68/push 0/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-counts-words-by-default:
|
|
# without metadata, count words
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "ab cd ef")
|
|
# . . push args
|
|
68/push "ab cd ef"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 3, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-counts-words-by-default"/imm32
|
|
68/push 3/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-ignores-trailing-comment:
|
|
# trailing comments appropriately ignored
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "ab cd # ef")
|
|
# . . push args
|
|
68/push "ab cd # ef"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 2, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-ignores-trailing-comment"/imm32
|
|
68/push 2/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-num-bytes-handles-imm32:
|
|
# if a word has the /imm32 metadata, count it as 4 bytes
|
|
# . prolog
|
|
55/push-EBP
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# setup
|
|
# . clear-stream(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . clear-stream(_test-output-stream)
|
|
# . . push args
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input
|
|
# . write(_test-input-stream, "ab cd/imm32 ef")
|
|
# . . push args
|
|
68/push "ab cd/imm32 ef"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# EAX = num-bytes(_test-input-stream)
|
|
# . . push args
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call num-bytes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# check-ints-equal(EAX, 6, msg)
|
|
# . . push args
|
|
68/push "F - test-num-bytes-handles-imm32"/imm32
|
|
68/push 6/imm32/true
|
|
50/push-EAX
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
== data
|
|
|
|
Segment-size:
|
|
0x1000/imm32/4KB
|
|
|
|
# This block of bytes gets copied to the start of the output ELF file, with
|
|
# some fields filled in.
|
|
# http://www.sco.com/developers/gabi/latest/ch4.eheader.html
|
|
Elf_header:
|
|
# - length
|
|
0x34/imm32
|
|
# - data
|
|
$e_ident:
|
|
7f 45/E 4c/L 46/F
|
|
01/32-bit 01/little-endian 01/file-version 00/no-os-extensions
|
|
00 00 00 00 00 00 00 00 # 8 bytes of padding
|
|
$e_type:
|
|
02 00
|
|
$e_machine:
|
|
03 00
|
|
$e_version:
|
|
1/imm32
|
|
Elf_e_entry:
|
|
0x09000000/imm32 # approximate default; must be updated
|
|
$e_phoff:
|
|
0x34/imm32 # offset for the 'program header table' containing segment headers
|
|
$e_shoff:
|
|
0/imm32 # no sections
|
|
$e_flags:
|
|
0/imm32 # unused
|
|
$e_ehsize:
|
|
0x34 00
|
|
$e_phentsize:
|
|
0x20 00
|
|
Elf_e_phnum:
|
|
00 00 # number of segments; must be updated
|
|
$e_shentsize:
|
|
00 00 # no sections
|
|
$e_shnum:
|
|
00 00
|
|
$e_shstrndx:
|
|
00 00
|
|
|
|
# This block of bytes gets copied after the Elf_header once for each segment.
|
|
# Some fields need filling in each time.
|
|
# https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html
|
|
Elf_program_header_entry:
|
|
# - length
|
|
0x20/imm32
|
|
# - data
|
|
$p_type:
|
|
1/imm32/PT_LOAD
|
|
Elf_p_offset:
|
|
0/imm32 # byte offset in the file at which a segment begins; must be updated
|
|
Elf_p_vaddr:
|
|
0/imm32 # starting address to store the segment at before running the program
|
|
Elf_p_paddr:
|
|
0/imm32 # should have same value as Elf_p_vaddr
|
|
Elf_p_filesz:
|
|
0/imm32
|
|
Elf_p_memsz:
|
|
0/imm32 # should have same value as Elf_p_filesz
|
|
Elf_p_flags:
|
|
6/imm32/rw- # read/write/execute permissions for the segment; must be updated for the code segment
|
|
$p_align:
|
|
# we hold this constant; changing it will require adjusting the way we
|
|
# compute the starting address for each segment
|
|
0x1000/imm32
|
|
|
|
# . . vim:nowrap:textwidth=0
|