about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-12-29 14:32:27 -0800
committerKartik Agaram <vc@akkartik.com>2018-12-29 14:32:27 -0800
commitc164f4fb6be4dcdf452e4276127a2cfabc32c33f (patch)
tree6f2953f8df9b233d760ad5bbc25a0e6236db4adc /subx
parentdd9ba09a7c74455f17afb515c377a217fa8be8bc (diff)
downloadmu-c164f4fb6be4dcdf452e4276127a2cfabc32c33f.tar.gz
4889 - playing with kinda-safe pointers
Diffstat (limited to 'subx')
-rw-r--r--subx/apps/handlebin0 -> 7639 bytes
-rw-r--r--subx/apps/handle.subx211
2 files changed, 211 insertions, 0 deletions
diff --git a/subx/apps/handle b/subx/apps/handle
new file mode 100644
index 00000000..ea73b522
--- /dev/null
+++ b/subx/apps/handle
Binary files differdiff --git a/subx/apps/handle.subx b/subx/apps/handle.subx
new file mode 100644
index 00000000..eda89945
--- /dev/null
+++ b/subx/apps/handle.subx
@@ -0,0 +1,211 @@
+# 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
+
+== 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
+
+# main:
+    e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+    # syscall(exit, Num-test-failures)
+    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+    b8/copy-to-EAX  1/imm32/exit
+    cd/syscall  0x80/imm8
+
+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
+    81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
+    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:  # - this test uses the bottom of the stack segment as scratch space
+    # . 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
+    # var ad/EAX : (address allocation-descriptor) = {0x0b000000, 0x0b00000a}
+    68/push  0x0b00000a/imm32/limit
+    68/push  0x0b000000/imm32/curr
+    89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EAX
+    # 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(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
+    # 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, 0x0b000000, msg)
+    # . . push args
+    68/push  "F - test-new: address of handle"/imm32
+    68/push  0x0b000000/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
+    # 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/direct    0/rm32/EAX    .           .             .           .           .               1/imm32           # copy 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-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/direct    0/rm32/EAX    .           .             .           .           .               1/imm32           # copy to *EAX
+    # . 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:
+    01 00 00 00  # 1
+
+# . . vim:nowrap:textwidth=0