diff options
Diffstat (limited to 'subx/apps/handle.subx')
-rw-r--r-- | subx/apps/handle.subx | 412 |
1 files changed, 0 insertions, 412 deletions
diff --git a/subx/apps/handle.subx b/subx/apps/handle.subx deleted file mode 100644 index ba824f85..00000000 --- a/subx/apps/handle.subx +++ /dev/null @@ -1,412 +0,0 @@ -# A sketch of Mu-style handles or kinda-safe pointers, that add a modicum of -# checking to dynamically allocated memory. -# -# This approach avoids using 'allocate' directly in favor of two primitives: -# - 'new', which allocates some space (the 'payload'), stores the address -# along with an opaque 'alloc id' in a 'handle', and prepends the same -# alloc id to the payload. -# - 'lookup', which checks that the alloc id at the start of a handle matches -# the alloc id at the start of the payload before returning the address. -# -# Layout of a handle: -# offset 0: alloc id -# offset 4: address -# -# To run (from the subx directory): -# $ ./subx translate *.subx apps/handle.subx -o apps/handle -# $ ./subx run apps/handle -# Expected result is a successful lookup followed by a hard abort: -# lookup succeeded -# lookup failed -# (This file is a prototype. The 'tests' in it aren't real; failures are -# expected.) - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 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 - -# no Entry; the standard library runs all tests by default - -new: # ad : (address allocation-descriptor), n : int, out : (address handle) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # ECX = n+4 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX - 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX - # EAX = allocate(ad, ECX) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EDX = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX - # out->address = EAX - 89/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDX+4) - # if (EAX == 0) out->alloc_id = 0, return - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $new:continue/disp8 - c7 0/subop/copy 0/mod/indirect 2/rm32/EDX . . . . . 0/imm32 # copy to *EDX - eb/jump $new:end/disp8 -$new:continue: - # otherwise: - # ECX = *Next-alloc-id - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 1/r32/ECX Next-alloc-id/disp32 # copy *Next-alloc-id to ECX - # *EAX = *Next-alloc-id/ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # out->alloc_id = *Next-alloc-id - 89/copy 0/mod/indirect 2/rm32/EDX . . . 1/r32/ECX . . # copy ECX to *EDX - # increment *Next-alloc-id - ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # increment *Next-alloc-id -$new:end: - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-new: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var heap/EDX : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # heap = new-segment(512) - # . . push args - 52/push-EDX - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # var handle/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # new(heap, 2, handle/ECX) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 52/push-EDX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(handle->alloc_id, 0x34, msg) - # . . push args - 68/push "F - test-new: alloc id of handle"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(*handle->address, 0x34, msg) - # . . push args - 68/push "F - test-new: alloc id of payload"/imm32 - 68/push 0x34/imm32 - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(*Next-alloc-id, 0x35) - # . . push args - 68/push "F - test-new: next alloc id"/imm32 - 68/push 0x35/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # copy to *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -_pending-test-new-failure: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # define an allocation-descriptor with no space left - # . var ad/EAX : (address allocation-descriptor) = {0x10, 0x10} - 68/push 0x10/imm32/limit - 68/push 0x10/imm32/curr - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . var handle/ECX = {random, random} - 68/push 1234/imm32/address - 68/push 5678/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # try to allocate - # . new(ad, 2, handle/ECX) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 50/push-EAX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # handle should be cleared - # . check-ints-equal(handle->alloc_id, 0, msg) - # . . push args - 68/push "F - test-new-failure: alloc id of handle"/imm32 - 68/push 0/imm32 - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-ints-equal(handle->address, 0, msg) - # . . push args - 68/push "F - test-new-failure: address of handle"/imm32 - 68/push 0/imm32 - 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 - # Next-alloc-id should be unmodified - # . check-ints-equal(*Next-alloc-id, 0x34) - # . . push args - 68/push "F - test-new-failure: next alloc id"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # copy to *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -lookup: # h : (handle T) -> EAX : (address T) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - as a proof of concept for future inlining, uses no general-purpose registers besides the output (EAX) - # EAX = handle - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX - # - inline { - # push handle->alloc_id - ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX - # EAX = handle->address (payload) - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # copy *(EAX+4) to EAX - # push handle->address - 50/push-EAX - # EAX = payload->alloc_id - 8b/copy 0/mod/indirect 0/rm32/EAX . . . . . . # copy *EAX to EAX - # if (EAX != handle->alloc_id) abort - 39/compare 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # compare *(ESP+4) and EAX - 75/jump-if-not-equal $lookup:abort/disp8 - # EAX = pop handle->address - 58/pop-to-EAX - # discard handle->alloc_id - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # add 4 - 05/add-to-EAX 4/imm32 - # - } - # - alternative consuming a second register { -#? # ECX = handle->alloc_id -#? 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -#? # EAX = handle->address (payload) -#? 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 4/disp8 . # copy *(EAX+4) to EAX -#? # if (ECX != *EAX) abort -#? 39/compare 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # compare *EAX and ECX -#? 75/jump-if-not-equal $lookup:abort/disp8 -#? # add 4 to EAX -#? 05/add-to-EAX 4/imm32 - # - } - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$lookup:abort: - # . _write(2/stderr, msg) - # . . push args - 68/push "lookup failed\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32/exit-status - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -test-lookup-success: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - # var heap/EBX : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # heap = new-segment(512) - # . . push args - 53/push-EBX - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # var handle/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EDX = heap->curr - 8b/copy 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # copy *EBX to EDX - # new(heap, 2, handle) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 53/push-EBX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # EAX = lookup(handle) - # . . push args - 51/push-ECX - # . . call - e8/call lookup/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # EAX contains old top of heap, except skipping the alloc id in the payload - # . check-ints-equal(EAX, old_top+4, msg) - # . . push args - 68/push "F - test-lookup-success"/imm32 - 81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 4/imm32 # add to EDX - 52/push-EDX - 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 - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # write(2/stderr, "lookup succeeded\n") - # . . push args - 68/push "lookup succeeded\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 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-lookup-failure: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var heap/ESI : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # heap = new-segment(512) - # . . push args - 56/push-ESI - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # var h1/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EBX = heap->curr - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX - # first allocation, to h1 - # . new(heap, 2, h1) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 56/push-ESI - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # reset heap->curr to mimic reclamation - 89/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy EBX to *ESI - # second allocation that returns the same address as the first - # var h2/EDX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # . new(heap, 2, h2) - # . . push args - 52/push-EDX - 68/push 2/imm32/size - 56/push-ESI - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(h1->address, h2->address, msg) - # . . push args - 68/push "F - test-lookup-failure"/imm32 - ff 6/subop/push 1/mod/*+disp8 2/rm32/ECX . . . . 4/disp8 . # push *(EDX+4) - 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 - # lookup(h1) should crash - # . . push args - 51/push-ECX - # . . call - e8/call lookup/disp32 - # should never get past this point - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -# Monotonically increasing counter for calls to 'new' -Next-alloc-id: - 1/imm32 - -# . . vim:nowrap:textwidth=0 |