start using the new carry flag

Skimping on tests; the code changes seem pretty trivial. Will this fix
CI?!
This commit is contained in:
Kartik Agaram 2019-05-13 17:27:45 -07:00
parent 2b9925c708
commit 6f6d458fcd
18 changed files with 96 additions and 60 deletions

View File

@ -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")

View File

@ -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"
);
}

View File

@ -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"
);
}

View File

@ -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"
);
}

View File

@ -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() {

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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)

View File

@ -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)

View File

@ -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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.