diff --git a/linux/bootstrap/017jump_disp8.cc b/linux/bootstrap/017jump_disp8.cc index 30e60a74..37df6d5b 100644 --- a/linux/bootstrap/017jump_disp8.cc +++ b/linux/bootstrap/017jump_disp8.cc @@ -405,3 +405,27 @@ void test_jle_disp8_greater() { ); CHECK_TRACE_DOESNT_CONTAIN("run: jump 5"); } + +//:: jump if overflow + +:(before "End Initialize Op Names") +put_new(Name, "70", "jump disp8 bytes away if OF is set (jcc/jo)"); +put_new(Name, "71", "jump disp8 bytes away if OF is unset (jcc/jno)"); + +:(before "End Single-Byte Opcodes") +case 0x70: { // jump disp8 if OF is set + const int8_t offset = static_cast(next()); + if (OF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} +case 0x71: { // jump disp8 if OF is unset + const int8_t offset = static_cast(next()); + if (!OF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} diff --git a/linux/bootstrap/018jump_disp32.cc b/linux/bootstrap/018jump_disp32.cc index e77bc584..75fb576a 100644 --- a/linux/bootstrap/018jump_disp32.cc +++ b/linux/bootstrap/018jump_disp32.cc @@ -405,3 +405,27 @@ void test_jle_disp32_greater() { ); CHECK_TRACE_DOESNT_CONTAIN("run: jump 5"); } + +//:: jump if overflow + +:(before "End Initialize Op Names") +put_new(Name_0f, "80", "jump disp32 bytes away if OF is set (jcc/jo)"); +put_new(Name_0f, "81", "jump disp32 bytes away if OF is unset (jcc/jno)"); + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x80: { // jump disp8 if OF is set + const int32_t offset = next32(); + if (OF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} +case 0x81: { // jump disp8 if OF is unset + const int32_t offset = next32(); + if (!OF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} diff --git a/linux/branches.mu b/linux/branches.mu new file mode 100644 index 00000000..411eaa0d --- /dev/null +++ b/linux/branches.mu @@ -0,0 +1,40 @@ +fn foo { + $foo: { + break-if-= + break-if-= $foo + break-if-!= + break-if-!= $foo + break-if-<= + break-if-<= $foo + break-if->= + break-if->= $foo + break-if-< + break-if-< $foo + break-if-> + break-if-> $foo + break-if-carry + break-if-carry $foo + break-if-overflow + break-if-overflow $foo + loop-if-= + loop-if-= $foo + loop-if-!= + loop-if-!= $foo + loop-if-<= + loop-if-<= $foo + loop-if->= + loop-if->= $foo + loop-if-< + loop-if-< $foo + loop-if-> + loop-if-> $foo + loop-if-carry + loop-if-carry $foo + loop-if-not-carry + loop-if-not-carry $foo + loop-if-overflow + loop-if-overflow $foo + loop-if-not-overflow + loop-if-not-overflow $foo + } +} diff --git a/linux/branches.out b/linux/branches.out new file mode 100644 index 00000000..878a91e5 --- /dev/null +++ b/linux/branches.out @@ -0,0 +1,161 @@ +== code +foo: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + { +$foo:0x00000001:loop: + { +$foo:loop: + { + 0f 85/jump-if-!= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 85/jump-if-!= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 84/jump-if-= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 84/jump-if-= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8f/jump-if-> break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8f/jump-if-> break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8c/jump-if-< break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8c/jump-if-< break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8d/jump-if->= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8d/jump-if->= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8e/jump-if-<= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 8e/jump-if-<= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 83/jump-if-addr>= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 83/jump-if-addr>= break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 81/jump-if-not-overflow break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 81/jump-if-not-overflow break/disp32 + e9/jump $foo:break/disp32 + } + { + 0f 85/jump-if-!= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 85/jump-if-!= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 84/jump-if-= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 84/jump-if-= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8f/jump-if-> break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8f/jump-if-> break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8c/jump-if-< break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8c/jump-if-< break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8d/jump-if->= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8d/jump-if->= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8e/jump-if-<= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 8e/jump-if-<= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 83/jump-if-addr>= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 83/jump-if-addr>= break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 82/jump-if-addr< break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 82/jump-if-addr< break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 81/jump-if-not-overflow break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 81/jump-if-not-overflow break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 80/jump-if-overflow break/disp32 + e9/jump $foo:loop/disp32 + } + { + 0f 80/jump-if-overflow break/disp32 + e9/jump $foo:loop/disp32 + } + } +$foo:break: + } +$foo:0x00000001:break: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return diff --git a/linux/mu b/linux/mu index 74374bee..2508cda4 100755 Binary files a/linux/mu and b/linux/mu differ diff --git a/linux/mu.subx b/linux/mu.subx index 07ba75a8..93065326 100644 --- a/linux/mu.subx +++ b/linux/mu.subx @@ -27610,9 +27610,9 @@ $emit-reverse-break:end: # Table from Mu branch instructions to the reverse SubX opcodes for them. Reverse-branch: # (table (handle array byte) (handle array byte)) # a table is a stream - 0x1c0/imm32/write + 0x240/imm32/write 0/imm32/read - 0x1c0/imm32/size + 0x240/imm32/size # data 0x11/imm32/alloc-id _string-break-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 0x11/imm32/alloc-id _string-loop-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 @@ -27642,6 +27642,14 @@ Reverse-branch: # (table (handle array byte) (handle array byte)) 0x11/imm32/alloc-id _string-loop-if-float<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 0x11/imm32/alloc-id _string-break-if-float>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 0x11/imm32/alloc-id _string-loop-if-float>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-carry/imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-carry/imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-not-carry/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-not-carry/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-overflow/imm32 0x11/imm32/alloc-id _string_0f_81_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-overflow/imm32 0x11/imm32/alloc-id _string_0f_81_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-not-overflow/imm32 0x11/imm32/alloc-id _string_0f_80_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-not-overflow/imm32 0x11/imm32/alloc-id _string_0f_80_jump_label/imm32 == code @@ -32836,6 +32844,82 @@ _Primitive-break-if->: # (payload primitive) 0/imm32/no-xm32 0/imm32/no-x32 0x11/imm32/alloc-id:fake + _Primitive-break-if-carry/imm32/next +_Primitive-break-if-carry: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-carry/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-not-carry/imm32/next +_Primitive-break-if-not-carry: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-not-carry/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-overflow/imm32/next +_Primitive-break-if-overflow: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-overflow/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_80_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-not-overflow/imm32/next +_Primitive-break-if-not-overflow: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-not-overflow/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_81_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake _Primitive-break/imm32/next _Primitive-break: # (payload primitive) 0x11/imm32/alloc-id:fake:payload @@ -33045,6 +33129,82 @@ _Primitive-loop-if->: # (payload primitive) 0/imm32/no-xm32 0/imm32/no-x32 0x11/imm32/alloc-id:fake + _Primitive-loop-if-carry/imm32/next +_Primitive-loop-if-carry: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-carry/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-not-carry/imm32/next +_Primitive-loop-if-not-carry: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-not-carry/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-overflow/imm32/next +_Primitive-loop-if-overflow: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-overflow/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_80_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-not-overflow/imm32/next +_Primitive-loop-if-not-overflow: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-not-overflow/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_81_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake _Primitive-loop/imm32/next # we probably don't need an unconditional break _Primitive-loop: # (payload primitive) 0x11/imm32/alloc-id:fake:payload @@ -33891,6 +34051,26 @@ _string-break-if-float>=: # (payload array byte) # "break-if-float>=" 0x10/imm32/size 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/= +_string-break-if-carry: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-carry" + 0xe/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y +_string-break-if-not-carry: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-not-carry" + 0x12/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y +_string-break-if-overflow: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-overflow" + 0x11/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w +_string-break-if-not-overflow: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-not-overflow" + 0x15/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w _string-compare: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "compare" @@ -33910,12 +34090,12 @@ _string-copy-byte: 0x11/imm32/alloc-id:fake:payload # "copy-byte" 0x9/imm32/size - 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e + 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x62/b 0x79/y 0x74/t 0x65/e _string-copy-byte-to: 0x11/imm32/alloc-id:fake:payload # "copy-byte-to" 0xc/imm32/size - 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o + 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/dash 0x74/t 0x6f/o _string-decrement: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "decrement" @@ -34001,6 +34181,26 @@ _string-loop-if-float>=: # (payload array byte) # "loop-if-float>=" 0xf/imm32/size 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/= +_string-loop-if-carry: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-carry" + 0xd/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y +_string-loop-if-not-carry: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-not-carry" + 0x11/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y +_string-loop-if-overflow: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-overflow" + 0x10/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w +_string-loop-if-not-overflow: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-not-overflow" + 0x14/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w _string-multiply: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "multiply" @@ -34045,12 +34245,12 @@ _string-square-root: 0x11/imm32/alloc-id:fake:payload # "square-root" 0xb/imm32/size - 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t + 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t _string-inverse-square-root: 0x11/imm32/alloc-id:fake:payload # "inverse-square-root" 0x13/imm32/size - 0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/- 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t + 0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/dash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t _string-negate: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "negate" @@ -34133,6 +34333,36 @@ _string_0d_or_with_eax: # (payload array byte) # "0d/or-with-eax" 0xe/imm32/size 0x30/0 0x64/d 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x +_string_0f_80_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 80/jump-if-overflow" + 0x16/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w +_string_0f_80_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 80/jump-if-overflow break/disp32" + 0x23/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +_string_0f_80_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 80/jump-if-overflow loop/disp32" + 0x22/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +_string_0f_81_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 81/jump-if-not-overflow" + 0x1a/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w +_string_0f_81_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 81/jump-if-not-overflow break/disp32" + 0x27/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +_string_0f_81_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 81/jump-if-not-overflow loop/disp32" + 0x26/imm32/size + 0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 _string_0f_82_jump_label: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "0f 82/jump-if-addr<" @@ -34176,7 +34406,7 @@ _string_0f_84_jump_break: # (payload array byte) _string_0f_84_jump_loop: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "0f 84/jump-if-= loop/disp32" - 0x1b/imm32/size + 0x1a/imm32/size 0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 _string_0f_85_jump_label: # (payload array byte) 0x11/imm32/alloc-id:fake:payload @@ -34527,12 +34757,12 @@ _string_8a_copy_byte: 0x11/imm32/alloc-id:fake:payload # "8a/byte->" 0x9/imm32/size - 0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/> + 0x38/8 0x61/a 0x2f/slash 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/dash 0x3e/> _string_88_copy_byte: 0x11/imm32/alloc-id:fake:payload # "88/byte<-" 0x9/imm32/size - 0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/- + 0x38/8 0x38/8 0x2f/slash 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/- _string_8d_copy_address: # (payload array byte) 0x11/imm32/alloc-id:fake:payload # "8d/copy-address" diff --git a/mu_instructions b/mu_instructions index 10d00f10..7a458660 100644 --- a/mu_instructions +++ b/mu_instructions @@ -293,6 +293,31 @@ Similar float variants like `break-if-float<` are aliases for the corresponding `addr` equivalents. The x86 instruction set stupidly has floating-point operations only update a subset of flags. +Four sets of conditional jumps are useful for detecting overflow. + +break-if-carry => "0f 82/jump-if-carry break/disp32" +break-if-carry label => "0f 82/jump-if-carry " label "/disp32" +loop-if-carry => "0f 82/jump-if-carry break/disp32" +loop-if-carry label => "0f 82/jump-if-carry " label "/disp32" + +break-if-not-carry => "0f 83/jump-if-not-carry break/disp32" +break-if-not-carry label => "0f 83/jump-if-not-carry " label "/disp32" +loop-if-not-carry => "0f 83/jump-if-not-carry break/disp32" +loop-if-not-carry label => "0f 83/jump-if-not-carry " label "/disp32" + +break-if-overflow => "0f 80/jump-if-overflow break/disp32" +break-if-overflow label => "0f 80/jump-if-overflow " label ":break/disp32" +loop-if-overflow => "0f 80/jump-if-overflow loop/disp32" +loop-if-overflow label => "0f 80/jump-if-overflow " label ":loop/disp32" + +break-if-not-overflow => "0f 81/jump-if-not-overflow break/disp32" +break-if-not-overflow label => "0f 81/jump-if-not-overflow " label ":break/disp32" +loop-if-not-overflow => "0f 81/jump-if-not-overflow loop/disp32" +loop-if-not-overflow label => "0f 81/jump-if-not-overflow " label ":loop/disp32" + +All this relies on a convention that every `{}` block is delimited by labels +ending in `:loop` and `:break`. + ## Returns The `return` instruction cleans up variable declarations just like an unconditional diff --git a/subx_opcodes b/subx_opcodes index f8bdc045..19fa1dbd 100644 --- a/subx_opcodes +++ b/subx_opcodes @@ -51,6 +51,8 @@ Opcodes currently supported by SubX: 5f: pop top of stack to EDI (pop) 68: push imm32 to stack (push) 69: multiply rm32 by imm32 and store result in r32 (imul) + 70: jump disp8 bytes away if OF is set (jcc/jo) + 71: jump disp8 bytes away if OF is unset (jcc/jno) 72: jump disp8 bytes away if lesser (addr, float), if CF is set (jcc/jb/jnae) 73: jump disp8 bytes away if greater or equal (addr, float), if CF is unset (jcc/jae/jnb) 74: jump disp8 bytes away if equal, if ZF is set (jcc/jz/je) @@ -91,6 +93,8 @@ Opcodes currently supported by SubX: f7: negate/multiply/divide rm32 (with EAX and EDX if necessary) depending on subop (neg/mul/idiv) ff: increment/decrement/jump/push/call rm32 based on subop (inc/dec/jmp/push/call) 0f 2f: compare: set CF if x32 < xm32 (comiss) + 0f 80: jump disp32 bytes away if OF is set (jcc/jo) + 0f 81: jump disp32 bytes away if OF is unset (jcc/jno) 0f 82: jump disp32 bytes away if lesser (addr, float), if CF is set (jcc/jb/jnae) 0f 83: jump disp32 bytes away if greater or equal (addr, float), if CF is unset (jcc/jae/jnb) 0f 84: jump disp32 bytes away if equal, if ZF is set (jcc/jz/je)