From ce2c1efc41470764126e9a1a7f4e0cfec4213587 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 14 Jul 2019 09:42:36 -0700 Subject: . --- html/subx/059stop.subx.html | 355 ++++++++++++++++++++++---------------------- 1 file changed, 174 insertions(+), 181 deletions(-) (limited to 'html/subx/059stop.subx.html') diff --git a/html/subx/059stop.subx.html b/html/subx/059stop.subx.html index 83fddf7d..cb1fe62e 100644 --- a/html/subx/059stop.subx.html +++ b/html/subx/059stop.subx.html @@ -3,8 +3,8 @@ Mu - subx/059stop.subx - - + + @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.CommentedCode { color: #8a8a8a; } .subxComment { color: #005faf; } -.Constant { color: #008787; } -.LineNr { } .subxS1Comment { color: #0000af; } -.CommentedCode { color: #8a8a8a; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.subxTest { color: #5f8700; } -.subxMinorFunction { color: #875f5f; } +.LineNr { } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Constant { color: #008787; } +.subxMinorFunction { color: #875f5f; } +.subxTest { color: #5f8700; } --> @@ -40,7 +40,7 @@ function JumpToLine() if (lineNum.indexOf('L') == -1) { lineNum = 'L'+lineNum; } - lineElem = document.getElementById(lineNum); + var lineElem = document.getElementById(lineNum); /* Always jump to new location even if the line was hidden inside a fold, or * we corrected the raw number to a line ID. */ @@ -98,180 +98,173 @@ if ('onhashchange' in window) { 37 # . op subop mod rm32 base index scale r32 38 # . 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 39 - 40 #? Entry: # run a single test, while debugging - 41 #? e8/call test-stop-skips-returns-on-exit/disp32 - 42 #? # syscall(exit, Num-test-failures) - 43 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 44 #? b8/copy-to-EAX 1/imm32/exit - 45 #? cd/syscall 0x80/imm8 - 46 - 47 # Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to - 48 # the stack. - 49 # Ugly that we need to know the size of args, but so it goes. - 50 tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void> - 51 # . prolog - 52 55/push-EBP - 53 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 54 # . save registers - 55 50/push-EAX - 56 51/push-ECX - 57 # EAX = nbytes - 58 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - 59 # Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor. - 60 # The return address for a call in the caller's body will be at: - 61 # X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address) - 62 # X-12 if the caller takes 8 bytes of args - 63 # ..and so on - 64 # That's the value we need to return: X-nbytes-4 - 65 # - 66 # However, we also need to account for the perturbance to ESP caused by the - 67 # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 - 68 # bytes for the return address and 4 bytes to push EBP above. - 69 # So EBP at this point is X-16. - 70 # - 71 # So the return address for the next call in the caller is: - 72 # EBP+8 if the caller takes 4 bytes of args - 73 # EBP+4 if the caller takes 8 bytes of args - 74 # EBP if the caller takes 12 bytes of args - 75 # EBP-4 if the caller takes 16 bytes of args - 76 # ..and so on - 77 # That's EBP+12-nbytes. - 78 # option 1: 6 + 3 bytes - 79 #? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX - 80 #? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX - 81 # option 2: 2 + 4 bytes - 82 f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX - 83 8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX - 84 # copy EAX to ed->target - 85 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - 86 89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX - 87 # initialize ed->value - 88 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4) - 89 $tailor-exit-descriptor:end: - 90 # . restore registers - 91 59/pop-to-ECX - 92 58/pop-to-EAX - 93 # . epilog - 94 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 95 5d/pop-to-EBP - 96 c3/return - 97 - 98 stop: # ed : (address exit-descriptor), value : int - 99 # no prolog; one way or another, we're going to clobber registers -100 # EAX = ed -101 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX -102 # if (ed->target == 0) really exit -103 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX -104 75/jump-if-not-equal $stop:fake/disp8 -105 # . syscall(exit, value) -106 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX -107 b8/copy-to-EAX 1/imm32/exit -108 cd/syscall 0x80/imm8 -109 $stop:fake: -110 # otherwise: -111 # ed->value = value+1 -112 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX -113 41/increment-ECX -114 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) -115 # perform a non-local jump to ed->target -116 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP -117 $stop:end: -118 c3/return # doesn't return to caller -119 -120 test-stop-skips-returns-on-exit: -121 # This looks like the standard prolog, but is here for different reasons. -122 # A function calling 'stop' can't rely on EBP persisting past the call. -123 # -124 # Use EBP here as a stable base to refer to locals and arguments from in the -125 # presence of push/pop/call instructions. -126 # *Don't* use EBP as a way to restore ESP. -127 55/push-EBP -128 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -129 # Make room for an exit descriptor on the stack. That's almost always the -130 # right place for it, available only as long as it's legal to use. Once this -131 # containing function returns we'll need a new exit descriptor. -132 # var ed/EAX : (address exit-descriptor) -133 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -134 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -135 # Size the exit-descriptor precisely for the next call below, to _test-stop-1. -136 # tailor-exit-descriptor(ed, 4) -137 # . . push args -138 68/push 4/imm32/nbytes-of-args-for-_test-stop-1 + 40 # Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to + 41 # the stack. + 42 # Ugly that we need to know the size of args, but so it goes. + 43 tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <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 # EAX = nbytes + 51 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX + 52 # Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor. + 53 # The return address for a call in the caller's body will be at: + 54 # X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address) + 55 # X-12 if the caller takes 8 bytes of args + 56 # ..and so on + 57 # That's the value we need to return: X-nbytes-4 + 58 # + 59 # However, we also need to account for the perturbance to ESP caused by the + 60 # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 + 61 # bytes for the return address and 4 bytes to push EBP above. + 62 # So EBP at this point is X-16. + 63 # + 64 # So the return address for the next call in the caller is: + 65 # EBP+8 if the caller takes 4 bytes of args + 66 # EBP+4 if the caller takes 8 bytes of args + 67 # EBP if the caller takes 12 bytes of args + 68 # EBP-4 if the caller takes 16 bytes of args + 69 # ..and so on + 70 # That's EBP+12-nbytes. + 71 # option 1: 6 + 3 bytes + 72 #? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX + 73 #? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX + 74 # option 2: 2 + 4 bytes + 75 f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX + 76 8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX + 77 # copy EAX to ed->target + 78 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX + 79 89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX + 80 # initialize ed->value + 81 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4) + 82 $tailor-exit-descriptor:end: + 83 # . restore registers + 84 59/pop-to-ECX + 85 58/pop-to-EAX + 86 # . epilog + 87 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 88 5d/pop-to-EBP + 89 c3/return + 90 + 91 stop: # ed : (address exit-descriptor), value : int + 92 # no prolog; one way or another, we're going to clobber registers + 93 # EAX = ed + 94 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX + 95 # if (ed->target == 0) really exit + 96 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX + 97 75/jump-if-not-equal $stop:fake/disp8 + 98 # . syscall(exit, value) + 99 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX +100 b8/copy-to-EAX 1/imm32/exit +101 cd/syscall 0x80/imm8 +102 $stop:fake: +103 # otherwise: +104 # ed->value = value+1 +105 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX +106 41/increment-ECX +107 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) +108 # perform a non-local jump to ed->target +109 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP +110 $stop:end: +111 c3/return # doesn't return to caller +112 +113 test-stop-skips-returns-on-exit: +114 # This looks like the standard prolog, but is here for different reasons. +115 # A function calling 'stop' can't rely on EBP persisting past the call. +116 # +117 # Use EBP here as a stable base to refer to locals and arguments from in the +118 # presence of push/pop/call instructions. +119 # *Don't* use EBP as a way to restore ESP. +120 55/push-EBP +121 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +122 # Make room for an exit descriptor on the stack. That's almost always the +123 # right place for it, available only as long as it's legal to use. Once this +124 # containing function returns we'll need a new exit descriptor. +125 # var ed/EAX : (address exit-descriptor) +126 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP +127 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +128 # Size the exit-descriptor precisely for the next call below, to _test-stop-1. +129 # tailor-exit-descriptor(ed, 4) +130 # . . push args +131 68/push 4/imm32/nbytes-of-args-for-_test-stop-1 +132 50/push-EAX +133 # . . call +134 e8/call tailor-exit-descriptor/disp32 +135 # . . discard args +136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +137 # . _test-stop-1(ed) +138 # . . push args 139 50/push-EAX 140 # . . call -141 e8/call tailor-exit-descriptor/disp32 -142 # . . discard args -143 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -144 # . _test-stop-1(ed) -145 # . . push args -146 50/push-EAX -147 # . . call -148 e8/call _test-stop-1/disp32 -149 # registers except ESP may be clobbered at this point -150 # restore args -151 58/pop-to-EAX -152 # check that _test-stop-1 tried to call exit(1) -153 # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 -154 # . . push args -155 68/push "F - test-stop-skips-returns-on-exit"/imm32 -156 68/push 2/imm32 -157 # . . push ed->value -158 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -159 # . . call -160 e8/call check-ints-equal/disp32 -161 # . . discard args -162 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -163 # . epilog -164 # don't restore ESP from EBP; manually reclaim locals -165 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -166 5d/pop-to-EBP -167 c3/return -168 -169 _test-stop-1: # ed : (address exit-descriptor) -170 # . prolog -171 55/push-EBP -172 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -173 # _test-stop-2(ed) -174 # . . push args -175 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -176 # . . call -177 e8/call _test-stop-2/disp32 -178 # should never get past this point -179 $_test-stop-1:dead-end: -180 # . . discard args -181 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -182 # signal test failed: check-ints-equal(1, 0, msg) -183 # . . push args -184 68/push "F - test-stop-skips-returns-on-exit"/imm32 -185 68/push 0/imm32 -186 68/push 1/imm32 -187 # . . call -188 e8/call check-ints-equal/disp32 -189 # . . discard args -190 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -191 # . epilog -192 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -193 5d/pop-to-EBP -194 c3/return -195 -196 _test-stop-2: # ed : (address exit-descriptor) -197 # . prolog -198 55/push-EBP -199 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -200 # . stop(ed, 1) -201 # . . push args -202 68/push 1/imm32 -203 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -204 # . . call -205 e8/call stop/disp32 -206 # should never get past this point -207 $_test-stop-2:dead-end: -208 # . epilog -209 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -210 5d/pop-to-EBP -211 c3/return -212 -213 # . . vim:nowrap:textwidth=0 +141 e8/call _test-stop-1/disp32 +142 # registers except ESP may be clobbered at this point +143 # restore args +144 58/pop-to-EAX +145 # check that _test-stop-1 tried to call exit(1) +146 # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 +147 # . . push args +148 68/push "F - test-stop-skips-returns-on-exit"/imm32 +149 68/push 2/imm32 +150 # . . push ed->value +151 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +152 # . . call +153 e8/call check-ints-equal/disp32 +154 # . . discard args +155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +156 # . epilog +157 # don't restore ESP from EBP; manually reclaim locals +158 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +159 5d/pop-to-EBP +160 c3/return +161 +162 _test-stop-1: # ed : (address exit-descriptor) +163 # . prolog +164 55/push-EBP +165 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +166 # _test-stop-2(ed) +167 # . . push args +168 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +169 # . . call +170 e8/call _test-stop-2/disp32 +171 # should never get past this point +172 $_test-stop-1:dead-end: +173 # . . discard args +174 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +175 # signal test failed: check-ints-equal(1, 0, msg) +176 # . . push args +177 68/push "F - test-stop-skips-returns-on-exit"/imm32 +178 68/push 0/imm32 +179 68/push 1/imm32 +180 # . . call +181 e8/call check-ints-equal/disp32 +182 # . . discard args +183 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +184 # . epilog +185 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +186 5d/pop-to-EBP +187 c3/return +188 +189 _test-stop-2: # ed : (address exit-descriptor) +190 # . prolog +191 55/push-EBP +192 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +193 # . stop(ed, 1) +194 # . . push args +195 68/push 1/imm32 +196 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +197 # . . call +198 e8/call stop/disp32 +199 # should never get past this point +200 $_test-stop-2:dead-end: +201 # . epilog +202 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +203 5d/pop-to-EBP +204 c3/return +205 +206 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0