1 # Print an error message followed by the text representation of a byte. Then exit. 2 3 == code 4 # instruction effective address register displacement immediate 5 # . op subop mod rm32 base index scale r32 6 # . 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 7 8 # main: 9 # manual test 10 #? # . var ed/EAX : exit-descriptor 11 #? 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 12 #? 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX 13 #? # . configure ed to really exit() 14 #? # . . ed->target = 0 15 #? c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX 16 #? # . error-byte(ed, Stdout, msg, 34) 17 #? 68/push 0x34/imm32 18 #? 68/push "abc"/imm32 19 #? 68/push Stderr/imm32 20 #? 50/push-EAX 21 #? e8/call error-byte/disp32 22 # automatic test 23 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. 24 # . syscall(exit, Num-test-failures) 25 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX 26 b8/copy-to-EAX 1/imm32 27 cd/syscall 0x80/imm8 28 29 # write(out, "Error: "+msg+": "+byte) then stop(ed, 1) 30 error-byte: # ed : (address exit-descriptor), out : (address buffered-file), msg : (address array byte), n : byte -> <void> 31 # . prolog 32 55/push-EBP 33 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 34 # write-buffered(out, "Error: ") 35 # . . push args 36 68/push "Error: "/imm32 37 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 38 # . . call 39 e8/call write-buffered/disp32 40 # . . discard args 41 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 42 # write-buffered(out, msg) 43 # . . push args 44 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) 45 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 46 # . . call 47 e8/call write-buffered/disp32 48 # . . discard args 49 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 50 # write-buffered(out, ": ") 51 # . . push args 52 68/push ": "/imm32 53 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 54 # . . call 55 e8/call write-buffered/disp32 56 # . . discard args 57 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 58 # print-byte(out, byte) 59 # . . push args 60 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) 61 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 62 # . . call 63 e8/call print-byte/disp32 64 # . . discard args 65 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 66 # write-buffered(out, Newline) 67 # . . push args 68 68/push Newline/imm32 69 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 70 # . . call 71 e8/call write-buffered/disp32 72 # . . discard args 73 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 74 # . flush(out) 75 # . . push args 76 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) 77 # . . call 78 e8/call flush/disp32 79 # . . discard args 80 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 81 # stop(ed, 1) 82 # . . push args 83 68/push 1/imm32 84 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) 85 # . . call 86 e8/call stop/disp32 87 # should never get past this point 88 $error-byte:dead-end: 89 # . epilog 90 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 91 5d/pop-to-EBP 92 c3/return 93 94 == data 95 96 # The buffered file for standard error. 97 Stderr: 98 # file descriptor or (address stream) 99 02 00 00 00 # 1 = standard error 100 # current write index 101 00 00 00 00 102 # current read index 103 00 00 00 00 104 # length (8) 105 08 00 00 00 106 # data 107 00 00 00 00 00 00 00 00 # 8 bytes 108 109 # TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency. But 110 # I don't want to type in 1024 bytes here. 111 112 # . . vim:nowrap:textwidth=0