about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-03-20 22:59:36 -0700
committerKartik Agaram <vc@akkartik.com>2019-03-20 22:59:36 -0700
commit19aca82c249666fcc679f61dd3f8250e1f373e5c (patch)
tree8e9ac9c1f74e52daca93393358a098be651ceb5a /subx
parent4068f0ca5b3a380790794a986897815d8b6a45a8 (diff)
downloadmu-19aca82c249666fcc679f61dd3f8250e1f373e5c.tar.gz
5012
Add a bounds-check to `next-word`.
Diffstat (limited to 'subx')
-rw-r--r--subx/013direct_addressing.cc6
-rwxr-xr-xsubx/apps/packbin21171 -> 21327 bytes
-rw-r--r--subx/apps/pack.subx57
3 files changed, 61 insertions, 2 deletions
diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc
index 8f554772..2a984dfe 100644
--- a/subx/013direct_addressing.cc
+++ b/subx/013direct_addressing.cc
@@ -34,6 +34,7 @@ case 0x01: {  // add r32 to r/m32
 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
 // We return a pointer so that instructions can write to multiple bytes in
 // 'Mem' at once.
+// beware: will eventually have side-effects
 int32_t* effective_address(uint8_t modrm) {
   const uint8_t mod = (modrm>>6);
   // ignore middle 3 'reg opcode' bits
@@ -43,9 +44,12 @@ int32_t* effective_address(uint8_t modrm) {
     trace(Callstack_depth+1, "run") << "r/m32 is " << rname(rm) << end();
     return &Reg[rm].i;
   }
-  return mem_addr_i32(effective_address_number(modrm));
+  uint32_t addr = effective_address_number(modrm);
+  trace(Callstack_depth+1, "run") << "effective address contains " << read_mem_i32(addr) << end();
+  return mem_addr_i32(addr);
 }
 
+// beware: will eventually have side-effects
 uint32_t effective_address_number(uint8_t modrm) {
   const uint8_t mod = (modrm>>6);
   // ignore middle 3 'reg opcode' bits
diff --git a/subx/apps/pack b/subx/apps/pack
index e3e7ea66..9b261693 100755
--- a/subx/apps/pack
+++ b/subx/apps/pack
Binary files differdiff --git a/subx/apps/pack.subx b/subx/apps/pack.subx
index 8a82fcb5..9156f965 100644
--- a/subx/apps/pack.subx
+++ b/subx/apps/pack.subx
@@ -23,7 +23,7 @@
 Entry:  # run tests if necessary, convert stdin if not
 
 #?     # for debugging: run a single test
-#?     e8/call test-convert-passes-segment-headers-through/disp32
+#?     e8/call test-next-word-returns-empty-string-on-eof/disp32
 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 #?     eb/jump  $main:end/disp8
 
@@ -711,6 +711,7 @@ test-convert-instruction-passes-labels-through:
     c3/return
 
 # (re)compute the bounds of the next word in the line
+# return empty string on reaching end of file
 next-word:  # line : (address stream byte), out : (address slice)
     # . prolog
     55/push-EBP
@@ -732,6 +733,18 @@ next-word:  # line : (address stream byte), out : (address slice)
     e8/call  skip-chars-matching/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$next-word:check0:
+    # if (line->read >= line->write) clear out and return
+    # . EAX = line->read
+    8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ESI+4) to EAX
+    # . if (EAX < line->write) goto next check
+    3b/compare                      0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # compare EAX with *ESI
+    7c/jump-if-lesser  $next-word:check1/disp8
+    # . return out = {0, 0}
+    c7          0/subop/copy        0/mod/direct    7/rm32/EDI    .           .             .           .           .               0/imm32           # copy to *EDI
+    c7          0/subop/copy        1/mod/*+disp8   7/rm32/EDI    .           .             .           .           4/disp8         0/imm32           # copy to *(EDI+4)
+    eb/jump  $next-word:end/disp8
+$next-word:check1:
     # out->start = &line->data[line->read]
     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
@@ -901,6 +914,48 @@ test-next-word-returns-whole-comment:
     5d/pop-to-EBP
     c3/return
 
+test-next-word-returns-empty-string-on-eof:
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # setup
+    # . clear-stream(_test-stream)
+    # . . push args
+    68/push  _test-stream/imm32
+    # . . call
+    e8/call  clear-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # var slice/ECX = {0, 0}
+    68/push  0/imm32/end
+    68/push  0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # write nothing to _test-stream
+    # next-word(_test-stream, slice)
+    # . . push args
+    51/push-ECX
+    68/push  _test-stream/imm32
+    # . . call
+    e8/call  next-word/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # check-ints-equal(slice->end - slice->start, 0, msg)
+    # . . push args
+    68/push  "F - test-next-word-returns-empty-string-on-eof"/imm32
+    68/push  0/imm32
+    # . . push slice->end - slice->start
+    8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+    2b/subtract                     0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract *ECX from EAX
+    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
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
 has-metadata?:  # word : (address slice), s : (address string) -> EAX : boolean
     # pseudocode:
     #   var twig : &slice = next-token-from-slice(word->start, word->end, '/')  # skip name