827dd4a7fe
One less error that's only in the bootstrap phase. On the other hand, for simplicity I got rid of the ability to override the Entry label. One less special case, but we're also going further from the ability to run subsets of layers. We haven't really been exercising it for a long time, though (commit 7842, March 2021 when we made baremetal the default).
4694 lines
243 KiB
Plaintext
4694 lines
243 KiB
Plaintext
# Assign addresses (co-ordinates) to instructions (landmarks) in a program
|
|
# (landscape).
|
|
# Use the addresses assigned to:
|
|
# a) replace labels
|
|
# b) add an ELF header and segment headers with addresses and offsets correctly filled in
|
|
#
|
|
# To build:
|
|
# $ bootstrap/bootstrap translate [01]*.subx subx-params.subx survey_elf.subx -o survey_elf
|
|
#
|
|
# 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 |bootstrap/bootstrap run survey_elf
|
|
# ...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: # run tests if necessary, convert stdin if not
|
|
# . prologue
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
|
|
# Heap = new-segment(Heap-size)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size
|
|
# . . 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(Trace-size)
|
|
# . . push args
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-size/disp32 # push *Heap-size
|
|
# . . call
|
|
e8/call initialize-trace-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
|
|
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
|
# if (argc <= 1) goto interactive
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
|
|
7e/jump-if-<= $subx-survey-main:interactive/disp8
|
|
# if (!kernel-string-equal?(argv[1], "test")) goto interactive
|
|
# . eax = kernel-string-equal?(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
|
|
# . if (eax == false) goto interactive
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $subx-survey-main:interactive/disp8
|
|
# run-tests()
|
|
e8/call run-tests/disp32
|
|
# syscall_exit(*Num-test-failures)
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx
|
|
eb/jump $subx-survey-main:end/disp8
|
|
$subx-survey-main:interactive:
|
|
# - otherwise convert stdin
|
|
# subx-survey(Stdin, Stdout)
|
|
# . . push args
|
|
68/push Stdout/imm32
|
|
68/push Stdin/imm32
|
|
# . . call
|
|
e8/call subx-survey/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
|
|
$subx-survey-main:end:
|
|
e8/call syscall_exit/disp32
|
|
|
|
# data structures:
|
|
# segment-info: {address, file-offset, size} (12 bytes)
|
|
# segments: (addr stream {(handle array byte), segment-info}) (20 bytes per row)
|
|
# label-info: {segment-name: (handle array byte), segment-offset, address} (16 bytes)
|
|
# labels: (addr stream {(handle array byte), label-info}) (24 bytes per row)
|
|
# these are all inefficient, using sequential scans for lookups
|
|
|
|
subx-survey: # infile: (addr buffered-file), out: (addr buffered-file)
|
|
# pseudocode
|
|
# var in: (stream byte Input-size)
|
|
# slurp(infile, in)
|
|
# var segments: (stream {segment-name, segment-info})
|
|
# var labels: (stream {label-name, label-info} Max-labels)
|
|
# compute-offsets(in, segments, labels)
|
|
# compute-addresses(segments, labels)
|
|
# rewind-stream(in)
|
|
# emit-output(in, out, segments, labels)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
56/push-esi
|
|
# var segments/ecx: (stream {string, segment-info} 200) # 10 rows * 20 bytes/row
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc8/imm32 # subtract from esp
|
|
68/push 0xc8/imm32/size
|
|
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 label-info Max-labels)
|
|
# . data
|
|
2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Max-labels/disp32 # subtract *Max-labels from esp
|
|
# . size
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Max-labels/disp32 # push *Max-labels
|
|
# . read
|
|
68/push 0/imm32/read
|
|
# . write
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx
|
|
# var in/esi: (stream byte Input-size)
|
|
# . data
|
|
2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Input-size/disp32 # subtract *Input-size from esp
|
|
# . size
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Input-size/disp32 # push *Input-size
|
|
# . read
|
|
68/push 0/imm32/read
|
|
# . write
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
|
# 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
|
|
# 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
|
|
# 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
|
|
# 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
|
|
# 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
|
|
$subx-survey:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xec/imm32 # add to esp
|
|
03/add 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Max-labels/disp32 # add *Max-labels to esp
|
|
03/add 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Input-size/disp32 # add *Input-size to esp
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-subx-survey-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
|
|
#
|
|
# . prologue
|
|
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->buffer)
|
|
# . . push args
|
|
68/push $_test-input-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . 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->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# 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
|
|
# subx-survey(_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 subx-survey/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-subx-survey-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-subx-survey-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-subx-survey-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-subx-survey-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
|
|
# . epilogue
|
|
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
|
|
== data
|
|
|
|
compute-offsets:file-offset: # int
|
|
0/imm32
|
|
compute-offsets:segment-offset: # int
|
|
0/imm32
|
|
compute-offsets:segment-tmp: # slice
|
|
0/imm32/start
|
|
0/imm32/end
|
|
|
|
== code
|
|
|
|
# write segments->file-offset,
|
|
# segments->size,
|
|
# labels->segment-name, and
|
|
# labels->segment-offset
|
|
compute-offsets: # in: (addr stream byte), segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
|
|
# skeleton:
|
|
# for lines in 'in'
|
|
# for words in line
|
|
# switch word
|
|
# case 1
|
|
# case 2
|
|
# ...
|
|
# default
|
|
#
|
|
# pseudocode:
|
|
# var curr-segment-name: (handle array byte)
|
|
# var file-offset = 0
|
|
# var segment-offset = 0
|
|
# var line: (stream byte 512)
|
|
# var sinfo: (addr segment-info)
|
|
# var linfo: (addr label-info)
|
|
# 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
|
|
# sinfo = get-or-insert-handle(segments, curr-segment-name)
|
|
# sinfo->size = file-offset - sinfo->file-offset
|
|
# trace("segment '", curr-segment-name, "' has size ", sinfo->size)
|
|
# segment-tmp = next-word(line)
|
|
# if slice-empty?(segment-tmp)
|
|
# abort
|
|
# curr-segment-name = slice-to-string(segment-tmp)
|
|
# segment-tmp = next-word(line)
|
|
# if slice-empty?(segment-tmp)
|
|
# abort
|
|
# sinfo = get-or-insert-handle(segments, curr-segment-name)
|
|
# sinfo->starting-address = parse-hex-int-from-slice(segment-tmp)
|
|
# sinfo->file-offset = file-offset
|
|
# trace("segment '", curr-segment-name, "' is at file offset ", sinfo->file-offset)
|
|
# segment-offset = 0
|
|
# break (next line)
|
|
# else if label?(word-slice)
|
|
# strip trailing ':' from word-slice
|
|
# linfo: (addr label-info) = insert-slice-or-abort(labels, word-slice)
|
|
# linfo->segment-name = curr-segment-name
|
|
# trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.")
|
|
# linfo->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
|
|
# sinfo = get-or-insert-handle(segments, curr-segment-name)
|
|
# sinfo->size = file-offset - sinfo->file-offset
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# var curr-segment-name/esi: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to 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:file-offset
|
|
# segment-offset = 0
|
|
c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *compute-offsets:segment-offset
|
|
# var line/ecx: (stream byte 512)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp
|
|
68/push 0x200/imm32/size
|
|
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: (addr slice)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx
|
|
$compute-offsets: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
|
|
# 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-= $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:
|
|
# 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
|
|
$compute-offsets:case-empty:
|
|
# 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 != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $compute-offsets:line-loop/disp32
|
|
$compute-offsets:case-comment:
|
|
# if slice-starts-with?(word-slice, "#") continue
|
|
# . . push args
|
|
68/push "#"/imm32
|
|
52/push-edx
|
|
# . . call
|
|
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 != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $compute-offsets:line-loop/disp32
|
|
$compute-offsets:case-segment-header:
|
|
# if (!slice-equal?(word-slice, "==")) goto next case
|
|
# . 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 == false) goto next case
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 84/jump-if-= $compute-offsets:case-label/disp32
|
|
# if (*curr-segment-name == 0) goto construct-next-segment
|
|
81 7/subop/compare 0/mod/indirect 6/rm32/esi . . . . . 0/imm32 # compare *esi
|
|
74/jump-if-= $compute-offsets:construct-next-segment/disp8
|
|
# sinfo/edi = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . eax = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x14/imm32/row-size
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call get-or-insert-handle/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . edi = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
# sinfo->size = file-offset - sinfo->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 = sinfo->file-offset
|
|
8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
|
|
# . ebx -= ecx
|
|
29/subtract 3/mod/direct 3/rm32/ebx . . . 1/r32/ecx . . # subtract ecx from ebx
|
|
# . sinfo->size = ebx
|
|
89/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy ebx to *(edi+8)
|
|
# . restore ecx
|
|
59/pop-to-ecx
|
|
# trace-sssns("segment '", curr-segment-name, "' has size ", sinfo->size, ".")
|
|
# . eax = lookup(curr-segment-name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-sssns("segment '", eax, "' has size ", sinfo->size, ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-ebx
|
|
68/push "' has size "/imm32
|
|
50/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
|
|
$compute-offsets:construct-next-segment:
|
|
# next-word(line, segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
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
|
|
# if slice-empty?(segment-tmp) abort
|
|
# . eax = slice-empty?(segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
# . . 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 != false) abort
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $compute-offsets:abort/disp32
|
|
$compute-offsets:update-curr-segment-name:
|
|
# slice-to-string(Heap, segment-tmp, curr-segment-name)
|
|
# . . push args
|
|
56/push-esi
|
|
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 . . . . . 0xc/imm32 # add to esp
|
|
# next-word(line, segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
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
|
|
# if slice-empty?(segment-tmp) abort
|
|
# . eax = slice-empty?(segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
# . . 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 != false) abort
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $compute-offsets:abort/disp32
|
|
# sinfo/edi = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . eax = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x14/imm32/row-size
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call get-or-insert-handle/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . edi = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
# sinfo->address = parse-hex-int-from-slice(segment-tmp)
|
|
# . eax = parse-hex-int-from-slice(segment-tmp)
|
|
# . . push args
|
|
68/push compute-offsets:segment-tmp/imm32
|
|
# . . call
|
|
e8/call parse-hex-int-from-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . sinfo->address = eax
|
|
89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
|
|
# sinfo->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 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
|
|
# trace-sssns("segment '", curr-segment-name, "' is at file offset ", sinfo->file-offset, "")
|
|
# . eax = lookup(curr-segment-name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-sssns("segment '", eax, "' is at file offset ", file-offset, ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:file-offset/disp32 # push *file-offset
|
|
68/push "' is at file offset "/imm32
|
|
50/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
|
|
# 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 (!label?(word-slice)) goto next case
|
|
# . eax = label?(word-slice)
|
|
# . . push args
|
|
52/push-edx
|
|
# . . call
|
|
e8/call label?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . if (eax == false) goto next case
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 84/jump-if-= $compute-offsets:case-default/disp32
|
|
# strip trailing ':' from word-slice
|
|
ff 1/subop/decrement 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # decrement *(edx+4)
|
|
# linfo/edi = insert-slice-or-abort(labels, word-slice, row-size=24)
|
|
# . eax = insert-slice-or-abort(labels, word-slice, row-size=24)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
68/push 0x18/imm32/row-size
|
|
52/push-edx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call insert-slice-or-abort/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . edi = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
$compute-offsets:save-label-offset:
|
|
# linfo->segment-name = curr-segment-name
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
|
|
89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax
|
|
89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
|
|
# trace-slsss("label '" word-slice "' is in segment '" current-segment-name "'.")
|
|
# . eax = lookup(curr-segment-name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-slsss("label '" word-slice "' is in segment '" eax "'.")
|
|
# . . push args
|
|
68/push "'."/imm32
|
|
50/push-eax
|
|
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
|
|
# linfo->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
|
|
# . linfo->segment-offset = ebx
|
|
89/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy ebx to *(edi+8)
|
|
# trace-slsns("label '" word-slice "' is at segment offset " *segment-offset/eax ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-ebx
|
|
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->buffer)
|
|
#? # . . push args
|
|
#? 68/push $Stderr->buffer/imm32
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
#? # . write-int32-hex-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 write-int32-hex-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 Newline/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:
|
|
# sinfo/edi = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . eax = get-or-insert-handle(segments, curr-segment-name, row-size=16)
|
|
# . . push args
|
|
68/push 0x14/imm32/row-size
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call get-or-insert-handle/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . edi = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
# sinfo->size = file-offset - sinfo->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 = sinfo->file-offset
|
|
8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
|
|
# . ebx -= ecx
|
|
29/subtract 3/mod/direct 3/rm32/ebx . . . 1/r32/ecx . . # subtract ecx from ebx
|
|
# . sinfo->size = ebx
|
|
89/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy ebx to *(edi+8)
|
|
# . restore ecx
|
|
59/pop-to-ecx
|
|
# trace-sssns("segment '", curr-segment-name, "' has size ", sinfo->size, ".")
|
|
# . eax = lookup(curr-segment-name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-sssns("segment '", eax, "' has size ", ebx, ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-ebx
|
|
68/push "' has size "/imm32
|
|
50/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
|
|
$compute-offsets: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
|
|
# . epilogue
|
|
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 optionally an address\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
|
|
e8/call syscall_exit/disp32
|
|
# 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.
|
|
#
|
|
# . prologue
|
|
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 byte 2*20)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x28/imm32 # subtract from esp
|
|
68/push 0x28/imm32/size
|
|
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 byte 2*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x30/imm32 # subtract from esp
|
|
68/push 0x30/imm32/size
|
|
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, 0x18, msg)
|
|
# . . push args
|
|
68/push "F - test-compute-offsets-maintains-labels-write-index"/imm32
|
|
68/push 0x18/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# write segments->file-offset,
|
|
# segments->address, and
|
|
# labels->address
|
|
compute-addresses: # segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
|
|
# pseudocode:
|
|
# var srow: (addr segment-row) = segments->data
|
|
# var max: (addr byte) = &segments->data[segments->write]
|
|
# var num-segments: int = segments->write / 20
|
|
# var starting-offset: int = 0x34 + (num-segments * 0x20)
|
|
# while true
|
|
# if (srow >= max) break
|
|
# srow->file-offset += starting-offset
|
|
# srow->address &= 0xfffff000 # clear last 12 bits for p_align
|
|
# srow->address += (srow->file-offset & 0x00000fff)
|
|
# trace-sssns("segment " srow->key " starts at address " srow->address)
|
|
# srow += 20 # row-size
|
|
# var lrow: (addr label-row) = labels->data
|
|
# max = &labels->data[labels->write]
|
|
# while true
|
|
# if (lrow >= max) break
|
|
# var seg-name: (addr array byte) = lookup(lrow->segment-name)
|
|
# var label-seg: (addr segment-info) = get(segments, seg-name)
|
|
# lrow->address = label-seg->address + lrow->segment-offset
|
|
# trace-sssns("label " lrow->key " is at address " lrow->address)
|
|
# lrow += 24 # row-size
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
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
|
|
# var num-segments/edi: int = segments->write / 20 (row-size)
|
|
# . eax = segments->write
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
|
|
# . edx = 0
|
|
ba/copy-to-edx 0/imm32
|
|
# . ecx = 20 (row-size)
|
|
b9/copy-to-ecx 0x14/imm32/row-size
|
|
# . eax /= ecx (clobbering edx)
|
|
f7 7/subop/divide 3/mod/direct 1/rm32/ecx . . . . . . # divide eax by ecx
|
|
# . edi = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
# var starting-offset/edi: int = 0x34 + (num-segments * 0x20) # make room for ELF headers
|
|
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
|
|
# var max/ecx: (addr byte) = &segments->data[segments->write]
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 1/r32/ecx 0xc/disp8 . # copy esi+ecx+12 to ecx
|
|
# var srow/esi: (addr segment-row) = segments->data
|
|
8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 0xc/disp8 . # copy esi+12 to esi
|
|
$compute-addresses:segment-loop:
|
|
# if (srow >= max) break
|
|
39/compare 3/mod/direct 6/rm32/esi . . . 1/r32/ecx . . # compare esi with ecx
|
|
73/jump-if-addr>= $compute-addresses:segment-break/disp8
|
|
# srow->file-offset += starting-offset
|
|
01/add 1/mod/*+disp8 6/rm32/esi . . . 7/r32/edi 0xc/disp8 . # add edi to *(esi+12)
|
|
# clear last 12 bits of srow->address for p_align=0x1000
|
|
# . edx = srow->address
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 8/disp8 . # copy *(esi+8) 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 6/rm32/esi . . . 3/r32/ebx 0xc/disp8 . # copy *(esi+12) 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 6/rm32/esi . . . 2/r32/edx 8/disp8 . # copy edx to *(esi+8)
|
|
# trace-sssns("segment " srow " starts at address " srow->address ".")
|
|
# . eax = lookup(*srow)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-sssns("segment " eax " starts at address " srow->address ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
52/push-edx
|
|
68/push "' starts at address "/imm32
|
|
50/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 += 20 # size of row
|
|
81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0x14/imm32 # add to esi
|
|
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
|
|
# var max/ecx: (addr byte) = &labels->data[labels->write]
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 1/r32/ecx 0xc/disp8 . # copy esi+ecx+12 to ecx
|
|
# var lrow/esi: (addr label-row) = labels->data
|
|
8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 0xc/disp8 . # copy esi+12 to esi
|
|
$compute-addresses:label-loop:
|
|
# if (lrow >= max) break
|
|
39/compare 3/mod/direct 6/rm32/esi . . . 1/r32/ecx . . # compare esi with ecx
|
|
0f 83/jump-if-addr>= $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 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
|
|
#? # }}}
|
|
# var seg-name/edx: (addr array byte) = lookup(lrow->segment-name)
|
|
# . eax = lookup(lrow->segment-name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 0xc/disp8 . # push *(esi+12)
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 8/disp8 . # push *(esi+8)
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . edx = eax
|
|
89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # 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
|
|
#? # }}}
|
|
# var label-seg/edx: (addr segment-info) = get(segments, seg-name, row-size=20, "segment table")
|
|
# . eax = get(segments, seg-name, row-size=20)
|
|
# . . push args
|
|
68/push "segment table"/imm32
|
|
68/push 0x14/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 . . . . . 0x10/imm32 # add to esp
|
|
# . edx = eax
|
|
89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx
|
|
# 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 6/rm32/esi . . . 3/r32/ebx 0x10/disp8 . # add *(esi+16) to ebx
|
|
# lrow->address = ebx
|
|
89/copy 1/mod/*+disp8 6/rm32/esi . . . 3/r32/ebx 0x14/disp8 . # copy ebx to *(esi+20)
|
|
# trace-sssns("label " lrow->key " is at address " lrow->address ".")
|
|
# . eax = lookup(lrow->key)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . trace-sssns("label " eax " is at address " lrow->address ".")
|
|
# . . push args
|
|
68/push "."/imm32
|
|
53/push-ebx
|
|
68/push "' is at address "/imm32
|
|
50/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 += 24 # size of row
|
|
81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0x18/imm32 # add to esi
|
|
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
|
|
# . epilogue
|
|
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)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . var segments/ecx: (stream byte 10*20)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc8/imm32 # subtract from esp
|
|
68/push 0xc8/imm32/size
|
|
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 byte 8*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp
|
|
68/push 0xc0/imm32/size
|
|
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 h/ebx: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# . h = copy-array(Heap, "a")
|
|
# . . push args
|
|
53/push-ebx
|
|
68/push "a"/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call copy-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . stream-add5(segments, "a", 0x1000, 0, 5)
|
|
# . . push args
|
|
68/push 5/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1000/imm32/start-address
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call stream-add5/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp
|
|
# . h = copy-array(Heap, "b")
|
|
# . . push args
|
|
53/push-ebx
|
|
68/push "b"/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call copy-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . stream-add5(segments, "b", 0x2018, 5, 1)
|
|
# . . push args
|
|
68/push 1/imm32/segment-size
|
|
68/push 5/imm32/file-offset
|
|
68/push 0x2018/imm32/start-address
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call stream-add5/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp
|
|
# . h = copy-array(Heap, "c")
|
|
# . . push args
|
|
53/push-ebx
|
|
68/push "c"/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call copy-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . stream-add5(segments, "c", 0x5444, 6, 12)
|
|
68/push 0xc/imm32/segment-size
|
|
68/push 6/imm32/file-offset
|
|
68/push 0x5444/imm32/start-address
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call stream-add5/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp
|
|
# . stream-add6(labels, "l1", "a", 3, 0)
|
|
# . . push args
|
|
68/push 0/imm32/label-address
|
|
68/push 3/imm32/segment-offset
|
|
# . . push "a"
|
|
53/push-ebx
|
|
68/push "a"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l1"
|
|
53/push-ebx
|
|
68/push "l1"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/imm32 # add to esp
|
|
# . stream-add6(labels, "l2", "b", 0, 0)
|
|
# . . push args
|
|
68/push 0/imm32/label-address
|
|
68/push 0/imm32/segment-offset
|
|
# . . push "b"
|
|
53/push-ebx
|
|
68/push "b"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l2"
|
|
53/push-ebx
|
|
68/push "l2"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/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, 0x30, msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses/maintains-labels-write-index"/imm32
|
|
68/push 0x30/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-compute-addresses-large-segments:
|
|
# input:
|
|
# segments:
|
|
# - 'a': {0x1000, 0, 0x5604}
|
|
# - 'b': {0x2018, 0x5604, 1}
|
|
# labels:
|
|
# - 'l1': {'a', 3, 0}
|
|
#
|
|
# trace contains in any order (comments in parens):
|
|
# segment 'a' starts at address 0x00001074. (0x34 + 0x20 for each segment)
|
|
# segment 'b' starts at address 0x00002678. (0x018 discarded; last 3 nibbles from 0x1074 + 0x5604)
|
|
# label 'l1' is at address 0x00001077. (0x1074 + segment-offset 3)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . var segments/ecx: (stream byte 10*20)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc8/imm32 # subtract from esp
|
|
68/push 0xc8/imm32/size
|
|
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 byte 8*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp
|
|
68/push 0xc0/imm32/size
|
|
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 h/ebx: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# . h = copy-array(Heap, "a")
|
|
# . . push args
|
|
53/push-ebx
|
|
68/push "a"/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call copy-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . stream-add5(segments, "a", 0x1000, 0, 0x5604)
|
|
68/push 0x5604/imm32/segment-size
|
|
68/push 0/imm32/file-offset
|
|
68/push 0x1000/imm32/start-address
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call stream-add5/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp
|
|
# . h = copy-array(Heap, "b")
|
|
# . . push args
|
|
53/push-ebx
|
|
68/push "b"/imm32
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call copy-array/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . stream-add5(segments, "b", 0x2018, 0x5604, 1)
|
|
68/push 1/imm32/segment-size
|
|
68/push 0x5604/imm32/file-offset
|
|
68/push 0x2018/imm32/start-address
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call stream-add5/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp
|
|
# . stream-add6(labels, "l1", "a", 3, 0)
|
|
68/push 0/imm32/label-address
|
|
68/push 3/imm32/segment-offset
|
|
# . . push "a"
|
|
53/push-ebx
|
|
68/push "a"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l1"
|
|
53/push-ebx
|
|
68/push "l1"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/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 0x00001074.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses-large-segments/0"/imm32
|
|
68/push "segment 'a' starts at address 0x00001074."/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 0x00002678.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses-large-segments/1"/imm32
|
|
68/push "segment 'b' starts at address 0x00002678."/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 0x00001077.", msg)
|
|
# . . push args
|
|
68/push "F - test-compute-addresses-large-segments/3"/imm32
|
|
68/push "label 'l1' is at address 0x00001077."/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
emit-output: # in: (addr stream byte), out: (addr buffered-file), segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
|
|
# pseudocode:
|
|
# emit-headers(out, segments, labels)
|
|
# emit-segments(in, out, labels)
|
|
#
|
|
# . prologue
|
|
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, 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 . . . . 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 . . . . . 0xc/imm32 # add to esp
|
|
$emit-output:end:
|
|
# . epilogue
|
|
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 emit-segments
|
|
== data
|
|
|
|
emit-segments:datum: # slice
|
|
0/imm32/start
|
|
0/imm32/end
|
|
|
|
== code
|
|
|
|
emit-segments: # in: (addr stream byte), out: (addr buffered-file), labels: (addr stream {(handle array byte), label-info})
|
|
# pseudocode:
|
|
# var offset-of-next-instruction = 0
|
|
# var line: (stream byte 512)
|
|
# 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)
|
|
# var far-jump-or-call? = far-jump-or-call?(line)
|
|
# rewind-stream(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 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
|
|
# var datum: (addr slice) = next-token-from-slice(word-slice->start, word-slice->end, "/")
|
|
# var info: (addr label-info) = get-slice(labels, datum)
|
|
# if has-metadata?(word-slice, "imm8")
|
|
# abort
|
|
# 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")
|
|
# if far-jump-or-call?
|
|
# value = info->offset - offset-of-next-instruction
|
|
# else
|
|
# value = info->address
|
|
# emit(out, value, 4)
|
|
# else
|
|
# abort
|
|
# write-buffered(out, "\n")
|
|
#
|
|
# registers:
|
|
# line: ecx
|
|
# word-slice: edx
|
|
# offset-of-next-instruction: ebx
|
|
# far-jump-or-call?: edi
|
|
# info: esi (inner loop only)
|
|
# temporaries: eax, esi (outer loop)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# var line/ecx: (stream byte 512)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp
|
|
68/push 0x200/imm32/size
|
|
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: slice
|
|
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
|
|
# 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-= $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
|
|
# var far-jump-or-call?/edi: boolean = far-jump-or-call?(line)
|
|
# . . push args
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call far-jump-or-call?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/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: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/false
|
|
0f 85/jump-if-!= $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-= $emit-segments:next-line/disp32
|
|
$emit-segments:check-for-label:
|
|
# if label?(word-slice) break
|
|
# . eax = label?(word-slice)
|
|
# . . push args
|
|
52/push-edx
|
|
# . . call
|
|
e8/call label?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . if (eax != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $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 != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $emit-segments:line-loop/disp32
|
|
$emit-segments:2-character:
|
|
# if (size(word-slice) != 2) goto next check
|
|
# . eax = size(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-!= $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 Space/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 = next-token-from-slice(word-slice->start, word-slice->end, "/")
|
|
# . . push args
|
|
68/push emit-segments:datum/imm32
|
|
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 datum {{{
|
|
#? # . 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, datum)
|
|
#? # . . push args
|
|
#? 68/push emit-segments:datum/imm32
|
|
#? 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=24, "label table")
|
|
# . eax = get-slice(labels, datum, row-size=24, "label table")
|
|
# . . push args
|
|
68/push "label table"/imm32
|
|
68/push 0x18/imm32/row-size
|
|
68/push emit-segments:datum/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call get-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . esi = eax
|
|
89/copy 3/mod/direct 6/rm32/esi . . . 0/r32/eax . . # copy eax to esi
|
|
$emit-segments:check-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 != false) abort
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $emit-segments:imm8-abort/disp32
|
|
$emit-segments:check-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 == false) goto next check
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $emit-segments:check-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
|
|
#? # . write-int32-hex-buffered(Stderr, info->address)
|
|
#? # . . push args
|
|
#? ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 0xc/disp8 . # push *(esi+12)
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-int32-hex-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-imm32:
|
|
# emit-hex(out, info->address, 4)
|
|
# . . push args
|
|
68/push 4/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 0xc/disp8 . # push *(esi+12)
|
|
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-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 == false) goto next check
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $emit-segments:check-disp32/disp8
|
|
$emit-segments:emit-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 8/disp8 . # copy *(esi+8) 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-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 == false) abort
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 84/jump-if-= $emit-segments:abort/disp32
|
|
$emit-segments:emit-disp32:
|
|
# var value/eax = info->address
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 0xc/disp8 . # copy *(esi+12) to eax
|
|
# if (far-jump-or-call?) value = info->offset - offset-of-next-instruction
|
|
81 7/subop/compare 3/mod/direct 7/rm32/edi . . . . . 0/imm32/false # compare edi
|
|
74/jump-if-= $emit-segments:really-emit-disp32/disp8
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 8/disp8 . # copy *(esi+8) to eax
|
|
29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax
|
|
$emit-segments:really-emit-disp32:
|
|
# emit-hex(out, value, 4)
|
|
# . . push args
|
|
68/push 4/imm32
|
|
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 . . . . . 0x214/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
$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
|
|
e8/call syscall_exit/disp32
|
|
# 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
|
|
e8/call syscall_exit/disp32
|
|
# never gets here
|
|
|
|
test-emit-segments-non-far-control-flow:
|
|
# labels turn into absolute addresses if opcodes are not far jumps or calls
|
|
#
|
|
# input:
|
|
# in:
|
|
# == code 0x1000
|
|
# ab cd ef gh
|
|
# ij x/disp32
|
|
# == data 0x2000
|
|
# 00
|
|
# x:
|
|
# 34
|
|
# labels:
|
|
# - 'x': {'data', 1, 0x207a}
|
|
#
|
|
# output:
|
|
# ab cd ef gh
|
|
# ij 7a 20 00 00
|
|
# 00
|
|
# 34
|
|
#
|
|
# . prologue
|
|
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->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . var labels/edx: (stream byte 8*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp
|
|
68/push 0xc0/imm32/size
|
|
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 h/ebx: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# 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-add6(labels, "x", "data", 1, 0x207a)
|
|
68/push 0x207a/imm32/label-address
|
|
68/push 1/imm32/segment-offset
|
|
# . . push "data"
|
|
53/push-ebx
|
|
68/push "data"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l1"
|
|
53/push-ebx
|
|
68/push "x"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/imm32 # add to esp
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, labels)
|
|
# . . push args
|
|
52/push-edx
|
|
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 . . . . . 0xc/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
|
|
# . epilogue
|
|
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 turn into PC-relative addresses if opcodes are far jumps or calls
|
|
#
|
|
# input:
|
|
# in:
|
|
# == code 0x1000
|
|
# ab cd
|
|
# l1:
|
|
# ef gh
|
|
# e8 l1/disp32
|
|
# labels:
|
|
# - 'l1': {'code', 2, 0x1056}
|
|
#
|
|
# output:
|
|
# ab cd
|
|
# ef gh
|
|
# e8 f9 ff ff ff # -7
|
|
#
|
|
# . prologue
|
|
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->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . var labels/edx: (stream byte 8*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp
|
|
68/push 0xc0/imm32/size
|
|
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 h/ebx: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# 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, " e8 l1/disp32\n")
|
|
# . . push args
|
|
68/push " e8 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-add6(labels, "l1", "code", 2, 0x1056)
|
|
68/push 0x1056/imm32/label-address
|
|
68/push 2/imm32/segment-offset
|
|
# . . push "data"
|
|
53/push-ebx
|
|
68/push "code"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l1"
|
|
53/push-ebx
|
|
68/push "l1"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/imm32 # add to esp
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, labels)
|
|
# . . push args
|
|
52/push-edx
|
|
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 . . . . . 0xc/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, "e8 f9 ff ff ff ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-segments-code-label/2"/imm32
|
|
68/push "e8 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
|
|
# . epilogue
|
|
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
|
|
# labels:
|
|
# - 'l1': {'code', 2, 0x1056}
|
|
#
|
|
# output:
|
|
# ab cd
|
|
# ef gh
|
|
# ij 56 10 00 00
|
|
#
|
|
# . prologue
|
|
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->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . var labels/edx: (stream byte 8*24)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp
|
|
68/push 0xc0/imm32/size
|
|
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 h/ebx: (handle array byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# 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-add6(labels, "l1", "code", 2, 0x1056)
|
|
68/push 0x1056/imm32/label-address
|
|
68/push 2/imm32/segment-offset
|
|
# . . push "data"
|
|
53/push-ebx
|
|
68/push "code"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push "l1"
|
|
53/push-ebx
|
|
68/push "l1"/imm32
|
|
68/push Heap/imm32
|
|
e8/call copy-array/disp32
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4)
|
|
ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx
|
|
# . . push labels
|
|
52/push-edx
|
|
# . . call
|
|
e8/call stream-add6/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x1c/imm32 # add to esp
|
|
# component under test
|
|
# . emit-segments(_test-input-stream, _test-output-buffered-file, labels)
|
|
# . . push args
|
|
52/push-edx
|
|
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 . . . . . 0xc/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# reads line to make some checks
|
|
# don't assume the read state of line after calling this function
|
|
far-jump-or-call?: # line: (addr stream byte) -> result/edi: boolean
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# ecx = line
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
|
# var word-slice/edx: slice
|
|
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-slice/ebx: slice
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# result = false
|
|
bf/copy-to-edi 0/imm32/false
|
|
$far-jump-or-call?:check-first-word:
|
|
# 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
|
|
# if (slice-empty?(word-slice)) return false
|
|
# . 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) return
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $far-jump-or-call?:end/disp32
|
|
# datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
|
|
# . . push args
|
|
53/push-ebx
|
|
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
|
|
# if (datum-slice == "e8") return true
|
|
# . eax = slice-equal?(datum-slice, "e8")
|
|
# . . push args
|
|
68/push "e8"/imm32
|
|
53/push-ebx
|
|
# . . 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 != false) return true
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/jump-if-!= $far-jump-or-call?:return-true/disp8
|
|
# if (datum-slice == "e9") return true
|
|
# . eax = slice-equal?(datum-slice, "e9")
|
|
# . . push args
|
|
68/push "e9"/imm32
|
|
53/push-ebx
|
|
# . . 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 != false) return true
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/jump-if-!= $far-jump-or-call?:return-true/disp8
|
|
# if (datum-slice != "0f") return false
|
|
# . eax = slice-equal?(datum-slice, "0f")
|
|
# . . push args
|
|
68/push "0f"/imm32
|
|
53/push-ebx
|
|
# . . 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 == false) return
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $far-jump-or-call?:end/disp8
|
|
$far-jump-or-call?:check-second-word:
|
|
# 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
|
|
# if (slice-empty?(word-slice)) return false
|
|
# . 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) return
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/jump-if-!= $far-jump-or-call?:end/disp8
|
|
# if datum of word-slice does not start with "8", return false
|
|
# . start/eax = word-slice->start
|
|
8b/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy *edx to eax
|
|
# . c/eax = *start
|
|
8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
|
|
25/and-eax-with 0xff/imm32
|
|
# . if (eax != '8') return
|
|
3d/compare-eax-and 0x38/imm32/8
|
|
75/jump-if-!= $far-jump-or-call?:end/disp8
|
|
# otherwise return true
|
|
$far-jump-or-call?:return-true:
|
|
bf/copy-to-edi 1/imm32/true
|
|
$far-jump-or-call?:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# . restore registers
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
emit-headers: # out: (addr buffered-file), segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
|
|
# pseudocode:
|
|
# emit-elf-header(out, segments, labels)
|
|
# var curr-segment-row: (addr handle array byte) = segments->data
|
|
# max = &segments->data[segments->write]
|
|
# while true
|
|
# if (curr-segment >= max) break
|
|
# emit-elf-program-header-entry(out, curr-segment-row)
|
|
# curr-segment-row += 20 # size of a row
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
# 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-addr>= $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->buffer)
|
|
#? # . . push args
|
|
#? 68/push $Stderr->buffer/imm32
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
#? # . write-int32-hex-buffered(Stderr, &curr-segment)
|
|
#? # . . push args
|
|
#? 50/push-eax
|
|
#? 68/push Stderr/imm32
|
|
#? # . . call
|
|
#? e8/call write-int32-hex-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
|
|
#? # . write-int32-hex-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 write-int32-hex-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 Newline/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 += 20 # size of a row
|
|
05/add-to-eax 0x14/imm32
|
|
e9/jump $emit-headers:loop/disp32
|
|
$emit-headers:end:
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
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: (addr buffered-file), segments: (addr stream {(handle array byte), segment-info}), labels: (addr stream {(handle array byte), label-info})
|
|
# pseudocode
|
|
# *$Elf_e_entry = get(labels, "Entry")->address
|
|
# *$Elf_e_phnum = segments->write / 20 # size of a row
|
|
# emit-hex-array(out, Elf_header)
|
|
# write-buffered(out, "\n")
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx # 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=24, "label table")
|
|
# . . push args
|
|
68/push "label table"/imm32
|
|
68/push 0x18/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 . . . . . 0x10/imm32 # add to esp
|
|
# . eax = label-info->address
|
|
8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 0xc/disp8 . # copy *(eax+12) 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 / 20
|
|
# . 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 / 20 (clobbering ecx and edx)
|
|
b9/copy-to-ecx 0x14/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
|
|
# write-buffered(out, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write-buffered/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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# segment-info: {address, file-offset, size} (12 bytes)
|
|
# segments: (addr stream {(handle array byte), segment-info}) (20 bytes per row)
|
|
emit-elf-program-header-entry: # out: (addr buffered-file), curr-segment: (addr {(handle array byte), 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)
|
|
# write-buffered(out, "\n")
|
|
#
|
|
# . prologue
|
|
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 0xc/disp8 . # copy *(esi+12) 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 8/disp8 . # copy *(esi+8) 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 0x10/disp8 . # copy *(esi+16) 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?(name, "code") goto next check
|
|
# . var name/eax: (addr array byte) = lookup(curr-segment->name)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
|
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . eax = string-equal?(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 == false) goto next check
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $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
|
|
# write-buffered(out, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write-buffered/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
|
|
# . epilogue
|
|
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-add5: # in: (addr stream byte), key: handle, val1: addr, val2: addr, val3: addr
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
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->size]
|
|
# . edx = in->size
|
|
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-addr>= $stream-add5:abort/disp8
|
|
# *curr = key->alloc-id
|
|
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-addr>= $stream-add5:abort/disp8
|
|
# *curr = key->payload
|
|
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-addr>= $stream-add5:abort/disp8
|
|
# *curr = val1
|
|
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-addr>= $stream-add5:abort/disp8
|
|
# *curr = val2
|
|
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
|
|
# 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-addr>= $stream-add5:abort/disp8
|
|
# *curr = val3
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 0x1c/disp8 . # copy *(ebp+28) to ecx
|
|
89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax
|
|
# in->write += 20
|
|
81 0/subop/add 0/mod/indirect 6/rm32/esi . . . . . 0x14/imm32 # add to *esi
|
|
$stream-add5:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
$stream-add5:abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "overflow in stream-add5\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
|
|
e8/call syscall_exit/disp32
|
|
# never gets here
|
|
|
|
stream-add6: # in: (addr stream byte), key: handle, val1: addr, val2: addr, val3: addr, val4: addr
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
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->size]
|
|
# . edx = in->size
|
|
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-addr>= $stream-add6:abort/disp8
|
|
# *curr = key->alloc-id
|
|
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-addr>= $stream-add6:abort/disp8
|
|
# *curr = key->payload
|
|
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-addr>= $stream-add6:abort/disp8
|
|
# *curr = val1
|
|
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-addr>= $stream-add6:abort/disp8
|
|
# *curr = val2
|
|
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
|
|
# 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-addr>= $stream-add6:abort/disp8
|
|
$aa-write-segment-offset:
|
|
# *curr = val3
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 0x1c/disp8 . # copy *(ebp+28) 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-addr>= $stream-add6:abort/disp8
|
|
# *curr = val4
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 0x20/disp8 . # copy *(ebp+32) to ecx
|
|
89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax
|
|
# in->write += 24
|
|
81 0/subop/add 0/mod/indirect 6/rm32/esi . . . . . 0x18/imm32 # add to *esi
|
|
$stream-add6:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
$stream-add6:abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "overflow in stream-add6\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
|
|
e8/call syscall_exit/disp32
|
|
# 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: (addr array byte)
|
|
# l: (addr slice)
|
|
# one gotcha: 's5' must not be empty
|
|
|
|
trace-sssns: # s1: (addr array byte), s2: (addr array byte), s3: (addr array byte), n4: int, s5: (addr array byte)
|
|
# . prologue
|
|
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
|
|
# write-int32-hex(*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 write-int32-hex/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:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-trace-sssns:
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
trace-slsls: # s1: (addr array byte), l2: (addr slice), s3: (addr array byte), l4: (addr slice), s5: (addr array byte)
|
|
# . prologue
|
|
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:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-trace-slsls:
|
|
# . prologue
|
|
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: 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: 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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
trace-slsns: # s1: (addr array byte), l2: (addr slice), s3: (addr array byte), n4: int, s5: (addr array byte)
|
|
# . prologue
|
|
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-int32-hex(*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 write-int32-hex/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:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-trace-slsns:
|
|
# . prologue
|
|
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: 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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
trace-slsss: # s1: (addr array byte), l2: (addr slice), s3: (addr array byte), s4: (addr array byte), s5: (addr array byte)
|
|
# . prologue
|
|
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:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-trace-slsss:
|
|
# . prologue
|
|
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: 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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
num-bytes: # line: (addr stream byte) -> 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 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
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# var result/eax = 0
|
|
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
|
# var word-slice/ecx: slice
|
|
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->buffer)
|
|
#? # . . push args
|
|
#? 68/push $Stderr->buffer/imm32
|
|
#? # . . call
|
|
#? e8/call clear-stream/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
#? # . write-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 != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
# . restore result now that ZF is set
|
|
58/pop-to-eax
|
|
75/jump-if-!= $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-= $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-= $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 != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
# . restore result now that ZF is set
|
|
58/pop-to-eax
|
|
75/jump-if-!= $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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
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
|
|
# . prologue
|
|
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
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
== data
|
|
|
|
# This block of bytes gets copied to the start of the output ELF file, with
|
|
# some fields (the ones with labels capitalized) filled in.
|
|
# http://www.sco.com/developers/gabi/latest/ch4.eheader.html
|
|
Elf_header:
|
|
# - size
|
|
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:
|
|
# - size
|
|
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
|