about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-05-13 17:27:45 -0700
committerKartik Agaram <vc@akkartik.com>2019-05-13 17:56:20 -0700
commit6f6d458fcd619810d657fe3e1b82b4d1970dc2df (patch)
tree445ef65727d4453e9a13a01ecae151da924ccd97 /subx
parent2b9925c70835b102d26f27f2a32044552d0b6426 (diff)
downloadmu-6f6d458fcd619810d657fe3e1b82b4d1970dc2df.tar.gz
start using the new carry flag
Skimping on tests; the code changes seem pretty trivial. Will this fix
CI?!
Diffstat (limited to 'subx')
-rw-r--r--subx/012elf.cc23
-rw-r--r--subx/013direct_addressing.cc14
-rw-r--r--subx/014indirect_addressing.cc23
-rw-r--r--subx/015immediate_addressing.cc6
-rw-r--r--subx/017jump_disp8.cc54
-rw-r--r--subx/019functions.cc22
-rw-r--r--subx/031check_operands.cc4
-rw-r--r--subx/040---tests.cc4
-rw-r--r--subx/057write.subx2
-rw-r--r--subx/060read.subx2
-rw-r--r--subx/062write-stream.subx2
-rwxr-xr-xsubx/apps/assortbin21809 -> 21809 bytes
-rwxr-xr-xsubx/apps/crenshaw2-1bin18968 -> 18968 bytes
-rwxr-xr-xsubx/apps/crenshaw2-1bbin19527 -> 19527 bytes
-rwxr-xr-xsubx/apps/factorialbin17884 -> 17884 bytes
-rwxr-xr-xsubx/apps/handlebin18711 -> 18711 bytes
-rwxr-xr-xsubx/apps/hexbin21977 -> 21977 bytes
-rwxr-xr-xsubx/apps/packbin36569 -> 36569 bytes
18 files changed, 96 insertions, 60 deletions
diff --git a/subx/012elf.cc b/subx/012elf.cc
index 0fa9d793..0ae0b108 100644
--- a/subx/012elf.cc
+++ b/subx/012elf.cc
@@ -141,20 +141,17 @@ void load_segment_from_program_header(uint8_t* elf_contents, int segment_index,
 //   code:  0x09000000 -> 0x09ffffff (specified in ELF binary)
 //   data:  0x0a000000 -> 0x0affffff (specified in ELF binary)
 //   --- heap gets mmap'd somewhere here ---
-//   stack: 0x7dffffff -> 0x7d000000 (downward; not in ELF binary)
-//   argv hack: 0x7f000000 -> 0x7fffffff (not in ELF binary)
+//   stack: 0xbdffffff -> 0xbd000000 (downward; not in ELF binary)
+//   argv hack: 0xbf000000 -> 0xbfffffff (not in ELF binary)
 //
-// For now we avoid addresses with the most significant bit set; SubX doesn't
-// support unsigned comparison yet (https://github.com/akkartik/mu/issues/30)
-// Once we do, we can go up to 0xc0000000; higher addresses are reserved for
-// the Linux kernel.
-const int CODE_SEGMENT      = 0x09000000;
-const int DATA_SEGMENT      = 0x0a000000;
-const int START_HEAP        = 0x0b000000;
-const int END_HEAP          = 0x7d000000;
-const int STACK_SEGMENT     = 0x7d000000;
-const int AFTER_STACK       = 0x7e000000;
-const int ARGV_DATA_SEGMENT = 0x7f000000;
+// Addresses above 0xc0000000 are reserved for the Linux kernel.
+const uint32_t CODE_SEGMENT      = 0x09000000;
+const uint32_t DATA_SEGMENT      = 0x0a000000;
+const uint32_t START_HEAP        = 0x0b000000;
+const uint32_t END_HEAP          = 0xbd000000;
+const uint32_t STACK_SEGMENT     = 0xbd000000;
+const uint32_t AFTER_STACK       = 0xbe000000;
+const uint32_t ARGV_DATA_SEGMENT = 0xbf000000;
 // When updating the above memory map, don't forget to update `mmap`'s
 // implementation in the 'syscalls' layer.
 :(before "End Dump Info for Instruction")
diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc
index a2331213..2914e0dd 100644
--- a/subx/013direct_addressing.cc
+++ b/subx/013direct_addressing.cc
@@ -1183,8 +1183,8 @@ put_new(Name, "57", "push EDI to stack (push)");
 
 :(code)
 void test_push_r32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000008;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000008;
   Reg[EBX].i = 0x0000000a;
   run(
       "== 0x1\n"  // code segment
@@ -1193,7 +1193,7 @@ void test_push_r32() {
   );
   CHECK_TRACE_CONTENTS(
       "run: push EBX\n"
-      "run: decrementing ESP to 0x7d000004\n"
+      "run: decrementing ESP to 0xbd000004\n"
       "run: pushing value 0x0000000a\n"
   );
 }
@@ -1228,9 +1228,9 @@ put_new(Name, "5f", "pop top of stack to EDI (pop)");
 
 :(code)
 void test_pop_r32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000008;
-  write_mem_i32(0x7d000008, 0x0000000a);  // ..before this write
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000008;
+  write_mem_i32(0xbd000008, 0x0000000a);  // ..before this write
   run(
       "== 0x1\n"  // code segment
       // op     ModR/M  SIB   displacement  immediate
@@ -1241,7 +1241,7 @@ void test_pop_r32() {
   CHECK_TRACE_CONTENTS(
       "run: pop into EBX\n"
       "run: popping value 0x0000000a\n"
-      "run: incrementing ESP to 0x7d00000c\n"
+      "run: incrementing ESP to 0xbd00000c\n"
   );
 }
 
diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc
index e89a9986..a281921f 100644
--- a/subx/014indirect_addressing.cc
+++ b/subx/014indirect_addressing.cc
@@ -561,7 +561,6 @@ case 0x3b: {  // set SF if r32 < r/m32
   const uint8_t modrm = next();
   const uint8_t reg1 = (modrm>>3)&0x7;
   trace(Callstack_depth+1, "run") << "compare " << rname(reg1) << " with r/m32" << end();
-  const int32_t signed_arg1 = Reg[reg1].i;
   const int32_t* signed_arg2 = effective_address(modrm);
   const int32_t signed_difference = Reg[reg1].i - *signed_arg2;
   SF = (signed_difference < 0);
@@ -732,8 +731,8 @@ void test_jump_mem_at_r32() {
       // op     ModR/M  SIB   displacement  immediate
       "  ff     20                                    \n"  // jump to *EAX
       // ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX)
-      "  05                                 00 00 00 01\n"
-      "  05                                 00 00 00 02\n"
+      "  b8                                 00 00 00 01\n"
+      "  b8                                 00 00 00 02\n"
       "== 0x2000\n"  // data segment
       "08 00 00 00\n"  // 0x00000008
   );
@@ -742,9 +741,9 @@ void test_jump_mem_at_r32() {
       "run: jump to r/m32\n"
       "run: effective address is 0x00002000 (EAX)\n"
       "run: jumping to 0x00000008\n"
-      "run: 0x00000008 opcode: 05\n"
+      "run: 0x00000008 opcode: b8\n"
   );
-  CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: 05");
+  CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: b8");
 }
 
 :(before "End Op ff Subops")
@@ -761,8 +760,8 @@ case 4: {  // jump to r/m32
 :(code)
 void test_push_mem_at_r32() {
   Reg[EAX].i = 0x2000;
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000014;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000014;
   run(
       "== 0x1\n"  // code segment
       // op     ModR/M  SIB   displacement  immediate
@@ -773,7 +772,7 @@ void test_push_mem_at_r32() {
   CHECK_TRACE_CONTENTS(
       "run: push r/m32\n"
       "run: effective address is 0x00002000 (EAX)\n"
-      "run: decrementing ESP to 0x7d000010\n"
+      "run: decrementing ESP to 0xbd000010\n"
       "run: pushing value 0x000000af\n"
   );
 }
@@ -794,9 +793,9 @@ put_new(Name, "8f", "pop top of stack to rm32 (pop)");
 :(code)
 void test_pop_mem_at_r32() {
   Reg[EAX].i = 0x60;
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000000;
-  write_mem_i32(0x7d000000, 0x00000030);
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000000;
+  write_mem_i32(0xbd000000, 0x00000030);
   run(
       "== 0x1\n"  // code segment
       // op     ModR/M  SIB   displacement  immediate
@@ -807,7 +806,7 @@ void test_pop_mem_at_r32() {
       "run: pop into r/m32\n"
       "run: effective address is 0x00000060 (EAX)\n"
       "run: popping value 0x00000030\n"
-      "run: incrementing ESP to 0x7d000004\n"
+      "run: incrementing ESP to 0xbd000004\n"
   );
 }
 
diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc
index 6bf394df..4210c024 100644
--- a/subx/015immediate_addressing.cc
+++ b/subx/015immediate_addressing.cc
@@ -1191,8 +1191,8 @@ put_new(Name, "68", "push imm32 to stack (push)");
 
 :(code)
 void test_push_imm32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000014;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000014;
   run(
       "== 0x1\n"  // code segment
       // op     ModR/M  SIB   displacement  immediate
@@ -1200,7 +1200,7 @@ void test_push_imm32() {
   );
   CHECK_TRACE_CONTENTS(
       "run: push imm32 0x000000af\n"
-      "run: ESP is now 0x7d000010\n"
+      "run: ESP is now 0xbd000010\n"
       "run: contents at ESP: 0x000000af\n"
   );
 }
diff --git a/subx/017jump_disp8.cc b/subx/017jump_disp8.cc
index 22ae6567..35cc1331 100644
--- a/subx/017jump_disp8.cc
+++ b/subx/017jump_disp8.cc
@@ -135,7 +135,8 @@ void test_jne_rel8_fail() {
 //:: jump if greater
 
 :(before "End Initialize Op Names")
-put_new(Name, "7f", "jump disp8 bytes away if greater, if ZF is unset and SF == OF (jcc/jg/jnle)");
+put_new(Name, "7f", "jump disp8 bytes away if greater (signed), if ZF is unset and SF == OF (jcc/jg/jnle)");
+put_new(Name, "77", "jump disp8 bytes away if greater (unsigned), if ZF is unset and CF is unset (jcc/ja/jnbe)");
 
 :(code)
 void test_jg_rel8_success() {
@@ -158,9 +159,17 @@ void test_jg_rel8_success() {
 }
 
 :(before "End Single-Byte Opcodes")
-case 0x7f: {  // jump rel8 if !SF and !ZF
+case 0x7f: {  // jump rel8 if SF == OF and !ZF
   const int8_t offset = static_cast<int>(next());
-  if (!ZF && SF == OF) {
+  if (SF == OF && !ZF) {
+    trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
+    EIP += offset;
+  }
+  break;
+}
+case 0x77: {  // jump rel8 if !CF and !ZF
+  const int8_t offset = static_cast<int>(next());
+  if (!CF && !ZF) {
     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
     EIP += offset;
   }
@@ -190,7 +199,8 @@ void test_jg_rel8_fail() {
 //:: jump if greater or equal
 
 :(before "End Initialize Op Names")
-put_new(Name, "7d", "jump disp8 bytes away if greater or equal, if SF == OF (jcc/jge/jnl)");
+put_new(Name, "7d", "jump disp8 bytes away if greater or equal (signed), if SF == OF (jcc/jge/jnl)");
+put_new(Name, "73", "jump disp8 bytes away if greater or equal (unsigned), if CF is unset (jcc/jae/jnb)");
 
 :(code)
 void test_jge_rel8_success() {
@@ -212,7 +222,7 @@ void test_jge_rel8_success() {
 }
 
 :(before "End Single-Byte Opcodes")
-case 0x7d: {  // jump rel8 if !SF
+case 0x7d: {  // jump rel8 if SF == OF
   const int8_t offset = static_cast<int>(next());
   if (SF == OF) {
     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
@@ -220,6 +230,14 @@ case 0x7d: {  // jump rel8 if !SF
   }
   break;
 }
+case 0x73: {  // jump rel8 if !CF
+  const int8_t offset = static_cast<int>(next());
+  if (!CF) {
+    trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
+    EIP += offset;
+  }
+  break;
+}
 
 :(code)
 void test_jge_rel8_fail() {
@@ -243,7 +261,8 @@ void test_jge_rel8_fail() {
 //:: jump if lesser
 
 :(before "End Initialize Op Names")
-put_new(Name, "7c", "jump disp8 bytes away if lesser, if SF != OF (jcc/jl/jnge)");
+put_new(Name, "7c", "jump disp8 bytes away if lesser (signed), if SF != OF (jcc/jl/jnge)");
+put_new(Name, "72", "jump disp8 bytes away if lesser (unsigned), if CF is set (jcc/jb/jnae)");
 
 :(code)
 void test_jl_rel8_success() {
@@ -266,7 +285,7 @@ void test_jl_rel8_success() {
 }
 
 :(before "End Single-Byte Opcodes")
-case 0x7c: {  // jump rel8 if SF and !ZF
+case 0x7c: {  // jump rel8 if SF != OF
   const int8_t offset = static_cast<int>(next());
   if (SF != OF) {
     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
@@ -274,6 +293,14 @@ case 0x7c: {  // jump rel8 if SF and !ZF
   }
   break;
 }
+case 0x72: {  // jump rel8 if CF
+  const int8_t offset = static_cast<int>(next());
+  if (CF) {
+    trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
+    EIP += offset;
+  }
+  break;
+}
 
 :(code)
 void test_jl_rel8_fail() {
@@ -298,7 +325,8 @@ void test_jl_rel8_fail() {
 //:: jump if lesser or equal
 
 :(before "End Initialize Op Names")
-put_new(Name, "7e", "jump disp8 bytes away if lesser or equal, if ZF is set or SF != OF (jcc/jle/jng)");
+put_new(Name, "7e", "jump disp8 bytes away if lesser or equal (signed), if ZF is set or SF != OF (jcc/jle/jng)");
+put_new(Name, "76", "jump disp8 bytes away if lesser or equal (unsigned), if ZF is set or CF is set (jcc/jbe/jna)");
 
 :(code)
 void test_jle_rel8_equal() {
@@ -341,7 +369,7 @@ void test_jle_rel8_lesser() {
 }
 
 :(before "End Single-Byte Opcodes")
-case 0x7e: {  // jump rel8 if SF or ZF
+case 0x7e: {  // jump rel8 if ZF or SF != OF
   const int8_t offset = static_cast<int>(next());
   if (ZF || SF != OF) {
     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
@@ -349,6 +377,14 @@ case 0x7e: {  // jump rel8 if SF or ZF
   }
   break;
 }
+case 0x76: {  // jump rel8 if ZF or CF
+  const int8_t offset = static_cast<int>(next());
+  if (ZF || CF) {
+    trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
+    EIP += offset;
+  }
+  break;
+}
 
 :(code)
 void test_jle_rel8_greater() {
diff --git a/subx/019functions.cc b/subx/019functions.cc
index 27fb4fb0..00da8397 100644
--- a/subx/019functions.cc
+++ b/subx/019functions.cc
@@ -5,8 +5,8 @@ put_new(Name, "e8", "call disp32 (call)");
 
 :(code)
 void test_call_disp32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000064;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000064;
   run(
       "== 0x1\n"  // code segment
       // op     ModR/M  SIB   displacement  immediate
@@ -15,7 +15,7 @@ void test_call_disp32() {
   );
   CHECK_TRACE_CONTENTS(
       "run: call imm32 0x000000a0\n"
-      "run: decrementing ESP to 0x7d000060\n"
+      "run: decrementing ESP to 0xbd000060\n"
       "run: pushing value 0x00000006\n"
       "run: jumping to 0x000000a6\n"
   );
@@ -37,8 +37,8 @@ case 0xe8: {  // call disp32 relative to next EIP
 
 :(code)
 void test_call_r32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000064;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000064;
   Reg[EBX].u = 0x000000a0;
   run(
       "== 0x1\n"  // code segment
@@ -49,7 +49,7 @@ void test_call_r32() {
   CHECK_TRACE_CONTENTS(
       "run: call to r/m32\n"
       "run: r/m32 is EBX\n"
-      "run: decrementing ESP to 0x7d000060\n"
+      "run: decrementing ESP to 0xbd000060\n"
       "run: pushing value 0x00000003\n"
       "run: jumping to 0x000000a3\n"
   );
@@ -68,8 +68,8 @@ case 2: {  // call function pointer at r/m32
 
 :(code)
 void test_call_mem_at_r32() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000064;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000064;
   Reg[EBX].u = 0x2000;
   run(
       "== 0x1\n"  // code segment
@@ -82,7 +82,7 @@ void test_call_mem_at_r32() {
   CHECK_TRACE_CONTENTS(
       "run: call to r/m32\n"
       "run: effective address is 0x00002000 (EBX)\n"
-      "run: decrementing ESP to 0x7d000060\n"
+      "run: decrementing ESP to 0xbd000060\n"
       "run: pushing value 0x00000003\n"
       "run: jumping to 0x000000a3\n"
   );
@@ -95,8 +95,8 @@ put_new(Name, "c3", "return from most recent unfinished call (ret)");
 
 :(code)
 void test_ret() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000064;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000064;
   write_mem_u32(Reg[ESP].u, 0x10);
   run(
       "== 0x1\n"  // code segment
diff --git a/subx/031check_operands.cc b/subx/031check_operands.cc
index 9590979f..aad84da6 100644
--- a/subx/031check_operands.cc
+++ b/subx/031check_operands.cc
@@ -152,8 +152,12 @@ void init_permitted_operands() {
 
   // jump
   put(Permitted_operands, "eb", 0x04);
+  put(Permitted_operands, "72", 0x04);
+  put(Permitted_operands, "73", 0x04);
   put(Permitted_operands, "74", 0x04);
   put(Permitted_operands, "75", 0x04);
+  put(Permitted_operands, "76", 0x04);
+  put(Permitted_operands, "77", 0x04);
   put(Permitted_operands, "7c", 0x04);
   put(Permitted_operands, "7d", 0x04);
   put(Permitted_operands, "7e", 0x04);
diff --git a/subx/040---tests.cc b/subx/040---tests.cc
index 237bb811..e5949bbd 100644
--- a/subx/040---tests.cc
+++ b/subx/040---tests.cc
@@ -16,8 +16,8 @@ Transform.push_back(create_test_function);
 
 :(code)
 void test_run_test() {
-  Mem.push_back(vma(0x7d000000));  // manually allocate memory
-  Reg[ESP].u = 0x7d000100;
+  Mem.push_back(vma(0xbd000000));  // manually allocate memory
+  Reg[ESP].u = 0xbd000100;
   run(
       "== 0x1\n"  // code segment
       "main:\n"
diff --git a/subx/057write.subx b/subx/057write.subx
index 3135003b..455146ac 100644
--- a/subx/057write.subx
+++ b/subx/057write.subx
@@ -27,7 +27,7 @@ write:  # f : fd or (address stream), s : (address array byte) -> <void>
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # if (f < 0x08000000) _write(f, s) and return  # f can't be a user-mode address, so treat it as a kernel file descriptor
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x08000000/imm32  # compare *(EBP+8)
-    7d/jump-if-greater-or-equal  $write:fake/disp8
+    73/jump-if-greater-unsigned-or-equal  $write:fake/disp8
     # . . push args
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
diff --git a/subx/060read.subx b/subx/060read.subx
index cedafbf5..d377a1ad 100644
--- a/subx/060read.subx
+++ b/subx/060read.subx
@@ -51,7 +51,7 @@ read:  # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # if (f < 0x08000000) return _read(f, s)  # f can't be a user-mode address, so treat it as a kernel file descriptor
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x08000000/imm32  # compare *(EBP+8)
-    7d/jump-if-greater-or-equal  $read:fake/disp8
+    73/jump-if-greater-unsigned-or-equal  $read:fake/disp8
     # . . push args
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
diff --git a/subx/062write-stream.subx b/subx/062write-stream.subx
index 83268422..92c67dc2 100644
--- a/subx/062write-stream.subx
+++ b/subx/062write-stream.subx
@@ -21,7 +21,7 @@ write-stream:  # f : fd or (address stream), s : (address stream) -> <void>
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # if (f < 0x08000000) _write-stream(f, s), return  # f can't be a user-mode address, so treat it as a kernel file descriptor
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x08000000/imm32  # compare *(EBP+8)
-    7d/jump-if-greater-or-equal  $write-stream:fake/disp8
+    73/jump-if-greater-unsigned-or-equal  $write-stream:fake/disp8
     # . . push args
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
diff --git a/subx/apps/assort b/subx/apps/assort
index 3fbc3b7e..d2aaaf1a 100755
--- a/subx/apps/assort
+++ b/subx/apps/assort
Binary files differdiff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1
index ca1e52fa..3fbc9c33 100755
--- a/subx/apps/crenshaw2-1
+++ b/subx/apps/crenshaw2-1
Binary files differdiff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b
index 8a468ff5..71265ffe 100755
--- a/subx/apps/crenshaw2-1b
+++ b/subx/apps/crenshaw2-1b
Binary files differdiff --git a/subx/apps/factorial b/subx/apps/factorial
index 9ea9716b..4f5f7dc2 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/handle b/subx/apps/handle
index b32183db..520ca276 100755
--- a/subx/apps/handle
+++ b/subx/apps/handle
Binary files differdiff --git a/subx/apps/hex b/subx/apps/hex
index ed1d9eeb..667fbc1f 100755
--- a/subx/apps/hex
+++ b/subx/apps/hex
Binary files differdiff --git a/subx/apps/pack b/subx/apps/pack
index a4a20626..2b313f08 100755
--- a/subx/apps/pack
+++ b/subx/apps/pack
Binary files differ