diff options
-rw-r--r-- | subx/apps/hex | bin | 9733 -> 10160 bytes | |||
-rw-r--r-- | subx/apps/hex.subx | 138 |
2 files changed, 137 insertions, 1 deletions
diff --git a/subx/apps/hex b/subx/apps/hex index 299151cc..b6c2afea 100644 --- a/subx/apps/hex +++ b/subx/apps/hex Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx index 4bc56fcf..f73a9a66 100644 --- a/subx/apps/hex.subx +++ b/subx/apps/hex.subx @@ -44,6 +44,7 @@ #? e8/call test-scan-next-byte/disp32 #? e8/call test-scan-next-byte-handles-eof/disp32 #? e8/call test-scan-next-byte-skips-comment/disp32 +#? e8/call test-convert-next-hex-byte/disp32 e8/call run-tests/disp32 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX eb/jump $main:end/disp8 @@ -96,7 +97,7 @@ convert-next-hex-byte: # in : (address buffered-file), err : (address buffered- # if (EAX == 0xffffffff) return # ECX = EAX # EAX = scan-next-byte(in, err, ed) - # if (EAX == 0xffffffff) error("partial byte found") + # if (EAX == 0xffffffff) error("partial byte found.") # ECX = (ECX << 8) | EAX # return # @@ -104,13 +105,148 @@ convert-next-hex-byte: # in : (address buffered-file), err : (address buffered- 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # . save registers + 51/push-ECX + # EAX = scan-next-byte(in, err, ed) + # . . push args + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call scan-next-byte/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # if (EAX == 0xffffffff) return + 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX + 74/jump-if-equal $convert-next-hex-byte:end/disp8 + # ECX = EAX + 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX + # EAX = scan-next-byte(in, err, ed) + # . . push args + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call scan-next-byte/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # if (EAX == 0xffffffff) error(ed, err, "partial byte found.") + 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX + 75/jump-if-not-equal $convert-next-hex-byte:convert/disp8 + # . error-byte(ed, err, msg, '.') # reusing error-byte to avoid creating _yet_ another helper + # . . push args + 68/push 0x2e/imm32/period/dummy + 68/push "convert-next-hex-byte: partial byte found"/imm32 + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) + # . . call + e8/call error-byte/disp32 # never returns +$convert-next-hex-byte:convert: + # EAX = (EAX << 8) | ECX + # . EAX <<= 8 + c1/shift 4/subop/left 3/mod/direct 0/rm32/EAX . . . . . 8/imm8 # shift EAX left by 8 bits + # . EAX |= ECX + 09/or 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # EAX = bitwise OR with ECX $convert-next-hex-byte:end: # . restore registers + 59/pop-to-ECX # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return +test-convert-next-hex-byte: + # - check that the first two bytes of the input are assembled into the resulting number + # This test uses exit-descriptors. Use EBP for setting up local variables. + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # clear all streams + # . clear-stream(_test-stream) + # . . push args + 68/push _test-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(_test-buffered-file+4) + # . . push args + b8/copy-to-EAX _test-buffered-file/imm32 + 05/add-to-EAX 4/imm32 + 50/push-EAX + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(_test-error-stream) + # . . push args + 68/push _test-error-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # initialize '_test-stream' to "abc" + # . write(_test-stream, "abc") + # . . push args + 68/push "abc"/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # initialize exit-descriptor 'ed' for the call to 'convert-next-hex-byte' below + # . var ed/ECX : exit-descriptor + 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP + 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX + # . tailor-exit-descriptor(ed, 12) + # . . push args + 68/push 0xc/imm32/nbytes-of-args-for-convert-next-hex-byte + 51/push-ECX/ed + # . . call + e8/call tailor-exit-descriptor/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # EAX = convert-next-hex-byte(_test-buffered-file, _test-error-stream, ed) + # . . push args + 51/push-ECX/ed + 68/push _test-error-stream/imm32 + 68/push _test-buffered-file/imm32 + # . . call + e8/call convert-next-hex-byte/disp32 + # registers except ESP may be clobbered at this point + # pop args to convert-next-hex-bytes + # . . discard first 2 args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # . . restore ed + 59/pop-to-ECX + # check that convert-next-hex-byte didn't abort + # . check-ints-equal(ed->value, 0, msg) + # . . push args + 68/push "F - test-convert-next-hex-byte: unexpected abort"/imm32 + 68/push 0/imm32 + # . . push ed->value + ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # return if abort + 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) + 75/jump-if-not-equal $test-convert-next-hex-byte:end/disp8 + # check-ints-equal(EAX, 0x61/a 0x62/b, msg) + # . . push args + 68/push "F - test-convert-next-hex-byte"/imm32 + 68/push 0x6261/imm32/ab + 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 +$test-convert-next-hex-byte:end: + # . epilog + # don't restore ESP from EBP; manually reclaim locals + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 5d/pop-to-EBP + c3/return + # read whitespace until a hex byte, and return it # return 0xffffffff if file ends without finding a hex byte # on '#' skip all bytes until newline |