From 6f37250dd9d81c812fb5eddd747d237d94fff9b2 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Wed, 24 Oct 2018 23:05:58 -0700 Subject: 4722 --- html/subx/056write.subx.html | 378 +++++++++++++++++++------------------------ 1 file changed, 162 insertions(+), 216 deletions(-) (limited to 'html/subx/056write.subx.html') diff --git a/html/subx/056write.subx.html b/html/subx/056write.subx.html index 89d8859b..83562c91 100644 --- a/html/subx/056write.subx.html +++ b/html/subx/056write.subx.html @@ -15,7 +15,6 @@ body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color a { color:#eeeeee; text-decoration: none; } a:hover { text-decoration: underline; } * { font-size: 12pt; font-size: 1em; } -.CommentedCode { color: #6c6c6c; } .LineNr { color: #444444; } .Delimiter { color: #800080; } .Comment { color: #9090ff; } @@ -89,222 +88,169 @@ if ('onhashchange' in window) { 33 # 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 34 35 # main: (manual test if this is the last file loaded) - 36 #? e8/call test-write-appends/disp32 - 37 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - 38 # syscall(exit, Num-test-failures) - 39 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 1/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 40 b8/copy-to-EAX 1/imm32 - 41 cd/syscall 0x80/imm8 - 42 - 43 write: # f : fd or (address stream), s : (address array byte) -> <void> - 44 # prolog - 45 55/push-EBP - 46 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 47 # save registers - 48 50/push-EAX - 49 51/push-ECX - 50 52/push-EDX - 51 53/push-EBX - 52 56/push-ESI - 53 # if (f < 0x08000000) _write(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor - 54 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) - 55 7f/jump-if-greater $write:else/disp8 - 56 # push args - 57 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 58 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - 59 # call - 60 e8/call _write/disp32 - 61 # discard args - 62 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 63 eb/jump $write:end/disp8 - 64 $write:else: - 65 # otherwise, treat 'f' as a stream to append to - 66 # - 67 # pseudocode: - 68 # destend = &f.data[t.length] - 69 # oldw = f.write - 70 # if s.length == 0 return - 71 # f.write += s.length - 72 # dest = &f.data[oldw] - 73 # srcend = &s.data[s.length] - 74 # src = &s.data[0] - 75 # while true: - 76 # if src >= srcend break - 77 # if dest >= destend break # for now silently ignore filled up ostream buffer - 78 # *dest = *src - 79 # ++src - 80 # ++dest - 81 # - 82 # key registers to set up for the loop: - 83 # EAX/dest, ECX/destend, EBX/src, ESI/srcend - 84 # we save EDX for byte operations (has to be one of the first 4 registers) - 85 # - 86 # register setup before the loop: - 87 # EAX = *(EBP+8) # f - 88 # EBX = *(EBP+12) # s - 89 # ECX = *(EAX+4) # f.length - 90 # ECX = EAX+8+ECX # destend = &f.data[f.length] - 91 # ESI = *EAX # oldw = f.write - 92 # EDX = *EBX # s.length - 93 # *EAX = *EAX + EDX # update f.write (allowed to go past f.length) - 94 # # do this here just because it's convenient - 95 # EAX = EAX+8+ESI # dest = &f.data[oldw] - 96 # ESI = EBX+4+EDX # srcend = &s.data[s.length] - 97 # EBX = EBX+4 # src = &s.data[0] - 98 # - 99 # EAX = f -100 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX -101 # EBX = s -102 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX -103 # ECX = f.length -104 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX -105 # ECX/destend = &f.data[f.length] -106 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 8/disp8 . # copy EAX+ECX+8 to ECX -107 # ESI/oldw = f.write -108 8b/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy *EAX to ESI -109 # EDX = s.length -110 8b/copy 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # copy *EBX to EDX -111 # if EDX == 0 return -112 81 7/subop/compare 3/mod/direct 2/rm32/EDX . . . . . 0/imm32 # compare EDX -113 74/jump-if-equal $write:end/disp8 -114 # f.write += s.length -115 01/add 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to *EAX -116 # EAX/dest = &f.data[oldw] -117 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 6/index/ESI . 0/r32/EAX 8/disp8 . # copy EAX+ESI+8 to EAX -118 # ESI/srcend = &s.data[s.length] -119 8d/copy-address 1/mod/*+disp8 4/rm32/sib 3/base/EBX 2/index/EDX . 6/r32/ESI 4/disp8 . # copy EBX+EDX+4 to ESI -120 # EBX/src = &s.data[0] -121 81 0/subop/add 3/mod/direct 3/rm32/EBX . . . . . 4/imm32 # add to EBX -122 # while (true) -123 $write:loop: -124 # if EBX/src >= ESI/srcend break -125 39/compare 3/mod/direct 3/rm32/EBX . . . 6/r32/ESI . . # compare EBX with ESI -126 7d/jump-if-greater-or-equal $write:end/disp8 -127 # if EAX/dest >= ECX/destend break (for now silently ignore filled up ostream buffer) -128 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX -129 7d/jump-if-greater-or-equal $write:end/disp8 -130 # copy one byte -131 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 2/r32/DL . . # copy byte at *EBX to DL -132 88/copy-byte 0/mod/indirect 0/rm32/EAX . . . 2/r32/DL . . # copy byte at DL to *EAX -133 # updates -134 40/increment-EAX -135 43/increment-EBX -136 eb/jump $write:loop/disp8 -137 $write:end: -138 # restore registers -139 5e/pop-to-ESI -140 5b/pop-to-EBX -141 5a/pop-to-EDX -142 59/pop-to-ECX -143 58/pop-to-EAX -144 # epilog -145 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -146 5d/pop-to-EBP -147 c3/return -148 -149 clear-ostream: # f : (address ostream) -150 # prolog -151 55/push-EBP -152 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -153 # save registers -154 50/push-EAX -155 51/push-ECX -156 # EAX = f -157 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX -158 # ECX = f.length -159 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX -160 # ECX = &f.data[f.length] -161 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 8/disp8 . # copy EAX+ECX+8 to ECX -162 # f.write = 0 -163 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX -164 # EAX = f.data -165 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # add to EAX -166 # while (true) -167 $clear-ostream:loop: -168 # if EAX >= ECX break -169 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX -170 7d/jump-if-greater-or-equal $clear-ostream:end/disp8 -171 # *EAX = 0 -172 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX -173 # EAX += 4 -174 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX -175 eb/jump $clear-ostream:loop/disp8 -176 $clear-ostream:end: -177 # restore registers -178 59/pop-to-ECX -179 58/pop-to-EAX -180 # epilog -181 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -182 5d/pop-to-EBP -183 c3/return -184 -185 test-write-single: -186 # clear-ostream(Test-ostream) + 36 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + 37 # syscall(exit, Num-test-failures) + 38 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 1/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 39 b8/copy-to-EAX 1/imm32 + 40 cd/syscall 0x80/imm8 + 41 + 42 write: # f : fd or (address stream), s : (address array byte) -> <void> + 43 # prolog + 44 55/push-EBP + 45 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 46 # if (f < 0x08000000) _write(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor + 47 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) + 48 7f/jump-if-greater $write:fake/disp8 + 49 # push args + 50 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + 51 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + 52 # call + 53 e8/call _write/disp32 + 54 # discard args + 55 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 56 eb/jump $write:end/disp8 + 57 $write:fake: + 58 # otherwise, treat 'f' as a stream to append to + 59 # save registers + 60 50/push-EAX + 61 51/push-ECX + 62 52/push-EDX + 63 53/push-EBX + 64 # ECX = f + 65 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX + 66 # EDX = f.write + 67 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX + 68 # EBX = f.length + 69 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 4/disp8 . # copy *(ECX+4) to EBX + 70 # EAX = _append(&f.data[f.write], &f.data[f.length], s) + 71 # push s + 72 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + 73 # push &f.data[f.length] + 74 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 8/disp8 . # copy ECX+EBX+8 to EBX + 75 53/push-EBX + 76 # push &f.data[f.write] + 77 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 8/disp8 . # copy ECX+EBX+8 to EBX + 78 53/push-EBX + 79 # call + 80 e8/call _append/disp32 + 81 # discard args + 82 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 83 # f.write += EAX + 84 01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX + 85 # restore registers + 86 5b/pop-to-EBX + 87 5a/pop-to-EDX + 88 59/pop-to-ECX + 89 58/pop-to-EAX + 90 $write:end: + 91 # epilog + 92 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 93 5d/pop-to-EBP + 94 c3/return + 95 + 96 clear-ostream: # f : (address ostream) + 97 # prolog + 98 55/push-EBP + 99 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +100 # save registers +101 50/push-EAX +102 51/push-ECX +103 # EAX = f +104 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX +105 # ECX = f.length +106 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX +107 # ECX = &f.data[f.length] +108 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 8/disp8 . # copy EAX+ECX+8 to ECX +109 # f.write = 0 +110 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX +111 # EAX = f.data +112 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # add to EAX +113 # while (true) +114 $clear-ostream:loop: +115 # if EAX >= ECX break +116 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX +117 7d/jump-if-greater-or-equal $clear-ostream:end/disp8 +118 # *EAX = 0 +119 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX +120 # EAX += 4 +121 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX +122 eb/jump $clear-ostream:loop/disp8 +123 $clear-ostream:end: +124 # restore registers +125 59/pop-to-ECX +126 58/pop-to-EAX +127 # epilog +128 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +129 5d/pop-to-EBP +130 c3/return +131 +132 test-write-single: +133 # clear-ostream(Test-ostream) +134 # push args +135 68/push Test-ostream/imm32 +136 # call +137 e8/call clear-ostream/disp32 +138 # discard args +139 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +140 # write(Test-ostream, "Ab") +141 # push args +142 68/push "Ab"/imm32 +143 68/push Test-ostream/imm32 +144 # call +145 e8/call write/disp32 +146 # discard args +147 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +148 # check-ints-equal(*Test-ostream.data, 41/A 62/b 00 00, msg) +149 # push args +150 68/push "F - test-write-single"/imm32 +151 68/push 0x006241/imm32/Ab +152 # push *Test-ostream.data +153 b8/copy-to-EAX Test-ostream/imm32 +154 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) +155 # call +156 e8/call check-ints-equal/disp32 +157 # discard args +158 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +159 # end +160 c3/return +161 +162 test-write-appends: +163 # clear-ostream(Test-ostream) +164 # push args +165 68/push Test-ostream/imm32 +166 # call +167 e8/call clear-ostream/disp32 +168 # discard args +169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +170 # write(Test-ostream, "C") +171 # push args +172 68/push "C"/imm32 +173 68/push Test-ostream/imm32 +174 # call +175 e8/call write/disp32 +176 # discard args +177 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +178 # write(Test-ostream, "D") +179 # push args +180 68/push "D"/imm32 +181 68/push Test-ostream/imm32 +182 # call +183 e8/call write/disp32 +184 # discard args +185 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +186 # check-ints-equal(*Test-ostream.data, 43/C 44/D 00 00, msg) 187 # push args -188 68/push Test-ostream/imm32 -189 # call -190 e8/call clear-ostream/disp32 -191 # discard args -192 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -193 # write(Test-ostream, "Ab") -194 # push args -195 68/push "Ab"/imm32 -196 68/push Test-ostream/imm32 -197 # call -198 e8/call write/disp32 -199 # discard args -200 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -201 # check-ints-equal(*Test-ostream.data, 41/A 62/b 00 00, msg) -202 # push args -203 68/push "F - test-write-single"/imm32 -204 68/push 0x006241/imm32/Ab -205 # push *Test-ostream.data -206 b8/copy-to-EAX Test-ostream/imm32 -207 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) -208 # call -209 e8/call check-ints-equal/disp32 -210 # discard args -211 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -212 # end -213 c3/return -214 -215 test-write-appends: -216 # clear-ostream(Test-ostream) -217 # push args -218 68/push Test-ostream/imm32 -219 # call -220 e8/call clear-ostream/disp32 -221 # discard args -222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -223 # write(Test-ostream, "C") -224 # push args -225 68/push "C"/imm32 -226 68/push Test-ostream/imm32 -227 # call -228 e8/call write/disp32 -229 # discard args -230 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -231 # write(Test-ostream, "D") -232 # push args -233 68/push "D"/imm32 -234 68/push Test-ostream/imm32 -235 # call -236 e8/call write/disp32 -237 # discard args -238 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -239 # check-ints-equal(*Test-ostream.data, 43/C 44/D 00 00, msg) -240 # push args -241 68/push "F - test-write-appends"/imm32 -242 68/push 0x00004443/imm32/C-D -243 # push *Test-ostream.data -244 b8/copy-to-EAX Test-ostream/imm32 -245 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) -246 # call -247 e8/call check-ints-equal/disp32 -248 # discard args -249 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -250 # end -251 c3/return +188 68/push "F - test-write-appends"/imm32 +189 68/push 0x00004443/imm32/C-D +190 # push *Test-ostream.data +191 b8/copy-to-EAX Test-ostream/imm32 +192 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) +193 # call +194 e8/call check-ints-equal/disp32 +195 # discard args +196 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +197 # end +198 c3/return -- cgit 1.4.1-2-gfad0