From 9a77780158842db6e4aa098f5027e030fc3bd878 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 22 May 2020 23:08:09 -0700 Subject: 6384 --- html/069allocate.subx.html | 1161 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 913 insertions(+), 248 deletions(-) (limited to 'html/069allocate.subx.html') diff --git a/html/069allocate.subx.html b/html/069allocate.subx.html index 21ef578c..6f5ee389 100644 --- a/html/069allocate.subx.html +++ b/html/069allocate.subx.html @@ -16,14 +16,14 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } .subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxMinorFunction { color: #875f5f; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } +.subxMinorFunction { color: #875f5f; } --> @@ -79,255 +79,920 @@ if ('onhashchange' in window) { 18 19 == data 20 - 21 # A default allocation descriptor for programs to use. - 22 Heap: # allocation-descriptor - 23 # curr - 24 0/imm32 - 25 # limit - 26 0/imm32 - 27 - 28 # a reasonable default - 29 Heap-size: # int - 30 0x400000/imm32/4MB - 31 - 32 == code - 33 # instruction effective address register displacement immediate - 34 # . op subop mod rm32 base index scale r32 - 35 # . 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 + 21 # Allocations are returned in a handle, which consists of an alloc-id and a payload. + 22 # The alloc-id helps detect use-after-free errors. + 23 Handle-size: # (addr int) + 24 8/imm32 + 25 + 26 # A default allocation descriptor for programs to use. + 27 Heap: # allocation-descriptor + 28 # curr + 29 0/imm32 + 30 # limit + 31 0/imm32 + 32 + 33 # a reasonable default + 34 Heap-size: # int + 35 0x600000/imm32/6MB 36 - 37 # Let's start initializing the default allocation descriptor. - 38 - 39 Entry: - 40 # initialize heap - 41 # . Heap = new-segment(Heap-size) - 42 # . . push args - 43 68/push Heap/imm32 - 44 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size - 45 # . . call - 46 e8/call new-segment/disp32 - 47 # . . discard args - 48 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 49 - 50 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - 51 $array-equal-main:end: - 52 # syscall(exit, Num-test-failures) - 53 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx - 54 b8/copy-to-eax 1/imm32/exit - 55 cd/syscall 0x80/imm8 - 56 - 57 # Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr. - 58 # Abort if there isn't enough memory in 'ad'. - 59 allocate: # ad: (addr allocation-descriptor), n: int -> address-or-null/eax: (addr _) - 60 # . prologue - 61 55/push-ebp - 62 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - 63 # . save registers - 64 51/push-ecx - 65 52/push-edx - 66 # ecx = ad - 67 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - 68 # save ad->curr - 69 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 70 # check if there's enough space - 71 # . edx = ad->curr + n - 72 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx - 73 03/add 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # add *(ebp+12) to edx - 74 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # compare edx with *(ecx+4) - 75 73/jump-if->=-signed $allocate:abort/disp8 - 76 $allocate:commit: - 77 # update ad->curr - 78 89/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy edx to *ecx - 79 $allocate:end: - 80 # . restore registers - 81 5a/pop-to-edx - 82 59/pop-to-ecx - 83 # . epilogue - 84 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 85 5d/pop-to-ebp - 86 c3/return - 87 - 88 $allocate:abort: - 89 # . _write(2/stderr, error) - 90 # . . push args - 91 68/push "allocate: failed to allocate\n"/imm32 - 92 68/push 2/imm32/stderr - 93 # . . call - 94 e8/call _write/disp32 - 95 # . . discard args - 96 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 97 # . syscall(exit, 1) - 98 bb/copy-to-ebx 1/imm32 - 99 b8/copy-to-eax 1/imm32/exit -100 cd/syscall 0x80/imm8 -101 # never gets here -102 -103 test-allocate-success: -104 # . prologue -105 55/push-ebp -106 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -107 # var ad/ecx: allocation-descriptor = {11, 15} -108 68/push 0xf/imm32/limit -109 68/push 0xb/imm32/curr -110 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx -111 # var eax: (handle byte) = allocate(ad, 3) -112 # . . push args -113 68/push 3/imm32 -114 51/push-ecx -115 # . . call -116 e8/call allocate/disp32 -117 # . . discard args -118 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -119 # check-ints-equal(eax, 11, msg) -120 # . . push args -121 68/push "F - test-allocate-success: returns current pointer of allocation descriptor"/imm32 -122 68/push 0xb/imm32 -123 50/push-eax -124 # . . call -125 e8/call check-ints-equal/disp32 -126 # . . discard args -127 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -128 # check-ints-equal(ad->curr, 14, msg) -129 # . . push args -130 68/push "F - test-allocate-success: updates allocation descriptor"/imm32 -131 68/push 0xe/imm32 -132 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx -133 # . . call -134 e8/call check-ints-equal/disp32 -135 # . . discard args -136 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -137 # . epilogue -138 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -139 5d/pop-to-ebp -140 c3/return -141 -142 _pending-test-allocate-failure: -143 # . prologue -144 55/push-ebp -145 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -146 # var ad/ecx: allocation-descriptor = {11, 15} -147 68/push 0xf/imm32/limit -148 68/push 0xb/imm32/curr -149 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx -150 # var eax: (handle byte) = allocate(ad, 6) -151 # . . push args -152 68/push 6/imm32 -153 51/push-ecx -154 # . . call -155 e8/call allocate/disp32 -156 # . . discard args -157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -158 # check-ints-equal(eax, 0, msg) -159 # . . push args -160 68/push "F - test-allocate-failure: returns null"/imm32 -161 68/push 0/imm32 -162 50/push-eax -163 # . . call -164 e8/call check-ints-equal/disp32 -165 # . . discard args -166 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -167 # no change to ad->curr -168 # . check-ints-equal(ad->curr, 11) -169 # . . push args -170 68/push "F - test-allocate-failure: updates allocation descriptor"/imm32 -171 68/push 0xb/imm32 -172 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx -173 # . . call -174 e8/call check-ints-equal/disp32 -175 # . . discard args -176 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -177 # . epilogue -178 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -179 5d/pop-to-ebp -180 c3/return -181 -182 # helper: create a nested allocation descriptor (useful for tests) -183 allocate-region: # ad: (addr allocation-descriptor), n: int -> new-ad: (handle allocation-descriptor) -184 # . prologue -185 55/push-ebp -186 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -187 # . save registers -188 51/push-ecx -189 # eax = allocate(ad, n) -190 # . . push args -191 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) -192 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) -193 # . . call -194 e8/call allocate/disp32 -195 # . . discard args -196 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -197 # if (eax == 0) abort -198 3d/compare-eax-and 0/imm32 -199 74/jump-if-= $allocate-region:abort/disp8 -200 # earmark 8 bytes at the start for a new allocation descriptor -201 # . *eax = eax + 8 -202 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx -203 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 8/imm32 # add to ecx -204 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax -205 # . *(eax+4) = eax + n -206 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx -207 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # add *(ebp+12) to ecx -208 89/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy ecx to *(eax+4) -209 # . restore registers -210 59/pop-to-ecx -211 # . epilogue -212 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -213 5d/pop-to-ebp -214 c3/return -215 -216 # We could create a more general '$abort' jump target, but then we'd need to do -217 # a conditional jump followed by loading the error message and an unconditional -218 # jump. Or we'd need to unconditionally load the error message before a -219 # conditional jump, even if it's unused the vast majority of the time. This way -220 # we bloat a potentially cold segment in RAM so we can abort with a single -221 # instruction. -222 $allocate-region:abort: -223 # . _write(2/stderr, error) -224 # . . push args -225 68/push "allocate-region: failed to allocate\n"/imm32 -226 68/push 2/imm32/stderr + 37 Next-alloc-id: # int + 38 0x100/imm32 # save a few alloc ids for fake handles + 39 + 40 == code + 41 # instruction effective address register displacement immediate + 42 # . op subop mod rm32 base index scale r32 + 43 # . 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 + 44 + 45 # Let's start initializing the default allocation descriptor. + 46 + 47 Entry: + 48 # initialize heap + 49 # . Heap = new-segment(Heap-size) + 50 # . . push args + 51 68/push Heap/imm32 + 52 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size + 53 # . . call + 54 e8/call new-segment/disp32 + 55 # . . discard args + 56 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 57 + 58 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + 59 $array-equal-main:end: + 60 # syscall(exit, Num-test-failures) + 61 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx + 62 b8/copy-to-eax 1/imm32/exit + 63 cd/syscall 0x80/imm8 + 64 + 65 # Allocate and clear 'n' bytes of memory from an allocation-descriptor 'ad'. + 66 # Abort if there isn't enough memory in 'ad'. + 67 allocate: # ad: (addr allocation-descriptor), n: int, out: (addr handle) + 68 # . prologue + 69 55/push-ebp + 70 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + 71 # . save registers + 72 50/push-eax + 73 # allocate-raw(ad, n, out) + 74 # . . push args + 75 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) + 76 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) + 77 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) + 78 # . . call + 79 e8/call allocate-raw/disp32 + 80 # . . discard args + 81 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + 82 # eax = out->payload + 4 + 83 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax + 84 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax + 85 05/add-to-eax 4/imm32 + 86 # zero-out(eax, n) + 87 # . . push args + 88 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) + 89 50/push-eax + 90 # . . call + 91 e8/call zero-out/disp32 + 92 # . . discard args + 93 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 94 $allocate:end: + 95 # . restore registers + 96 58/pop-to-eax + 97 # . epilogue + 98 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 99 5d/pop-to-ebp +100 c3/return +101 +102 # Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr. +103 # Abort if there isn't enough memory in 'ad'. +104 allocate-raw: # ad: (addr allocation-descriptor), n: int, out: (addr handle) +105 # . prologue +106 55/push-ebp +107 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +108 # . save registers +109 50/push-eax +110 51/push-ecx +111 52/push-edx +112 53/push-ebx +113 56/push-esi +114 57/push-edi +115 # ecx = ad +116 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx +117 # edx = out +118 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx +119 # ebx = n +120 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx +121 # out->alloc-id = Next-alloc-id +122 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/eax Next-alloc-id/disp32 # copy *Next-alloc-id to eax +123 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx +124 # out->payload = ad->curr +125 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax +126 $allocate-raw:save-payload-in-eax: +127 89/copy 1/mod/*+disp8 2/rm32/edx . . . 0/r32/eax 4/disp8 . # copy eax to *(edx+4) +128 # *out->payload = Next-alloc-id +129 8b/copy 1/mod/*+disp8 2/rm32/edx . . . 7/r32/edi 4/disp8 . # copy *(edx+4) to edi +130 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 6/r32/esi Next-alloc-id/disp32 # copy *Next-alloc-id to esi +131 89/copy 0/mod/indirect 7/rm32/edi . . . 6/r32/esi . . # copy esi to *edi +132 $allocate-raw:increment-next-alloc-id: +133 # increment *Next-alloc-id +134 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # increment *Next-alloc-id +135 # check if there's enough space +136 # TODO: move this check up before any state updates when we support error recovery +137 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 3/index/ebx . 0/r32/eax 4/disp8 . # copy eax+ebx+4 to eax +138 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # compare eax with *(ecx+4) +139 73/jump-if->=-signed $allocate-raw:abort/disp8 +140 $allocate-raw:commit: +141 # ad->curr += n+4 +142 89/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy eax to *ecx +143 $allocate-raw:end: +144 # . restore registers +145 5f/pop-to-edi +146 5e/pop-to-esi +147 5b/pop-to-ebx +148 5a/pop-to-edx +149 59/pop-to-ecx +150 58/pop-to-eax +151 # . epilogue +152 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +153 5d/pop-to-ebp +154 c3/return +155 +156 $allocate-raw:abort: +157 # . _write(2/stderr, error) +158 # . . push args +159 68/push "allocate: failed\n"/imm32 +160 68/push 2/imm32/stderr +161 # . . call +162 e8/call _write/disp32 +163 # . . discard args +164 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +165 # . syscall(exit, 1) +166 bb/copy-to-ebx 1/imm32 +167 b8/copy-to-eax 1/imm32/exit +168 cd/syscall 0x80/imm8 +169 # never gets here +170 +171 test-allocate-raw-success: +172 # . prologue +173 55/push-ebp +174 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +175 # var ad/ecx: allocation-descriptor +176 68/push 0/imm32/limit +177 68/push 0/imm32/curr +178 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +179 # ad = new-segment(512) +180 # . . push args +181 51/push-ecx +182 68/push 0x200/imm32 +183 # . . call +184 e8/call new-segment/disp32 +185 # . . discard args +186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +187 # var expected-payload/ebx = ad->curr +188 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx +189 # var h/edx: handle = {0, 0} +190 68/push 0/imm32 +191 68/push 0/imm32 +192 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx +193 # *Next-alloc-id = 0x34 +194 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id +195 # allocate-raw(ad, 3, h) +196 # . . push args +197 52/push-edx +198 68/push 3/imm32 +199 51/push-ecx +200 # . . call +201 e8/call allocate-raw/disp32 +202 # . . discard args +203 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +204 # check-ints-equal(h->alloc-id, 0x34, msg) +205 # . . push args +206 68/push "F - test-allocate-raw-success: sets alloc-id in handle"/imm32 +207 68/push 0x34/imm32 +208 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx +209 # . . call +210 e8/call check-ints-equal/disp32 +211 # . . discard args +212 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +213 # check-ints-equal(h->payload, expected-payload, msg) +214 # . . push args +215 68/push "F - test-allocate-raw-success: sets payload in handle"/imm32 +216 53/push-ebx +217 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) +218 # . . call +219 e8/call check-ints-equal/disp32 +220 # . . discard args +221 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +222 # check-ints-equal(h->payload->alloc-id, 0x34, msg) +223 # . . push args +224 68/push "F - test-allocate-raw-success: sets alloc-id in payload"/imm32 +225 68/push 0x34/imm32 +226 ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx 227 # . . call -228 e8/call _write/disp32 +228 e8/call check-ints-equal/disp32 229 # . . discard args -230 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -231 # . syscall(exit, 1) -232 bb/copy-to-ebx 1/imm32 -233 b8/copy-to-eax 1/imm32/exit -234 cd/syscall 0x80/imm8 -235 # never gets here -236 -237 # Claim the next 'n+4' bytes of memory and initialize the first 4 to n. -238 # Abort if there isn't enough memory in 'ad'. -239 allocate-array: # ad: (addr allocation-descriptor), n: int -> result/eax: (addr _) -240 # . prologue -241 55/push-ebp -242 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -243 # . save registers -244 51/push-ecx -245 52/push-edx -246 # ecx = n -247 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx -248 # var size/edx: int = n+4 -249 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy ecx+4 to edx -250 # result = allocate(ad, size) -251 # . . push args -252 52/push-edx -253 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) -254 # . . call -255 e8/call allocate/disp32 -256 # . . discard args -257 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -258 # *result = n -259 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax -260 $allocate-array:end: -261 # . restore registers -262 5a/pop-to-edx -263 59/pop-to-ecx -264 # . epilogue -265 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -266 5d/pop-to-ebp -267 c3/return -268 -269 # . . vim:nowrap:textwidth=0 +230 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +231 # check-ints-equal(*Next-alloc-id, 0x35, msg) +232 # . . push args +233 68/push "F - test-allocate-raw-success: increments Next-alloc-id"/imm32 +234 68/push 0x35/imm32 +235 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id +236 # . . call +237 e8/call check-ints-equal/disp32 +238 # . . discard args +239 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +240 # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id, msg) +241 # . . push args +242 68/push "F - test-allocate-raw-success: updates allocation descriptor"/imm32 +243 68/push 7/imm32 +244 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax +245 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax +246 50/push-eax +247 # . . call +248 e8/call check-ints-equal/disp32 +249 # . . discard args +250 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +251 # clean up +252 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id +253 # . epilogue +254 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +255 5d/pop-to-ebp +256 c3/return +257 +258 lookup: # h: (handle T) -> eax: (addr T) +259 # . prologue +260 55/push-ebp +261 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +262 # . save registers +263 51/push-ecx +264 # eax = 0 +265 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax +266 # ecx = handle->alloc_id +267 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx +268 # if (ecx == 0) return 0 +269 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx +270 74/jump-if-= $lookup:end/disp8 +271 # eax = handle->address (payload) +272 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax +273 # if (ecx != *eax) abort +274 39/compare 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # compare *eax and ecx +275 75/jump-if-!= $lookup:abort/disp8 +276 # add 4 to eax +277 05/add-to-eax 4/imm32 +278 $lookup:end: +279 # . restore registers +280 59/pop-to-ecx +281 # . epilogue +282 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +283 5d/pop-to-ebp +284 c3/return +285 +286 $lookup:abort: +287 # . _write(2/stderr, msg) +288 # . . push args +289 68/push "lookup failed\n"/imm32 +290 68/push 2/imm32/stderr +291 # . . call +292 e8/call _write/disp32 +293 # . . discard args +294 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +295 # . syscall(exit, 1) +296 bb/copy-to-ebx 1/imm32/exit-status +297 b8/copy-to-eax 1/imm32/exit +298 cd/syscall 0x80/imm8 +299 +300 test-lookup-success: +301 # . prologue +302 55/push-ebp +303 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +304 # var ad/ebx: allocation-descriptor +305 68/push 0/imm32/limit +306 68/push 0/imm32/curr +307 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx +308 # ad = new-segment(512) +309 # . . push args +310 53/push-ebx +311 68/push 0x200/imm32 +312 # . . call +313 e8/call new-segment/disp32 +314 # . . discard args +315 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +316 # var handle/ecx: handle +317 68/push 0/imm32/address +318 68/push 0/imm32/alloc-id +319 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +320 # var old-top/edx = ad->curr +321 8b/copy 0/mod/indirect 3/rm32/ebx . . . 2/r32/edx . . # copy *ebx to edx +322 # allocate-raw(ad, 2, handle) +323 # . . push args +324 51/push-ecx +325 68/push 2/imm32/size +326 53/push-ebx +327 # . . call +328 e8/call allocate-raw/disp32 +329 # . . discard args +330 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +331 # eax = lookup(handle) +332 # . . push args +333 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) +334 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +335 # . . call +336 e8/call lookup/disp32 +337 # . . discard args +338 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +339 # eax contains old top of heap, except skipping the alloc-id in the payload +340 # . check-ints-equal(eax, old-top+4, msg) +341 # . . push args +342 68/push "F - test-lookup-success"/imm32 +343 81 0/subop/add 3/mod/direct 2/rm32/edx . . . . . 4/imm32 # add to edx +344 52/push-edx +345 50/push-eax +346 # . . call +347 e8/call check-ints-equal/disp32 +348 # . . discard args +349 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +350 # clean up +351 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id +352 # . epilogue +353 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +354 5d/pop-to-ebp +355 c3/return +356 +357 test-lookup-null-returns-null: +358 # . prologue +359 55/push-ebp +360 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +361 # var handle/ecx: handle +362 68/push 0/imm32/address +363 68/push 0/imm32/alloc-id +364 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +365 # eax = lookup(handle) +366 # . . push args +367 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) +368 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +369 # . . call +370 e8/call lookup/disp32 +371 # . . discard args +372 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +373 # check-ints-equal(eax, 0, msg) +374 # . . push args +375 68/push "F - test-lookup-null-returns-null"/imm32 +376 68/push 0/imm32 +377 50/push-eax +378 # . . call +379 e8/call check-ints-equal/disp32 +380 # . . discard args +381 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +382 # . epilogue +383 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +384 5d/pop-to-ebp +385 c3/return +386 +387 _pending-test-lookup-failure: +388 # . prologue +389 55/push-ebp +390 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +391 # var heap/esi: allocation-descriptor +392 68/push 0/imm32/limit +393 68/push 0/imm32/curr +394 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi +395 # heap = new-segment(512) +396 # . . push args +397 56/push-esi +398 68/push 0x200/imm32 +399 # . . call +400 e8/call new-segment/disp32 +401 # . . discard args +402 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +403 # var h1/ecx: handle +404 68/push 0/imm32/address +405 68/push 0/imm32/alloc-id +406 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +407 # var old_top/ebx = heap->curr +408 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx +409 # first allocation, to h1 +410 # . allocate(heap, 2, h1) +411 # . . push args +412 51/push-ecx +413 68/push 2/imm32/size +414 56/push-esi +415 # . . call +416 e8/call allocate/disp32 +417 # . . discard args +418 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +419 # reset heap->curr to mimic reclamation +420 89/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy ebx to *esi +421 # second allocation that returns the same address as the first +422 # var h2/edx: handle +423 68/push 0/imm32/address +424 68/push 0/imm32/alloc-id +425 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx +426 # . allocate(heap, 2, h2) +427 # . . push args +428 52/push-edx +429 68/push 2/imm32/size +430 56/push-esi +431 # . . call +432 e8/call allocate/disp32 +433 # . . discard args +434 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +435 # check-ints-equal(h1->address, h2->address, msg) +436 # . . push args +437 68/push "F - test-lookup-failure"/imm32 +438 ff 6/subop/push 1/mod/*+disp8 2/rm32/ecx . . . . 4/disp8 . # push *(edx+4) +439 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) +440 # . . call +441 e8/call check-ints-equal/disp32 +442 # . . discard args +443 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +444 # lookup(h1) should crash +445 # . . push args +446 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) +447 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +448 # . . call +449 e8/call lookup/disp32 +450 # should never get past this point +451 # . . discard args +452 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +453 # clean up +454 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id +455 # . epilogue +456 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +457 5d/pop-to-ebp +458 c3/return +459 +460 # when comparing handles, just treat them as pure values +461 handle-equal?: # a: handle, b: handle -> eax: boolean +462 # . prologue +463 55/push-ebp +464 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +465 # . save registers +466 51/push-ecx +467 # eax = false +468 b8/copy-to-eax 0/imm32/false +469 $handle-equal?:compare-alloc-id: +470 # ecx = a->alloc_id +471 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx +472 # if (ecx != b->alloc_id) return false +473 39/compare 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # compare ecx and *(ebp+16) +474 75/jump-if-!= $handle-equal?:end/disp8 +475 $handle-equal?:compare-address: +476 # ecx = handle->address +477 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx +478 # if (ecx != b->address) return false +479 39/compare 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # compare ecx and *(ebp+20) +480 75/jump-if-!= $handle-equal?:end/disp8 +481 $handle-equal?:return-true: +482 # return true +483 b8/copy-to-eax 1/imm32/true +484 $handle-equal?:end: +485 # . restore registers +486 59/pop-to-ecx +487 # . epilogue +488 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +489 5d/pop-to-ebp +490 c3/return +491 +492 # helper: create a nested allocation descriptor (useful for tests) +493 allocate-region: # ad: (addr allocation-descriptor), n: int, out: (addr handle allocation-descriptor) +494 # . prologue +495 55/push-ebp +496 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +497 # . save registers +498 50/push-eax +499 51/push-ecx +500 # allocate(ad, n, out) +501 # . . push args +502 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) +503 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) +504 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) +505 # . . call +506 e8/call allocate/disp32 +507 # . . discard args +508 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +509 # eax = out->payload +510 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax +511 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax +512 # skip payload->allocid +513 05/add-to-eax 4/imm32 +514 # if (eax == 0) abort +515 3d/compare-eax-and 0/imm32 +516 74/jump-if-= $allocate-region:abort/disp8 +517 # earmark 8 bytes at the start for a new allocation descriptor +518 # . *eax = eax + 8 +519 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx +520 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 8/imm32 # add to ecx +521 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax +522 # . *(eax+4) = eax + n +523 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx +524 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # add *(ebp+12) to ecx +525 89/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy ecx to *(eax+4) +526 # . restore registers +527 59/pop-to-ecx +528 58/pop-to-eax +529 # . epilogue +530 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +531 5d/pop-to-ebp +532 c3/return +533 +534 # We could create a more general '$abort' jump target, but then we'd need to do +535 # a conditional jump followed by loading the error message and an unconditional +536 # jump. Or we'd need to unconditionally load the error message before a +537 # conditional jump, even if it's unused the vast majority of the time. This way +538 # we bloat a potentially cold segment in RAM so we can abort with a single +539 # instruction. +540 $allocate-region:abort: +541 # . _write(2/stderr, error) +542 # . . push args +543 68/push "allocate-region: failed to allocate\n"/imm32 +544 68/push 2/imm32/stderr +545 # . . call +546 e8/call _write/disp32 +547 # . . discard args +548 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +549 # . syscall(exit, 1) +550 bb/copy-to-ebx 1/imm32 +551 b8/copy-to-eax 1/imm32/exit +552 cd/syscall 0x80/imm8 +553 # never gets here +554 +555 # Claim the next 'n+4' bytes of memory and initialize the first 4 to n. +556 # Abort if there isn't enough memory in 'ad'. +557 allocate-array: # ad: (addr allocation-descriptor), n: int, out: (addr handle) +558 # . prologue +559 55/push-ebp +560 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +561 # . save registers +562 50/push-eax +563 51/push-ecx +564 52/push-edx +565 # ecx = n +566 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx +567 # var size/edx: int = n+4 +568 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy ecx+4 to edx +569 # allocate(ad, size, out) +570 # . . push args +571 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) +572 52/push-edx +573 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) +574 # . . call +575 e8/call allocate/disp32 +576 # . . discard args +577 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +578 # *out->payload = n +579 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax +580 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax +581 # . skip payload->allocid +582 05/add-to-eax 4/imm32 +583 # . +584 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax +585 $allocate-array:end: +586 # . restore registers +587 5a/pop-to-edx +588 59/pop-to-ecx +589 58/pop-to-eax +590 # . epilogue +591 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +592 5d/pop-to-ebp +593 c3/return +594 +595 test-allocate-array: +596 # . prologue +597 55/push-ebp +598 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +599 # var ad/ecx: allocation-descriptor +600 68/push 0/imm32/limit +601 68/push 0/imm32/curr +602 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +603 # ad = new-segment(512) +604 # . . push args +605 51/push-ecx +606 68/push 0x200/imm32 +607 # . . call +608 e8/call new-segment/disp32 +609 # . . discard args +610 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +611 # var expected-payload/ebx = ad->curr +612 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx +613 # var h/edx: handle = {0, 0} +614 68/push 0/imm32 +615 68/push 0/imm32 +616 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx +617 # *Next-alloc-id = 0x34 +618 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id +619 # allocate-array(ad, 3, h) +620 # . . push args +621 52/push-edx +622 68/push 3/imm32 +623 51/push-ecx +624 # . . call +625 e8/call allocate-array/disp32 +626 # . . discard args +627 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +628 # check-ints-equal(h->alloc-id, 0x34, msg) +629 # . . push args +630 68/push "F - test-allocate-array: sets alloc-id in handle"/imm32 +631 68/push 0x34/imm32 +632 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx +633 # . . call +634 e8/call check-ints-equal/disp32 +635 # . . discard args +636 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +637 # check-ints-equal(h->payload, expected-payload, msg) +638 # . . push args +639 68/push "F - test-allocate-array: sets payload in handle"/imm32 +640 53/push-ebx +641 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) +642 # . . call +643 e8/call check-ints-equal/disp32 +644 # . . discard args +645 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +646 # check-ints-equal(h->payload->alloc-id, 0x34, msg) +647 # . . push args +648 68/push "F - test-allocate-array: sets alloc-id in payload"/imm32 +649 68/push 0x34/imm32 +650 ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx +651 # . . call +652 e8/call check-ints-equal/disp32 +653 # . . discard args +654 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +655 # check-ints-equal(h->payload->size, 3, msg) +656 # . . push args +657 68/push "F - test-allocate-array: sets array size in payload"/imm32 +658 68/push 3/imm32 +659 ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4) +660 # . . call +661 e8/call check-ints-equal/disp32 +662 # . . discard args +663 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +664 # check-ints-equal(*Next-alloc-id, 0x35, msg) +665 # . . push args +666 68/push "F - test-allocate-array: increments Next-alloc-id"/imm32 +667 68/push 0x35/imm32 +668 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id +669 # . . call +670 e8/call check-ints-equal/disp32 +671 # . . discard args +672 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +673 # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id + 4 for array size, msg) +674 # . . push args +675 68/push "F - test-allocate-array: updates allocation descriptor"/imm32 +676 68/push 0xb/imm32 +677 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax +678 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax +679 50/push-eax +680 # . . call +681 e8/call check-ints-equal/disp32 +682 # . . discard args +683 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +684 # clean up +685 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id +686 # . epilogue +687 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +688 5d/pop-to-ebp +689 c3/return +690 +691 copy-array: # ad: (addr allocation-descriptor), src: (addr array), out: (addr handle) +692 # . prologue +693 55/push-ebp +694 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +695 # . save registers +696 50/push-eax +697 51/push-ecx +698 52/push-edx +699 56/push-esi +700 # esi = src +701 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi +702 # var size/ecx: int = src->size+4 +703 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx +704 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx +705 # allocate(ad, size, out) +706 # . . push args +707 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) +708 51/push-ecx +709 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) +710 # . . call +711 e8/call allocate/disp32 +712 # . . discard args +713 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +714 # var payload/eax: (addr byte) = out->payload +715 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax +716 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax +717 # . skip payload->allocid +718 05/add-to-eax 4/imm32 +719 # var max/ecx: (addr byte) = payload + size +720 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx +721 # _append-4(payload, max, src, &src->data[src->size]) +722 # . . push &src->data[src->size] +723 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx +724 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 2/index/edx . 2/r32/edx 4/disp8 . # copy esi+edx+4 to edx +725 52/push-edx +726 # . . push src +727 56/push-esi +728 # . . push max +729 51/push-ecx +730 # . . push payload +731 50/push-eax +732 # . . call +733 e8/call _append-4/disp32 +734 # . . discard args +735 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp +736 $copy-array:end: +737 # . restore registers +738 5e/pop-to-esi +739 5a/pop-to-edx +740 59/pop-to-ecx +741 58/pop-to-eax +742 # . epilogue +743 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +744 5d/pop-to-ebp +745 c3/return +746 +747 test-copy-array: +748 # . prologue +749 55/push-ebp +750 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +751 # var src/esi: (addr array int) = [3, 4, 5] +752 68/push 5/imm32 +753 68/push 4/imm32 +754 68/push 3/imm32 +755 68/push 0xc/imm32/size +756 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi +757 # var ad/ecx: allocation-descriptor +758 68/push 0/imm32/limit +759 68/push 0/imm32/curr +760 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +761 # ad = new-segment(512) +762 # . . push args +763 51/push-ecx +764 68/push 0x200/imm32 +765 # . . call +766 e8/call new-segment/disp32 +767 # . . discard args +768 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +769 # var expected-payload/ebx = ad->curr +770 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx +771 # var h/edx: handle = {0, 0} +772 68/push 0/imm32 +773 68/push 0/imm32 +774 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx +775 # *Next-alloc-id = 0x34 +776 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id +777 # copy-array(ad, src, h) +778 # . . push args +779 52/push-edx +780 56/push-esi +781 51/push-ecx +782 # . . call +783 e8/call copy-array/disp32 +784 # . . discard args +785 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +786 # check-ints-equal(h->alloc-id, 0x34, msg) +787 # . . push args +788 68/push "F - test-copy-array: sets alloc-id in handle"/imm32 +789 68/push 0x34/imm32 +790 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx +791 # . . call +792 e8/call check-ints-equal/disp32 +793 # . . discard args +794 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +795 # check-ints-equal(h->payload, expected-payload, msg) +796 # . . push args +797 68/push "F - test-copy-array: sets payload in handle"/imm32 +798 53/push-ebx +799 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) +800 # . . call +801 e8/call check-ints-equal/disp32 +802 # . . discard args +803 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +804 # check-ints-equal(h->payload->alloc-id, 0x34, msg) +805 # . . push args +806 68/push "F - test-copy-array: sets alloc-id in payload"/imm32 +807 68/push 0x34/imm32 +808 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx +809 # . . call +810 e8/call check-ints-equal/disp32 +811 # . . discard args +812 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +813 # var payload/eax: (addr int) = lookup(h) +814 # . . push args +815 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) +816 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx +817 # . . call +818 e8/call lookup/disp32 +819 # . . discard args +820 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +821 # check-ints-equal(payload->size, 0xc, msg) +822 # . . push args +823 68/push "F - test-copy-array: sets array size in payload"/imm32 +824 68/push 0xc/imm32 +825 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax +826 # . . call +827 e8/call check-ints-equal/disp32 +828 # . . discard args +829 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +830 # check-ints-equal(*Next-alloc-id, 0x35, msg) +831 # . . push args +832 68/push "F - test-copy-array: increments Next-alloc-id"/imm32 +833 68/push 0x35/imm32 +834 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id +835 # . . call +836 e8/call check-ints-equal/disp32 +837 # . . discard args +838 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +839 # check-ints-equal(ad->curr - expected-payload, 12 + 4 for alloc-id + 4 for length, msg) +840 # . . push args +841 68/push "F - test-copy-array: updates allocation descriptor"/imm32 +842 68/push 0x14/imm32 +843 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax +844 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax +845 50/push-eax +846 # . . call +847 e8/call check-ints-equal/disp32 +848 # . . discard args +849 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +850 # clean up +851 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id +852 # . epilogue +853 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +854 5d/pop-to-ebp +855 c3/return +856 +857 # Fill a region of memory with zeroes. +858 zero-out: # start: (addr byte), len: int +859 # pseudocode: +860 # curr/esi = start +861 # i/ecx = 0 +862 # while true +863 # if (i >= len) break +864 # *curr = 0 +865 # ++curr +866 # ++i +867 # +868 # . prologue +869 55/push-ebp +870 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +871 # . save registers +872 50/push-eax +873 51/push-ecx +874 52/push-edx +875 56/push-esi +876 # curr/esi = start +877 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi +878 # var i/ecx: int = 0 +879 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx +880 # edx = len +881 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx +882 $zero-out:loop: +883 # if (i >= len) break +884 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx +885 7d/jump-if->= $zero-out:end/disp8 +886 # *curr = 0 +887 c6 0/subop/copy 0/mod/direct 6/rm32/esi . . . . . 0/imm8 # copy byte to *esi +888 # ++curr +889 46/increment-esi +890 # ++i +891 41/increment-ecx +892 eb/jump $zero-out:loop/disp8 +893 $zero-out:end: +894 # . restore registers +895 5e/pop-to-esi +896 5a/pop-to-edx +897 59/pop-to-ecx +898 58/pop-to-eax +899 # . epilogue +900 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +901 5d/pop-to-ebp +902 c3/return +903 +904 test-zero-out: +905 # . prologue +906 55/push-ebp +907 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +908 # region/ecx = 34, 35, 36, 37 +909 68/push 0x37363534/imm32 +910 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +911 # zero-out(ecx, 3) +912 # . . push args +913 68/push 3/imm32/len +914 51/push-ecx +915 # . . call +916 e8/call zero-out/disp32 +917 # . . discard args +918 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +919 # first 3 bytes cleared, fourth left alone +920 # . check-ints-equal(*ecx, 0x37000000, msg) +921 # . . push args +922 68/push "F - test-zero-out"/imm32 +923 68/push 0x37000000/imm32 +924 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +925 # . . call +926 e8/call check-ints-equal/disp32 +927 # . . discard args +928 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +929 # . epilogue +930 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +931 5d/pop-to-ebp +932 c3/return +933 +934 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0