diff --git a/subx/011run.cc b/subx/011run.cc index 236401b8..319cbfb3 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -13,15 +13,15 @@ put_new(Help, "syntax", "(start of line, or following a space).\n" "\n" "Each segment starts with a header line: a '==' delimiter followed by the name of\n" - "the segment.\n" + "the segment and a (sometimes approximate) starting address in memory.\n" + "The name 'code' is special; instructions to execute should always go here.\n" "\n" - "The first segment contains code and should be called 'code'.\n" - "The second segment should be called 'data'.\n" - "The resulting binary starts running from the start of the code segment by default.\n" + "The resulting binary starts running from the start of the segment by default.\n" "To start elsewhere in the code segment, define a special label called 'Entry'.\n" "\n" "Segments with the same name get merged together. This rule helps keep functions and\n" "their data close together in .subx files.\n" + "You don't have to specify the starting address after the first time.\n" "\n" "Lines consist of a series of words. Words can contain arbitrary metadata\n" "after a '/', but they can never contain whitespace. Metadata has no effect\n" @@ -35,16 +35,16 @@ put_new(Help, "syntax", cerr << " syntax\n"; :(code) -void test_add_imm32_to_EAX() { +void test_copy_imm32_to_EAX() { // At the lowest level, SubX programs are a series of hex bytes, each // (variable-length) instruction on one line. run( // Comments start with '#' and are ignored. "# comment\n" - // Segment headers start with '==' and a name or starting hex address. + // Segment headers start with '==', a name and a starting hex address. // There's usually one code and one data segment. The code segment // always comes first. - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // After the header, each segment consists of lines, and each line // consists of words separated by whitespace. @@ -107,6 +107,7 @@ struct program { }; :(before "struct program") struct segment { + string name; uint32_t start; vector lines; // End segment Fields @@ -132,6 +133,7 @@ struct word { :(code) void parse(istream& fin, program& out) { + segment* curr_segment = NULL; vector l; while (has_data(fin)) { string line_data; @@ -148,19 +150,25 @@ void parse(istream& fin, program& out) { if (word_data[0] == '#') break; // comment if (word_data == ".") continue; // comment token if (word_data == "==") { - flush(out, l); - string segment_title; - lin >> segment_title; - if (starts_with(segment_title, "0x")) { - segment s; - s.start = parse_int(segment_title); - sanity_check_program_segment(out, s.start); - if (trace_contains_errors()) continue; - trace(3, "parse") << "new segment from 0x" << HEXWORD << s.start << end(); - out.segments.push_back(s); + flush(curr_segment, l); + string segment_name; + lin >> segment_name; + curr_segment = find(out, segment_name); + if (curr_segment != NULL) { + trace(3, "parse") << "appending to segment '" << segment_name << "'" << end(); + } + else { + trace(3, "parse") << "new segment '" << segment_name << "'" << end(); + uint32_t seg_start = 0; + lin >> std::hex >> seg_start; + sanity_check_program_segment(out, seg_start); + out.segments.push_back(segment()); + curr_segment = &out.segments.back(); + curr_segment->name = segment_name; + curr_segment->start = seg_start; + if (trace_contains_errors()) continue; + trace(3, "parse") << "starts at address 0x" << HEXWORD << curr_segment->start << end(); } - // End Segment Parsing Special-cases(segment_title) - // todo: segment segment metadata break; // skip rest of line } if (word_data[0] == ':') { @@ -174,19 +182,27 @@ void parse(istream& fin, program& out) { if (!curr.words.empty()) l.push_back(curr); } - flush(out, l); + flush(curr_segment, l); trace(99, "parse") << "done" << end(); } -void flush(program& p, vector& lines) { +segment* find(program& p, const string& segment_name) { + for (int i = 0; i < SIZE(p.segments); ++i) { + if (p.segments.at(i).name == segment_name) + return &p.segments.at(i); + } + return NULL; +} + +void flush(segment* s, vector& lines) { if (lines.empty()) return; - if (p.segments.empty()) { + if (s == NULL) { raise << "input does not start with a '==' section header\n" << end(); return; } - // End flush(p, lines) Special-cases - trace(99, "parse") << "flushing segment" << end(); - p.segments.back().lines.swap(lines); + trace(3, "parse") << "flushing segment" << end(); + s->lines.insert(s->lines.end(), lines.begin(), lines.end()); + lines.clear(); } void parse_word(const string& data, word& out) { @@ -216,9 +232,9 @@ void parse(const string& text_bytes) { void test_detect_duplicate_segments() { Hide_errors = true; parse( - "== 0xee\n" + "== segment1 0xee\n" "ab\n" - "== 0xee\n" + "== segment2 0xee\n" "cd\n" ); CHECK_TRACE_CONTENTS( @@ -242,7 +258,7 @@ void transform(program& p) { //:: load void load(const program& p) { - if (p.segments.empty()) { + if (find(p, "code") == NULL) { raise << "no code to run\n" << end(); return; } @@ -267,10 +283,20 @@ void load(const program& p) { ++addr; } } - if (i == 0) End_of_program = addr; + if (seg.name == "code") { + End_of_program = addr; + EIP = seg.start; + // End Initialize EIP + } } - EIP = p.segments.at(0).start; - // End Initialize EIP +} + +const segment* find(const program& p, const string& segment_name) { + for (int i = 0; i < SIZE(p.segments); ++i) { + if (p.segments.at(i).name == segment_name) + return &p.segments.at(i); + } + return NULL; } uint8_t hex_byte(const string& s) { @@ -291,8 +317,8 @@ uint8_t hex_byte(const string& s) { void test_number_too_large() { Hide_errors = true; parse_and_load( - "== 0x1\n" - "05 cab\n" + "== code 0x1\n" + "01 cab\n" ); CHECK_TRACE_CONTENTS( "error: token 'cab' is not a hex byte\n" @@ -302,8 +328,8 @@ void test_number_too_large() { void test_invalid_hex() { Hide_errors = true; parse_and_load( - "== 0x1\n" - "05 cx\n" + "== code 0x1\n" + "01 cx\n" ); CHECK_TRACE_CONTENTS( "error: token 'cx' is not a hex byte\n" @@ -312,8 +338,8 @@ void test_invalid_hex() { void test_negative_number() { parse_and_load( - "== 0x1\n" - "05 -12\n" + "== code 0x1\n" + "01 -02\n" ); CHECK_TRACE_COUNT("error", 0); } @@ -321,8 +347,8 @@ void test_negative_number() { void test_negative_number_too_small() { Hide_errors = true; parse_and_load( - "== 0x1\n" - "05 -12345\n" + "== code 0x1\n" + "01 -12345\n" ); CHECK_TRACE_CONTENTS( "error: token '-12345' is not a hex byte\n" @@ -331,12 +357,41 @@ void test_negative_number_too_small() { void test_hex_prefix() { parse_and_load( - "== 0x1\n" - "0x05 -0x12\n" + "== code 0x1\n" + "0x01 -0x02\n" ); CHECK_TRACE_COUNT("error", 0); } +void test_repeated_segment_merges_data() { + parse_and_load( + "== code 0x1\n" + "11 22\n" + "== code\n" // again + "33 44\n" + ); + CHECK_TRACE_CONTENTS( + "parse: new segment 'code'\n" + "parse: appending to segment 'code'\n" + // first segment + "load: 0x00000001 -> 11\n" + "load: 0x00000002 -> 22\n" + // second segment + "load: 0x00000003 -> 33\n" + "load: 0x00000004 -> 44\n" + ); +} + +void test_error_on_missing_segment_header() { + Hide_errors = true; + parse_and_load( + "01 02\n" + ); + CHECK_TRACE_CONTENTS( + "error: input does not start with a '==' section header\n" + ); +} + //: helper for tests void parse_and_load(const string& text_bytes) { program p; @@ -362,9 +417,9 @@ case 0xb8: { // copy imm32 to EAX } :(code) -void test_copy_imm32_to_EAX() { +void test_copy_imm32_to_EAX_again() { run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " b8 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EAX ); diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index 9c314b02..ca76acfb 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -8,7 +8,7 @@ void test_add_r32_to_r32() { Reg[EAX].i = 0x10; Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 01 d8 \n" // add EBX to EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -47,7 +47,7 @@ void test_add_r32_to_r32_signed_overflow() { Reg[EAX].i = 0x7fffffff; // largest positive signed integer Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 01 d8 \n" // add EBX to EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -64,7 +64,7 @@ void test_add_r32_to_r32_unsigned_overflow() { Reg[EAX].u = 0xffffffff; // largest unsigned number Reg[EBX].u = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 01 d8 \n" // add EBX to EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -80,7 +80,7 @@ void test_add_r32_to_r32_unsigned_overflow() { void test_add_r32_to_r32_unsigned_and_signed_overflow() { Reg[EAX].u = Reg[EBX].u = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 01 d8 \n" // add EBX to EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -157,7 +157,7 @@ void test_subtract_r32_from_r32() { Reg[EAX].i = 10; Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 29 d8 \n" // subtract EBX from EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -196,7 +196,7 @@ void test_subtract_r32_from_r32_signed_overflow() { Reg[EAX].i = 0x80000000; // smallest negative signed integer Reg[EBX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 29 d8 \n" // subtract EBX from EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -213,7 +213,7 @@ void test_subtract_r32_from_r32_unsigned_overflow() { Reg[EAX].i = 0; Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 29 d8 \n" // subtract EBX from EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -230,7 +230,7 @@ void test_subtract_r32_from_r32_signed_and_unsigned_overflow() { Reg[EAX].i = 0; Reg[EBX].i = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 29 d8 \n" // subtract EBX from EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -253,7 +253,7 @@ void test_multiply_EAX_by_r32() { Reg[EAX].i = 4; Reg[ECX].i = 3; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 e1 \n" // multiply EAX by ECX // ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX) @@ -302,7 +302,7 @@ void test_multiply_r32_into_r32() { Reg[EAX].i = 4; Reg[EBX].i = 2; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 0f af d8 \n" // subtract EBX into EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -338,7 +338,7 @@ case 0xaf: { // multiply r32 by r/m32 void test_negate_r32() { Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 db \n" // negate EBX // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX) @@ -378,7 +378,7 @@ case 3: { // negate r/m32 void test_negate_can_overflow() { Reg[EBX].i = 0x80000000; // INT_MIN run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 db \n" // negate EBX // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX) @@ -398,7 +398,7 @@ void test_divide_EAX_by_rm32() { Reg[EDX].u = 0; Reg[ECX].i = 3; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 f9 \n" // multiply EAX by ECX // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX) @@ -432,7 +432,7 @@ void test_divide_EAX_by_negative_rm32() { Reg[EDX].u = 0; Reg[ECX].i = -3; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 f9 \n" // multiply EAX by ECX // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX) @@ -451,7 +451,7 @@ void test_divide_negative_EAX_by_rm32() { Reg[EDX].i = -1; // sign extend Reg[ECX].i = 3; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 f9 \n" // multiply EAX by ECX // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX) @@ -470,7 +470,7 @@ void test_divide_negative_EDX_EAX_by_rm32() { Reg[EDX].i = -7; Reg[ECX].i = 0x40000000; // 2^30 (largest positive power of 2) run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 f9 \n" // multiply EAX by ECX // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX) @@ -494,7 +494,7 @@ void test_shift_left_r32_with_cl() { Reg[EBX].i = 13; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 e3 \n" // shift EBX left by CL bits // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX) @@ -547,7 +547,7 @@ void test_shift_right_arithmetic_r32_with_cl() { Reg[EBX].i = 26; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 fb \n" // shift EBX right by CL bits, while preserving sign // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -579,7 +579,7 @@ void test_shift_right_arithmetic_odd_r32_with_cl() { Reg[EBX].i = 27; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 fb \n" // shift EBX right by CL bits, while preserving sign // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -597,7 +597,7 @@ void test_shift_right_arithmetic_negative_r32_with_cl() { Reg[EBX].i = 0xfffffffd; // -3 Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 fb \n" // shift EBX right by CL bits, while preserving sign // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -618,7 +618,7 @@ void test_shift_right_logical_r32_with_cl() { Reg[EBX].i = 26; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 eb \n" // shift EBX right by CL bits, while padding zeroes // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX) @@ -657,7 +657,7 @@ void test_shift_right_logical_odd_r32_with_cl() { Reg[EBX].i = 27; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 eb \n" // shift EBX right by CL bits, while padding zeroes // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX) @@ -675,7 +675,7 @@ void test_shift_right_logical_negative_r32_with_cl() { Reg[EBX].i = 0xfffffffd; Reg[ECX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " d3 eb \n" // shift EBX right by CL bits, while padding zeroes // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX) @@ -698,7 +698,7 @@ void test_and_r32_with_r32() { Reg[EAX].i = 0x0a0b0c0d; Reg[EBX].i = 0x000000ff; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 21 d8 \n" // and EBX with destination EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -738,7 +738,7 @@ void test_or_r32_with_r32() { Reg[EAX].i = 0x0a0b0c0d; Reg[EBX].i = 0xa0b0c0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 09 d8 \n" // or EBX with destination EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -778,7 +778,7 @@ void test_xor_r32_with_r32() { Reg[EAX].i = 0x0a0b0c0d; Reg[EBX].i = 0xaabbc0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 31 d8 \n" // xor EBX with destination EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -814,7 +814,7 @@ case 0x31: { // xor r32 with r/m32 void test_not_r32() { Reg[EBX].i = 0x0f0f00ff; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " f7 d3 \n" // not EBX // ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX) @@ -846,7 +846,7 @@ void test_compare_r32_with_r32_greater() { Reg[EAX].i = 0x0a0b0c0d; Reg[EBX].i = 0x0a0b0c07; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX with EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -883,7 +883,7 @@ void test_compare_r32_with_r32_lesser_unsigned_and_signed() { Reg[EAX].i = 0x0a0b0c07; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX with EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -899,7 +899,7 @@ void test_compare_r32_with_r32_lesser_unsigned_and_signed_due_to_overflow() { Reg[EAX].i = 0x7fffffff; // largest positive signed integer Reg[EBX].i = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX with EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -915,7 +915,7 @@ void test_compare_r32_with_r32_lesser_signed() { Reg[EAX].i = 0xffffffff; // -1 Reg[EBX].i = 0x00000001; // 1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX with EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -931,7 +931,7 @@ void test_compare_r32_with_r32_lesser_unsigned() { Reg[EAX].i = 0x00000001; // 1 Reg[EBX].i = 0xffffffff; // -1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX with EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -947,7 +947,7 @@ void test_compare_r32_with_r32_equal() { Reg[EAX].i = 0x0a0b0c0d; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 39 d8 \n" // compare EAX and EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -968,7 +968,7 @@ put_new(Name, "89", "copy r32 to rm32 (mov)"); void test_copy_r32_to_r32() { Reg[EBX].i = 0xaf; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 89 d8 \n" // copy EBX to EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -1001,7 +1001,7 @@ void test_xchg_r32_with_r32() { Reg[EBX].i = 0xaf; Reg[EAX].i = 0x2e; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 87 d8 \n" // exchange EBX with EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) @@ -1044,7 +1044,7 @@ put_new(Name, "47", "increment EDI (inc)"); void test_increment_r32() { Reg[ECX].u = 0x1f; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 41 \n" // increment ECX ); @@ -1077,7 +1077,7 @@ put_new(Name, "ff", "increment/decrement/jump/push/call rm32 based on subop (inc void test_increment_rm32() { Reg[EAX].u = 0x20; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " ff c0 \n" // increment EAX // ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX) @@ -1126,7 +1126,7 @@ put_new(Name, "4f", "decrement EDI (dec)"); void test_decrement_r32() { Reg[ECX].u = 0x1f; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 49 \n" // decrement ECX ); @@ -1156,7 +1156,7 @@ case 0x4f: { // decrement r32 void test_decrement_rm32() { Reg[EAX].u = 0x20; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " ff c8 \n" // decrement EAX // ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX) @@ -1195,7 +1195,7 @@ void test_push_r32() { Reg[ESP].u = 0xbd000008; Reg[EBX].i = 0x0000000a; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 53 \n" // push EBX to stack ); @@ -1240,10 +1240,10 @@ void test_pop_r32() { Reg[ESP].u = 0xbd000008; write_mem_i32(0xbd000008, 0x0000000a); // ..before this write run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " 5b \n" // pop stack to EBX - "== 0x2000\n" // data segment + "== data 0x2000\n" // data segment "0a 00 00 00\n" // 0x0000000a ); CHECK_TRACE_CONTENTS( diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index ce523b3f..dd00c614 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -5,11 +5,11 @@ void test_add_r32_to_mem_at_r32() { Reg[EBX].i = 0x10; Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 18 \n" // add EBX to *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -40,11 +40,11 @@ void test_add_mem_at_r32_to_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x10; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 03 18 \n" // add *EAX to EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -81,11 +81,11 @@ void test_add_mem_at_r32_to_r32_signed_overflow() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 03 18 \n" // add *EAX to EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 1 ); CHECK_TRACE_CONTENTS( @@ -101,11 +101,11 @@ void test_add_mem_at_r32_to_r32_unsigned_overflow() { Reg[EAX].u = 0x2000; Reg[EBX].u = 0xffffffff; // largest unsigned number run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 03 18 \n" // add *EAX to EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" ); CHECK_TRACE_CONTENTS( @@ -121,11 +121,11 @@ void test_add_mem_at_r32_to_r32_unsigned_and_signed_overflow() { Reg[EAX].u = 0x2000; Reg[EBX].u = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 03 18 \n" // add *EAX to EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 80\n" // smallest negative signed integer ); CHECK_TRACE_CONTENTS( @@ -144,11 +144,11 @@ void test_subtract_r32_from_mem_at_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 29 18 \n" // subtract EBX from *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0a 00 00 00\n" // 0x0000000a ); CHECK_TRACE_CONTENTS( @@ -168,11 +168,11 @@ void test_subtract_mem_at_r32_from_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 10; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2b 18 \n" // subtract *EAX from EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -209,11 +209,11 @@ void test_subtract_mem_at_r32_from_r32_signed_overflow() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2b 18 \n" // subtract *EAX from EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ff ff ff 7f\n" // largest positive signed integer ); CHECK_TRACE_CONTENTS( @@ -229,11 +229,11 @@ void test_subtract_mem_at_r32_from_r32_unsigned_overflow() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2b 18 \n" // subtract *EAX from EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 1 ); CHECK_TRACE_CONTENTS( @@ -249,11 +249,11 @@ void test_subtract_mem_at_r32_from_r32_signed_and_unsigned_overflow() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2b 18 \n" // subtract *EAX from EBX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 80\n" // smallest negative signed integer ); CHECK_TRACE_CONTENTS( @@ -271,11 +271,11 @@ void test_and_r32_with_mem_at_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xff; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 21 18 \n" // and EBX with *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -295,11 +295,11 @@ void test_and_mem_at_r32_with_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 23 18 \n" // and *EAX with EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ff 00 00 00\n" // 0x000000ff ); CHECK_TRACE_CONTENTS( @@ -334,11 +334,11 @@ void test_or_r32_with_mem_at_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xa0b0c0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 09 18 #\n" // EBX with *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -358,11 +358,11 @@ void test_or_mem_at_r32_with_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xa0b0c0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0b 18 \n" // or *EAX with EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -397,10 +397,10 @@ void test_xor_r32_with_mem_at_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xa0b0c0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 31 18 \n" // xor EBX with *EAX - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c bb aa\n" // 0xaabb0c0d ); CHECK_TRACE_CONTENTS( @@ -420,11 +420,11 @@ void test_xor_mem_at_r32_with_r32() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xa0b0c0d0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 33 18 \n" // xor *EAX with EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -458,11 +458,11 @@ case 0x33: { // xor r/m32 with r32 void test_not_of_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " f7 13 \n" // not *EBX // ModR/M in binary: 00 (indirect mode) 010 (subop not) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ff 00 0f 0f\n" // 0x0f0f00ff ); CHECK_TRACE_CONTENTS( @@ -480,11 +480,11 @@ void test_compare_mem_at_r32_with_r32_greater() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c07; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 39 18 \n" // compare *EAX with EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -499,11 +499,11 @@ void test_compare_mem_at_r32_with_r32_lesser() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 39 18 \n" // compare *EAX with EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "07 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -518,11 +518,11 @@ void test_compare_mem_at_r32_with_r32_equal() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 39 18 \n" // compare *EAX and EBX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -542,11 +542,11 @@ void test_compare_r32_with_mem_at_r32_greater() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "07 0c 0b 0a\n" // 0x0a0b0c07 ); CHECK_TRACE_CONTENTS( @@ -580,11 +580,11 @@ void test_compare_r32_with_mem_at_r32_lesser_unsigned_and_signed() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c07; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -599,11 +599,11 @@ void test_compare_r32_with_mem_at_r32_lesser_unsigned_and_signed_due_to_overflow Reg[EAX].i = 0x2000; Reg[EBX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 80\n" // smallest negative signed integer ); CHECK_TRACE_CONTENTS( @@ -618,11 +618,11 @@ void test_compare_r32_with_mem_at_r32_lesser_signed() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0xffffffff; // -1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 1 ); CHECK_TRACE_CONTENTS( @@ -637,11 +637,11 @@ void test_compare_r32_with_mem_at_r32_lesser_unsigned() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x00000001; // 1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ff ff ff ff\n" // -1 ); CHECK_TRACE_CONTENTS( @@ -656,11 +656,11 @@ void test_compare_r32_with_mem_at_r32_equal() { Reg[EAX].i = 0x2000; Reg[EBX].i = 0x0a0b0c0d; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3b 18 \n" // compare EBX with *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0d 0c 0b 0a\n" // 0x0a0b0c0d ); CHECK_TRACE_CONTENTS( @@ -676,7 +676,7 @@ void test_copy_r32_to_mem_at_r32() { Reg[EBX].i = 0xaf; Reg[EAX].i = 0x60; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 89 18 \n" // copy EBX to *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) @@ -697,10 +697,10 @@ put_new(Name, "8b", "copy rm32 to r32 (mov)"); void test_copy_mem_at_r32_to_r32() { Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 8b 18 \n" // copy *EAX to EBX - "== 0x2000\n" // data segment + "== data 0x2000\n" "af 00 00 00\n" // 0x000000af ); CHECK_TRACE_CONTENTS( @@ -727,13 +727,13 @@ case 0x8b: { // copy r32 to r/m32 void test_jump_mem_at_r32() { Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // 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) " b8 00 00 00 01\n" " b8 00 00 00 02\n" - "== 0x2000\n" // data segment + "== data 0x2000\n" "08 00 00 00\n" // 0x00000008 ); CHECK_TRACE_CONTENTS( @@ -763,10 +763,10 @@ void test_push_mem_at_r32() { Mem.push_back(vma(0xbd000000)); // manually allocate memory Reg[ESP].u = 0xbd000014; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " ff 30 \n" // push *EAX to stack - "== 0x2000\n" // data segment + "== data 0x2000\n" "af 00 00 00\n" // 0x000000af ); CHECK_TRACE_CONTENTS( @@ -797,7 +797,7 @@ void test_pop_mem_at_r32() { Reg[ESP].u = 0xbd000000; write_mem_i32(0xbd000000, 0x00000030); run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 8f 00 \n" // pop stack into *EAX // ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) @@ -831,11 +831,11 @@ case 0x8f: { // pop stack into r/m32 void test_add_r32_to_mem_at_displacement() { Reg[EBX].i = 0x10; // source run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 1d 00 20 00 00 \n" // add EBX to *0x2000 // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -858,11 +858,11 @@ void test_add_r32_to_mem_at_r32_plus_disp8() { Reg[EBX].i = 0x10; // source Reg[EAX].i = 0x1ffe; // dest run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 58 02 \n" // add EBX to *(EAX+2) // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -893,11 +893,11 @@ void test_add_r32_to_mem_at_r32_plus_negative_disp8() { Reg[EBX].i = 0x10; // source Reg[EAX].i = 0x2001; // dest run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 58 ff \n" // add EBX to *(EAX-1) // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -915,11 +915,11 @@ void test_add_r32_to_mem_at_r32_plus_disp32() { Reg[EBX].i = 0x10; // source Reg[EAX].i = 0x1ffe; // dest run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 98 02 00 00 00 \n" // add EBX to *(EAX+2) // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -950,11 +950,11 @@ void test_add_r32_to_mem_at_r32_plus_negative_disp32() { Reg[EBX].i = 0x10; // source Reg[EAX].i = 0x2001; // dest run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 98 ff ff ff ff \n" // add EBX to *(EAX-1) // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -974,7 +974,7 @@ put_new(Name, "8d", "copy address in rm32 into r32 (lea)"); void test_copy_address() { Reg[EAX].u = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 8d 18 \n" // copy address in EAX into EBX // ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 478e3592..782a16b9 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -27,7 +27,7 @@ case 0x05: { // add imm32 to EAX void test_add_imm32_to_EAX_signed_overflow() { Reg[EAX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 01 00 00 00 \n" // add 1 to EAX ); @@ -42,7 +42,7 @@ void test_add_imm32_to_EAX_unsigned_overflow() { Reg[EAX].u = 0xffffffff; // largest unsigned number Reg[EBX].u = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 01 00 00 00 \n" // add 1 to EAX ); @@ -56,7 +56,7 @@ void test_add_imm32_to_EAX_unsigned_overflow() { void test_add_imm32_to_EAX_unsigned_and_signed_overflow() { Reg[EAX].u = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 00 00 00 80 \n" // add 0x80000000 to EAX ); @@ -76,7 +76,7 @@ put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/ void test_add_imm32_to_r32() { Reg[EBX].i = 1; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 0a 0b 0c 0d\n" // add 0x0d0c0b0a to EBX // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) @@ -129,7 +129,7 @@ case 0x81: { // combine r/m32 with imm32 void test_add_imm32_to_r32_signed_overflow() { Reg[EBX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 01 00 00 00\n" // add 1 to EBX // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) @@ -147,7 +147,7 @@ void test_add_imm32_to_r32_signed_overflow() { void test_add_imm32_to_r32_unsigned_overflow() { Reg[EBX].u = 0xffffffff; // largest unsigned number run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 01 00 00 00\n" // add 1 to EBX // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) @@ -165,7 +165,7 @@ void test_add_imm32_to_r32_unsigned_overflow() { void test_add_imm32_to_r32_unsigned_and_signed_overflow() { Reg[EBX].u = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 00 00 00 80\n" // add 0x80000000 to EBX // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) @@ -186,11 +186,11 @@ void test_add_imm32_to_r32_unsigned_and_signed_overflow() { void test_add_imm32_to_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 03 0a 0b 0c 0d \n" // add 0x0d0c0b0a to *EBX // ModR/M in binary: 00 (indirect mode) 000 (subop add) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -211,7 +211,7 @@ put_new(Name, "2d", "subtract imm32 from EAX (sub)"); void test_subtract_imm32_from_EAX() { Reg[EAX].i = 0x0d0c0baa; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 0a 0b 0c 0d \n" // subtract 0x0d0c0b0a from EAX ); @@ -245,7 +245,7 @@ case 0x2d: { // subtract imm32 from EAX void test_subtract_imm32_from_EAX_signed_overflow() { Reg[EAX].i = 0x80000000; // smallest negative signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d ff ff ff 7f \n" // subtract largest positive signed integer from EAX ); @@ -259,7 +259,7 @@ void test_subtract_imm32_from_EAX_signed_overflow() { void test_subtract_imm32_from_EAX_unsigned_overflow() { Reg[EAX].i = 0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 01 00 00 00 \n" // subtract 1 from EAX ); @@ -273,7 +273,7 @@ void test_subtract_imm32_from_EAX_unsigned_overflow() { void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() { Reg[EAX].i = 0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 00 00 00 80 \n" // subtract smallest negative signed integer from EAX ); @@ -289,11 +289,11 @@ void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() { void test_subtract_imm32_from_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0a 00 00 00\n" // 0x0000000a ); CHECK_TRACE_CONTENTS( @@ -329,11 +329,11 @@ case 5: { void test_subtract_imm32_from_mem_at_r32_signed_overflow() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b ff ff ff 7f \n" // subtract largest positive signed integer from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 80\n" // smallest negative signed integer ); CHECK_TRACE_CONTENTS( @@ -350,11 +350,11 @@ void test_subtract_imm32_from_mem_at_r32_signed_overflow() { void test_subtract_imm32_from_mem_at_r32_unsigned_overflow() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 00\n" // 0 ); CHECK_TRACE_CONTENTS( @@ -371,11 +371,11 @@ void test_subtract_imm32_from_mem_at_r32_unsigned_overflow() { void test_subtract_imm32_from_mem_at_r32_signed_and_unsigned_overflow() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 00 00 00 80 \n" // subtract smallest negative signed integer from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "00 00 00 00\n" // 0 ); CHECK_TRACE_CONTENTS( @@ -394,7 +394,7 @@ void test_subtract_imm32_from_mem_at_r32_signed_and_unsigned_overflow() { void test_subtract_imm32_from_r32() { Reg[EBX].i = 10; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 eb 01 00 00 00 \n" // subtract 1 from EBX // ModR/M in binary: 11 (direct mode) 101 (subop subtract) 011 (dest EBX) @@ -417,7 +417,7 @@ put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr void test_shift_left_r32_with_imm8() { Reg[EBX].i = 13; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 e3 01 \n" // shift EBX left by 1 bit // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX) @@ -468,7 +468,7 @@ case 0xc1: { void test_shift_right_arithmetic_r32_with_imm8() { Reg[EBX].i = 26; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 fb 01 \n" // shift EBX right by 1 bit // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -502,7 +502,7 @@ case 7: { // shift right r/m32 by CL, preserving sign void test_shift_right_arithmetic_odd_r32_with_imm8() { Reg[EBX].i = 27; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 fb 01 \n" // shift EBX right by 1 bit // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -520,7 +520,7 @@ void test_shift_right_arithmetic_odd_r32_with_imm8() { void test_shift_right_arithmetic_negative_r32_with_imm8() { Reg[EBX].i = 0xfffffffd; // -3 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 fb 01 \n" // shift EBX right by 1 bit, while preserving sign // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) @@ -540,7 +540,7 @@ void test_shift_right_arithmetic_negative_r32_with_imm8() { void test_shift_right_logical_r32_with_imm8() { Reg[EBX].i = 26; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 eb 01 \n" // shift EBX right by 1 bit, while padding zeroes // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX) @@ -578,7 +578,7 @@ case 5: { // shift right r/m32 by CL, preserving sign void test_shift_right_logical_odd_r32_with_imm8() { Reg[EBX].i = 27; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 eb 01 \n" // shift EBX right by 1 bit, while padding zeroes ); @@ -595,7 +595,7 @@ void test_shift_right_logical_odd_r32_with_imm8() { void test_shift_right_logical_negative_r32_with_imm8() { Reg[EBX].i = 0xfffffffd; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 eb 01 \n" // shift EBX right by 1 bit, while padding zeroes // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX) @@ -617,7 +617,7 @@ put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)"); void test_and_EAX_with_imm32() { Reg[EAX].i = 0xff; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 25 0a 0b 0c 0d \n" // and 0x0d0c0b0a with EAX ); @@ -649,11 +649,11 @@ case 0x25: { // and imm32 with EAX void test_and_imm32_with_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 23 0a 0b 0c 0d \n" // and 0x0d0c0b0a with *EBX // ModR/M in binary: 00 (indirect mode) 100 (subop and) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ff 00 00 00\n" // 0x000000ff ); CHECK_TRACE_CONTENTS( @@ -686,7 +686,7 @@ case 4: { void test_and_imm32_with_r32() { Reg[EBX].i = 0xff; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 e3 0a 0b 0c 0d \n" // and 0x0d0c0b0a with EBX // ModR/M in binary: 11 (direct mode) 100 (subop and) 011 (dest EBX) @@ -709,7 +709,7 @@ put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)"); void test_or_EAX_with_imm32() { Reg[EAX].i = 0xd0c0b0a0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0d 0a 0b 0c 0d \n" // or 0x0d0c0b0a with EAX ); @@ -741,11 +741,11 @@ case 0x0d: { // or imm32 with EAX void test_or_imm32_with_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 0b 0a 0b 0c 0d \n" // or 0x0d0c0b0a with *EBX // ModR/M in binary: 00 (indirect mode) 001 (subop or) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "a0 b0 c0 d0\n" // 0xd0c0b0a0 ); CHECK_TRACE_CONTENTS( @@ -776,7 +776,7 @@ case 1: { void test_or_imm32_with_r32() { Reg[EBX].i = 0xd0c0b0a0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 cb 0a 0b 0c 0d \n" // or 0x0d0c0b0a with EBX // ModR/M in binary: 11 (direct mode) 001 (subop or) 011 (dest EBX) @@ -799,7 +799,7 @@ put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)"); void test_xor_EAX_with_imm32() { Reg[EAX].i = 0xddccb0a0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 35 0a 0b 0c 0d \n" // xor 0x0d0c0b0a with EAX ); @@ -831,11 +831,11 @@ case 0x35: { // xor imm32 with EAX void test_xor_imm32_with_mem_at_r32() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 33 0a 0b 0c 0d \n" // xor 0x0d0c0b0a with *EBX // ModR/M in binary: 00 (indirect mode) 110 (subop xor) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "a0 b0 c0 d0\n" // 0xd0c0b0a0 ); CHECK_TRACE_CONTENTS( @@ -866,7 +866,7 @@ case 6: { void test_xor_imm32_with_r32() { Reg[EBX].i = 0xd0c0b0a0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 f3 0a 0b 0c 0d \n" // xor 0x0d0c0b0a with EBX // ModR/M in binary: 11 (direct mode) 110 (subop xor) 011 (dest EBX) @@ -889,7 +889,7 @@ put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)"); void test_compare_EAX_with_imm32_greater() { Reg[EAX].i = 0x0d0c0b0a; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d 07 0b 0c 0d \n" // compare EAX with 0x0d0c0b07 ); @@ -922,7 +922,7 @@ case 0x3d: { // compare EAX with imm32 void test_compare_EAX_with_imm32_lesser_unsigned_and_signed() { Reg[EAX].i = 0x0a0b0c07; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d 0d 0c 0b 0a \n" // compare EAX with imm32 ); @@ -935,7 +935,7 @@ void test_compare_EAX_with_imm32_lesser_unsigned_and_signed() { void test_compare_EAX_with_imm32_lesser_unsigned_and_signed_due_to_overflow() { Reg[EAX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d 00 00 00 80\n" // compare EAX with smallest negative signed integer ); @@ -948,7 +948,7 @@ void test_compare_EAX_with_imm32_lesser_unsigned_and_signed_due_to_overflow() { void test_compare_EAX_with_imm32_lesser_signed() { Reg[EAX].i = 0xffffffff; // -1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d 01 00 00 00\n" // compare EAX with 1 ); @@ -961,7 +961,7 @@ void test_compare_EAX_with_imm32_lesser_signed() { void test_compare_EAX_with_imm32_lesser_unsigned() { Reg[EAX].i = 0x00000001; // 1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d ff ff ff ff\n" // compare EAX with -1 ); @@ -974,7 +974,7 @@ void test_compare_EAX_with_imm32_lesser_unsigned() { void test_compare_EAX_with_imm32_equal() { Reg[EAX].i = 0x0d0c0b0a; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 3d 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EAX ); @@ -989,7 +989,7 @@ void test_compare_EAX_with_imm32_equal() { void test_compare_imm32_with_r32_greater() { Reg[EBX].i = 0x0d0c0b0a; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 fb 07 0b 0c 0d \n" // compare 0x0d0c0b07 with EBX // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX) @@ -1023,7 +1023,7 @@ case 7: { void test_compare_rm32_with_imm32_lesser_unsigned_and_signed() { Reg[EAX].i = 0x0a0b0c07; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 f8 0d 0c 0b 0a \n" // compare EAX with imm32 // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX) @@ -1040,7 +1040,7 @@ void test_compare_rm32_with_imm32_lesser_unsigned_and_signed() { void test_compare_rm32_with_imm32_lesser_unsigned_and_signed_due_to_overflow() { Reg[EAX].i = 0x7fffffff; // largest positive signed integer run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 f8 00 00 00 80\n" // compare EAX with smallest negative signed integer // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX) @@ -1057,7 +1057,7 @@ void test_compare_rm32_with_imm32_lesser_unsigned_and_signed_due_to_overflow() { void test_compare_rm32_with_imm32_lesser_signed() { Reg[EAX].i = 0xffffffff; // -1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 f8 01 00 00 00\n" // compare EAX with 1 // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX) @@ -1074,7 +1074,7 @@ void test_compare_rm32_with_imm32_lesser_signed() { void test_compare_rm32_with_imm32_lesser_unsigned() { Reg[EAX].i = 0x00000001; // 1 run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 f8 ff ff ff ff\n" // compare EAX with -1 // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX) @@ -1092,7 +1092,7 @@ void test_compare_rm32_with_imm32_lesser_unsigned() { void test_compare_imm32_with_r32_equal() { Reg[EBX].i = 0x0d0c0b0a; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 fb 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EBX // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX) @@ -1109,11 +1109,11 @@ void test_compare_imm32_with_r32_equal() { void test_compare_imm32_with_mem_at_r32_greater() { Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 3b 07 0b 0c 0d \n" // compare 0x0d0c0b07 with *EBX // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0a 0b 0c 0d\n" // 0x0d0c0b0a ); CHECK_TRACE_CONTENTS( @@ -1128,11 +1128,11 @@ void test_compare_imm32_with_mem_at_r32_greater() { void test_compare_imm32_with_mem_at_r32_lesser() { Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 38 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with *EAX // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "07 0b 0c 0d\n" // 0x0d0c0b07 ); CHECK_TRACE_CONTENTS( @@ -1148,11 +1148,11 @@ void test_compare_imm32_with_mem_at_r32_equal() { Reg[EBX].i = 0x0d0c0b0a; Reg[EBX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 3b 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with *EBX // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "0a 0b 0c 0d\n" // 0x0d0c0b0a ); CHECK_TRACE_CONTENTS( @@ -1178,7 +1178,7 @@ put_new(Name, "bf", "copy imm32 to EDI (mov)"); :(code) void test_copy_imm32_to_r32() { run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " bb 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EBX ); @@ -1211,7 +1211,7 @@ put_new(Name, "c7", "copy imm32 to rm32 (mov)"); void test_copy_imm32_to_mem_at_r32() { Reg[EBX].i = 0x60; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c7 03 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to *EBX // ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) @@ -1249,7 +1249,7 @@ void test_push_imm32() { Mem.push_back(vma(0xbd000000)); // manually allocate memory Reg[ESP].u = 0xbd000014; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 68 af 00 00 00 \n" // push *EAX to stack ); diff --git a/subx/016index_addressing.cc b/subx/016index_addressing.cc index ef72f710..6e1f63e6 100644 --- a/subx/016index_addressing.cc +++ b/subx/016index_addressing.cc @@ -5,12 +5,12 @@ void test_add_r32_to_mem_at_r32_with_sib() { Reg[EBX].i = 0x10; Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 1c 20 \n" // add EBX to *EAX // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) // SIB in binary: 00 (scale 1) 100 (no index) 000 (base EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -58,12 +58,12 @@ void test_add_r32_to_mem_at_base_r32_index_r32() { Reg[EAX].i = 0x1ffe; // dest base Reg[ECX].i = 0x2; // dest index run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 1c 08 \n" // add EBX to *(EAX+ECX) // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -78,12 +78,12 @@ void test_add_r32_to_mem_at_base_r32_index_r32() { void test_add_r32_to_mem_at_displacement_using_sib() { Reg[EBX].i = 0x10; // source run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 1c 25 00 20 00 00 \n" // add EBX to *0x2000 // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) // SIB in binary: 00 (scale 1) 100 (no index) 101 (not EBP but disp32) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -102,12 +102,12 @@ void test_add_r32_to_mem_at_base_r32_index_r32_plus_disp8() { Reg[EAX].i = 0x1ff9; // dest base Reg[ECX].i = 0x5; // dest index run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 5c 08 02 \n" // add EBX to *(EAX+ECX+2) // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 100 (dest in SIB) // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( @@ -132,12 +132,12 @@ void test_add_r32_to_mem_at_base_r32_index_r32_plus_disp32() { Reg[EAX].i = 0x1ff9; // dest base Reg[ECX].i = 0x5; // dest index run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 01 9c 08 02 00 00 00 \n" // add EBX to *(EAX+ECX+2) // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 100 (dest in SIB) // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "01 00 00 00\n" // 0x00000001 ); CHECK_TRACE_CONTENTS( diff --git a/subx/017jump_disp8.cc b/subx/017jump_disp8.cc index 35cc1331..086765c0 100644 --- a/subx/017jump_disp8.cc +++ b/subx/017jump_disp8.cc @@ -8,7 +8,7 @@ put_new(Name, "eb", "jump disp8 bytes away (jmp)"); :(code) void test_jump_rel8() { run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " eb 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -39,7 +39,7 @@ put_new(Name, "74", "jump disp8 bytes away if equal, if ZF is set (jcc/jz/je)"); void test_je_rel8_success() { ZF = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 74 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -67,7 +67,7 @@ case 0x74: { // jump rel8 if ZF void test_je_rel8_fail() { ZF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 74 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -90,7 +90,7 @@ put_new(Name, "75", "jump disp8 bytes away if not equal, if ZF is not set (jcc/j void test_jne_rel8_success() { ZF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 75 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -118,7 +118,7 @@ case 0x75: { // jump rel8 unless ZF void test_jne_rel8_fail() { ZF = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 75 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -144,7 +144,7 @@ void test_jg_rel8_success() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7f 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -182,7 +182,7 @@ void test_jg_rel8_fail() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7f 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -207,7 +207,7 @@ void test_jge_rel8_success() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7d 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -244,7 +244,7 @@ void test_jge_rel8_fail() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7d 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -270,7 +270,7 @@ void test_jl_rel8_success() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7c 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -308,7 +308,7 @@ void test_jl_rel8_fail() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7c 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -334,7 +334,7 @@ void test_jle_rel8_equal() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7e 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -354,7 +354,7 @@ void test_jle_rel8_lesser() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7e 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -392,7 +392,7 @@ void test_jle_rel8_greater() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 7e 05 \n" // skip 1 instruction " 05 00 00 00 01 \n" diff --git a/subx/018jump_disp32.cc b/subx/018jump_disp32.cc index 836146ee..524ef5f1 100644 --- a/subx/018jump_disp32.cc +++ b/subx/018jump_disp32.cc @@ -8,7 +8,7 @@ put_new(Name, "e9", "jump disp32 bytes away (jmp)"); :(code) void test_jump_disp32() { run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " e9 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -39,7 +39,7 @@ put_new(Name_0f, "84", "jump disp32 bytes away if equal, if ZF is set (jcc/jz/je void test_je_disp32_success() { ZF = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 84 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -67,7 +67,7 @@ case 0x84: { // jump disp32 if ZF void test_je_disp32_fail() { ZF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 84 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -90,7 +90,7 @@ put_new(Name_0f, "85", "jump disp32 bytes away if not equal, if ZF is not set (j void test_jne_disp32_success() { ZF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 85 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -118,7 +118,7 @@ case 0x85: { // jump disp32 unless ZF void test_jne_disp32_fail() { ZF = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 85 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -143,7 +143,7 @@ void test_jg_disp32_success() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8f 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -173,7 +173,7 @@ void test_jg_disp32_fail() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8f 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -197,7 +197,7 @@ void test_jge_disp32_success() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8d 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -226,7 +226,7 @@ void test_jge_disp32_fail() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8d 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -251,7 +251,7 @@ void test_jl_disp32_success() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8c 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -281,7 +281,7 @@ void test_jl_disp32_fail() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8c 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -306,7 +306,7 @@ void test_jle_disp32_equal() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8e 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -326,7 +326,7 @@ void test_jle_disp32_lesser() { SF = true; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8e 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" @@ -356,7 +356,7 @@ void test_jle_disp32_greater() { SF = false; OF = false; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 0f 8e 05 00 00 00 \n" // skip 1 instruction " 05 00 00 00 01 \n" diff --git a/subx/019functions.cc b/subx/019functions.cc index 00da8397..81e99e6e 100644 --- a/subx/019functions.cc +++ b/subx/019functions.cc @@ -8,7 +8,7 @@ void test_call_disp32() { Mem.push_back(vma(0xbd000000)); // manually allocate memory Reg[ESP].u = 0xbd000064; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " e8 a0 00 00 00 \n" // call function offset at 0x000000a0 // next EIP is 6 @@ -41,7 +41,7 @@ void test_call_r32() { Reg[ESP].u = 0xbd000064; Reg[EBX].u = 0x000000a0; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " ff d3 \n" // call function offset at EBX // next EIP is 3 @@ -72,11 +72,11 @@ void test_call_mem_at_r32() { Reg[ESP].u = 0xbd000064; Reg[EBX].u = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " ff 13 \n" // call function offset at *EBX // next EIP is 3 - "== 0x2000\n" // data segment + "== data 0x2000\n" "a0 00 00 00\n" // 0x000000a0 ); CHECK_TRACE_CONTENTS( @@ -99,10 +99,10 @@ void test_ret() { Reg[ESP].u = 0xbd000064; write_mem_u32(Reg[ESP].u, 0x10); run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c3 \n" // return - "== 0x2000\n" // data segment + "== data 0x2000\n" "10 00 00 00\n" // 0x00000010 ); CHECK_TRACE_CONTENTS( diff --git a/subx/021byte_addressing.cc b/subx/021byte_addressing.cc index 106cd426..6510e2a6 100644 --- a/subx/021byte_addressing.cc +++ b/subx/021byte_addressing.cc @@ -45,11 +45,11 @@ void test_copy_r8_to_mem_at_r32() { Reg[EBX].i = 0x224488ab; Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 88 18 \n" // copy BL to the byte at *EAX // ModR/M in binary: 00 (indirect mode) 011 (src BL) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "f0 cc bb aa\n" ); CHECK_TRACE_CONTENTS( @@ -83,11 +83,11 @@ void test_copy_mem_at_r32_to_r8() { Reg[EBX].i = 0xaabbcc0f; // one nibble each of lowest byte set to all 0s and all 1s, to maximize value of this test Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 8a 18 \n" // copy just the byte at *EAX to BL // ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "ab ff ff ff\n" // 0xab with more data in following bytes ); CHECK_TRACE_CONTENTS( @@ -119,7 +119,7 @@ void test_cannot_copy_byte_to_ESP_EBP_ESI_EDI() { Reg[ESI].u = 0xaabbccdd; Reg[EBX].u = 0x11223344; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " 8a f3 \n" // copy just the byte at *EBX to 8-bit register '6' // ModR/M in binary: 11 (direct mode) 110 (dest 8-bit 'register 6') 011 (src EBX) @@ -142,11 +142,11 @@ put_new(Name, "c6", "copy imm8 to r8/m8-at-r32 (mov)"); void test_copy_imm8_to_mem_at_r32() { Reg[EAX].i = 0x2000; run( - "== 0x1\n" // code segment + "== code 0x1\n" // op ModR/M SIB displacement immediate " c6 00 dd \n" // copy to the byte at *EAX // ModR/M in binary: 00 (indirect mode) 000 (unused) 000 (dest EAX) - "== 0x2000\n" // data segment + "== data 0x2000\n" "f0 cc bb aa\n" ); CHECK_TRACE_CONTENTS( diff --git a/subx/022div.cc b/subx/022div.cc index 0498d7ee..15ed89d8 100644 --- a/subx/022div.cc +++ b/subx/022div.cc @@ -7,7 +7,7 @@ put_new(Name, "99", "sign-extend EAX into EDX (cdq)"); void test_cdq() { Reg[EAX].i = 10; run( - "== 0x1\n" // code segment + "== code 0x1\n" "99\n" ); CHECK_TRACE_CONTENTS( @@ -28,7 +28,7 @@ case 0x99: { // sign-extend EAX into EDX void test_cdq_negative() { Reg[EAX].i = -10; run( - "== 0x1\n" // code segment + "== code 0x1\n" "99\n" ); CHECK_TRACE_CONTENTS( diff --git a/subx/028translate.cc b/subx/028translate.cc index 42b94632..5a8c60c1 100644 --- a/subx/028translate.cc +++ b/subx/028translate.cc @@ -100,7 +100,7 @@ void write_elf_header(ostream& out, const program& p) { // e_version O(0x01); O(0x00); O(0x00); O(0x00); // e_entry - uint32_t e_entry = p.segments.at(0).start; // convention + uint32_t e_entry = find(p, "code")->start; // Override e_entry emit(e_entry); // e_phoff -- immediately after ELF header @@ -130,6 +130,7 @@ void write_elf_header(ostream& out, const program& p) { uint32_t p_offset = /*size of ehdr*/0x34 + SIZE(p.segments)*0x20/*size of each phdr*/; for (int i = 0; i < SIZE(p.segments); ++i) { + const segment& curr = p.segments.at(i); //// phdr // p_type uint32_t p_type = 0x1; @@ -137,18 +138,18 @@ void write_elf_header(ostream& out, const program& p) { // p_offset emit(p_offset); // p_vaddr - uint32_t p_start = p.segments.at(i).start; + uint32_t p_start = curr.start; emit(p_start); // p_paddr emit(p_start); // p_filesz - uint32_t size = num_words(p.segments.at(i)); + uint32_t size = num_words(curr); assert(p_offset + size < SEGMENT_ALIGNMENT); emit(size); // p_memsz emit(size); // p_flags - uint32_t p_flags = (i == 0) ? /*r-x*/0x5 : /*rw-*/0x6; // convention: only first segment is code + uint32_t p_flags = (curr.name == "code") ? /*r-x*/0x5 : /*rw-*/0x6; emit(p_flags); // p_align diff --git a/subx/030---operands.cc b/subx/030---operands.cc index 1a4ec563..5e6d6432 100644 --- a/subx/030---operands.cc +++ b/subx/030---operands.cc @@ -30,7 +30,7 @@ cerr << " instructions\n"; :(code) void test_pack_immediate_constants() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "bb 0x2a/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -161,7 +161,7 @@ Transform.push_back(pack_operands); :(code) void pack_operands(program& p) { if (p.segments.empty()) return; - segment& code = p.segments.at(0); + segment& code = *find(p, "code"); // Pack Operands(segment code) trace(3, "transform") << "-- pack operands" << end(); for (int i = 0; i < SIZE(code.lines); ++i) { @@ -320,7 +320,7 @@ void test_preserve_metadata_when_emitting_single_byte() { :(code) void test_pack_disp8() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "74 2/disp8\n" // jump 2 bytes away if ZF is set ); CHECK_TRACE_CONTENTS( @@ -331,7 +331,7 @@ void test_pack_disp8() { void test_pack_disp8_negative() { transform( - "== 0x1\n" // code segment + "== code 0x1\n" // running this will cause an infinite loop "74 -1/disp8\n" // jump 1 byte before if ZF is set ); @@ -352,7 +352,7 @@ void transform(const string& text_bytes) { void test_pack_modrm_imm32() { run( - "== 0x1\n" // code segment + "== code 0x1\n" // instruction effective address operand displacement immediate\n" // op subop mod rm32 base index scale r32\n" // 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\n" @@ -366,7 +366,7 @@ void test_pack_modrm_imm32() { void test_pack_imm32_large() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "b9 0x080490a7/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -377,7 +377,7 @@ void test_pack_imm32_large() { void test_pack_immediate_constants_hex() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "b9 0x2a/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -390,7 +390,7 @@ void test_pack_immediate_constants_hex() { void test_pack_silently_ignores_non_hex() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "b9 foo/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -403,7 +403,7 @@ void test_pack_silently_ignores_non_hex() { void test_pack_flags_bad_hex() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "b9 0xfoo/imm32\n" ); CHECK_TRACE_CONTENTS( diff --git a/subx/031check_operands.cc b/subx/031check_operands.cc index aad84da6..45d9e7e1 100644 --- a/subx/031check_operands.cc +++ b/subx/031check_operands.cc @@ -4,7 +4,7 @@ void test_check_missing_imm8_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "cd\n" // interrupt ?? ); CHECK_TRACE_CONTENTS( @@ -348,7 +348,7 @@ uint32_t expected_bit_for_received_operand(const word& w, set& instructi void test_conflicting_operand_type() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "cd/software-interrupt 80/imm8/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -362,7 +362,7 @@ void test_conflicting_operand_type() { void test_check_missing_mod_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 3/rm32/ebx 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -443,7 +443,7 @@ void check_operand_metadata_absent(const line& inst, const string& type, const w void test_modrm_with_displacement() { Reg[EAX].u = 0x1; transform( - "== 0x1\n" + "== code 0x1\n" // just avoid null pointer "8b/copy 1/mod/lookup+disp8 0/rm32/EAX 2/r32/EDX 4/disp8\n" // copy *(EAX+4) to EDX ); @@ -453,7 +453,7 @@ void test_modrm_with_displacement() { void test_check_missing_disp8() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "89/copy 1/mod/lookup+disp8 0/rm32/EAX 1/r32/ECX\n" // missing disp8 ); CHECK_TRACE_CONTENTS( @@ -464,7 +464,7 @@ void test_check_missing_disp8() { void test_check_missing_disp32() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "8b/copy 0/mod/indirect 5/rm32/.disp32 2/r32/EDX\n" // missing disp32 ); CHECK_TRACE_CONTENTS( @@ -475,7 +475,7 @@ void test_check_missing_disp32() { void test_conflicting_operands_in_modrm_instruction() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 0/mod 3/mod\n" ); CHECK_TRACE_CONTENTS( @@ -486,7 +486,7 @@ void test_conflicting_operands_in_modrm_instruction() { void test_conflicting_operand_type_modrm() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 0/mod 3/rm32/r32\n" ); CHECK_TRACE_CONTENTS( @@ -497,7 +497,7 @@ void test_conflicting_operand_type_modrm() { void test_check_missing_rm32_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 0/mod 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -508,7 +508,7 @@ void test_check_missing_rm32_operand() { void test_check_missing_subop_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/mod 3/rm32/ebx 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -519,7 +519,7 @@ void test_check_missing_subop_operand() { void test_check_missing_base_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 0/mod/indirect 4/rm32/use-sib 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -530,7 +530,7 @@ void test_check_missing_base_operand() { void test_check_missing_index_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 0/mod/indirect 4/rm32/use-sib 0/base 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -541,7 +541,7 @@ void test_check_missing_index_operand() { void test_check_missing_base_operand_2() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 0/mod/indirect 4/rm32/use-sib 2/index 3/scale 1/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -552,7 +552,7 @@ void test_check_missing_base_operand_2() { void test_check_extra_displacement() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "89/copy 0/mod/indirect 0/rm32/EAX 1/r32/ECX 4/disp8\n" ); CHECK_TRACE_CONTENTS( @@ -563,7 +563,7 @@ void test_check_extra_displacement() { void test_check_duplicate_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "89/copy 0/mod/indirect 0/rm32/EAX 1/r32/ECX 1/r32\n" ); CHECK_TRACE_CONTENTS( @@ -573,7 +573,7 @@ void test_check_duplicate_operand() { void test_check_base_operand_not_needed_in_direct_mode() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "81 0/add/subop 3/mod/indirect 4/rm32/use-sib 1/imm32\n" ); CHECK_TRACE_COUNT("error", 0); @@ -582,7 +582,7 @@ void test_check_base_operand_not_needed_in_direct_mode() { void test_extra_modrm() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "59/pop-to-ECX 3/mod/direct 1/rm32/ECX 4/r32/ESP\n" ); CHECK_TRACE_CONTENTS( @@ -613,8 +613,8 @@ void check_operands_f3(const line& /*unused*/) { void test_check_missing_disp32_operand() { Hide_errors = true; run( - "== 0x1\n" // code segment - " 0f 84 # jmp if ZF to ??\n" + "== code 0x1\n" + " 0f 84 # jmp if ZF to ??\n" ); CHECK_TRACE_CONTENTS( "error: '0f 84' (jump disp32 bytes away if equal, if ZF is set): missing disp32 operand\n" diff --git a/subx/032check_operand_bounds.cc b/subx/032check_operand_bounds.cc index 0aae0f67..72a66e3f 100644 --- a/subx/032check_operand_bounds.cc +++ b/subx/032check_operand_bounds.cc @@ -3,7 +3,7 @@ void test_check_bitfield_sizes() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 4/mod 3/rm32 1/r32\n" // add ECX to EBX ); CHECK_TRACE_CONTENTS( @@ -66,7 +66,7 @@ void check_operand_bounds(const word& w) { void test_check_bitfield_sizes_for_imm8() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0xff/imm8" // shift EBX left ); CHECK(!trace_contains_errors()); @@ -75,7 +75,7 @@ void test_check_bitfield_sizes_for_imm8() { void test_check_bitfield_sizes_for_imm8_error() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0x100/imm8" // shift EBX left ); CHECK_TRACE_CONTENTS( @@ -85,7 +85,7 @@ void test_check_bitfield_sizes_for_imm8_error() { void test_check_bitfield_sizes_for_negative_imm8() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x80/imm8" // shift EBX left ); CHECK(!trace_contains_errors()); @@ -94,7 +94,7 @@ void test_check_bitfield_sizes_for_negative_imm8() { void test_check_bitfield_sizes_for_negative_imm8_error() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x81/imm8" // shift EBX left ); CHECK_TRACE_CONTENTS( @@ -105,7 +105,7 @@ void test_check_bitfield_sizes_for_negative_imm8_error() { void test_check_bitfield_sizes_for_disp8() { // not bothering to run transform( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 1/mod/*+disp8 3/rm32 1/r32 0x7f/disp8\n" // add ECX to *(EBX+0x7f) ); CHECK(!trace_contains_errors()); @@ -114,7 +114,7 @@ void test_check_bitfield_sizes_for_disp8() { void test_check_bitfield_sizes_for_disp8_error() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 1/mod/*+disp8 3/rm32 1/r32 0x80/disp8\n" // add ECX to *(EBX+0x80) ); CHECK_TRACE_CONTENTS( @@ -125,7 +125,7 @@ void test_check_bitfield_sizes_for_disp8_error() { void test_check_bitfield_sizes_for_negative_disp8() { // not bothering to run transform( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x80/disp8\n" // add ECX to *(EBX-0x80) ); CHECK(!trace_contains_errors()); @@ -134,7 +134,7 @@ void test_check_bitfield_sizes_for_negative_disp8() { void test_check_bitfield_sizes_for_negative_disp8_error() { Hide_errors = true; run( - "== 0x1\n" // code segment + "== code 0x1\n" "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x81/disp8\n" // add ECX to *(EBX-0x81) ); CHECK_TRACE_CONTENTS( diff --git a/subx/034compute_segment_address.cc b/subx/034compute_segment_address.cc index 47311219..9eb1615d 100644 --- a/subx/034compute_segment_address.cc +++ b/subx/034compute_segment_address.cc @@ -1,12 +1,16 @@ -//: Start allowing us to not specify precise addresses for the start of each -//: segment. +//: ELF binaries have finicky rules about the precise alignment each segment +//: should start at. They depend on the amount of code in a program. +//: We shouldn't expect people to adjust segment addresses everytime they make +//: a change to their programs. +//: Let's start taking the given segment addresses as guidelines, and adjust +//: them as necessary. //: This gives up a measure of control in placing code and data. void test_segment_name() { run( - "== code\n" + "== code 0x09000000\n" "05/add-to-EAX 0x0d0c0b0a/imm32\n" - // code starts at 0x08048000 + p_offset, which is 0x54 for a single-segment binary + // code starts at 0x09000000 + p_offset, which is 0x54 for a single-segment binary ); CHECK_TRACE_CONTENTS( "load: 0x09000054 -> 05\n" @@ -19,113 +23,6 @@ void test_segment_name() { ); } -//: Update the parser to handle non-numeric segment name. -//: -//: We'll also support repeated segments with non-numeric names. - -:(before "End Globals") -map Segment_index; -bool Currently_parsing_named_segment = false; // global to permit cross-layer communication -int Currently_parsing_segment_index = -1; // global to permit cross-layer communication -:(before "End Reset") -Segment_index.clear(); -Currently_parsing_named_segment = false; -Currently_parsing_segment_index = -1; - -:(before "End Segment Parsing Special-cases(segment_title)") -if (!starts_with(segment_title, "0x")) { - Currently_parsing_named_segment = true; - if (!contains_key(Segment_index, segment_title)) { - trace(3, "parse") << "new segment '" << segment_title << "'" << end(); - if (out.segments.empty() && segment_title != "code") { - raise << "first segment must be 'code' but is '" << segment_title << "'\n" << end(); - return; - } - if (SIZE(out.segments) == 1 && segment_title != "data") { - raise << "second segment must be 'data' but is '" << segment_title << "'\n" << end(); - return; - } - put(Segment_index, segment_title, SIZE(out.segments)); - out.segments.push_back(segment()); - } - else { - trace(3, "parse") << "appending to segment '" << segment_title << "'" << end(); - } - Currently_parsing_segment_index = get(Segment_index, segment_title); -} - -:(before "End flush(p, lines) Special-cases") -if (Currently_parsing_named_segment) { - assert(!p.segments.empty()); - trace(3, "parse") << "flushing segment" << end(); - vector& curr_segment_data = p.segments.at(Currently_parsing_segment_index).lines; - curr_segment_data.insert(curr_segment_data.end(), lines.begin(), lines.end()); - lines.clear(); - Currently_parsing_named_segment = false; - Currently_parsing_segment_index = -1; - return; -} - -:(code) -void test_repeated_segment_merges_data() { - run( - "== code\n" - "05/add-to-EAX 0x0d0c0b0a/imm32\n" - "== code\n" // again - "2d/subtract-from-EAX 0xddccbbaa/imm32\n" - ); - CHECK_TRACE_CONTENTS( - "parse: new segment 'code'\n" - "parse: appending to segment 'code'\n" - // first segment - "load: 0x09000054 -> 05\n" - "load: 0x09000055 -> 0a\n" - "load: 0x09000056 -> 0b\n" - "load: 0x09000057 -> 0c\n" - "load: 0x09000058 -> 0d\n" - // second segment - "load: 0x09000059 -> 2d\n" - "load: 0x0900005a -> aa\n" - "load: 0x0900005b -> bb\n" - "load: 0x0900005c -> cc\n" - "load: 0x0900005d -> dd\n" - ); -} - -void test_error_on_missing_segment_header() { - Hide_errors = true; - run( - "05/add-to-EAX 0/imm32\n" - ); - CHECK_TRACE_CONTENTS( - "error: input does not start with a '==' section header\n" - ); -} - -void test_error_on_first_segment_not_code() { - Hide_errors = true; - run( - "== data\n" - "05 00 00 00 00\n" - ); - CHECK_TRACE_CONTENTS( - "error: first segment must be 'code' but is 'data'\n" - ); -} - -void test_error_on_second_segment_not_data() { - Hide_errors = true; - run( - "== code\n" - "05/add-to-EAX 0/imm32\n" - "== bss\n" - "05 00 00 00 00\n" - ); - CHECK_TRACE_CONTENTS( - "error: second segment must be 'data' but is 'bss'\n" - ); -} - //: compute segment address :(before "End Level-2 Transforms") @@ -137,8 +34,10 @@ void compute_segment_starts(program& p) { uint32_t p_offset = /*size of ehdr*/0x34 + SIZE(p.segments)*0x20/*size of each phdr*/; for (size_t i = 0; i < p.segments.size(); ++i) { segment& curr = p.segments.at(i); - if (curr.start == 0) { - curr.start = CODE_SEGMENT + i*SPACE_FOR_SEGMENT + p_offset; + if (curr.start >= 0x08000000) { + // valid address for user space, so assume we're creating a real ELF binary, not just running a test + curr.start &= 0xfffff000; // same number of zeros as the p_align used when emitting the ELF binary + curr.start |= p_offset; trace(99, "transform") << "segment " << i << " begins at address 0x" << HEXWORD << curr.start << end(); } p_offset += size_of(curr); diff --git a/subx/035labels.cc b/subx/035labels.cc index f3131168..3c2d0dd8 100644 --- a/subx/035labels.cc +++ b/subx/035labels.cc @@ -23,7 +23,7 @@ void test_entry_label() { run( - "== 0x1\n" // code segment + "== code 0x1\n" "05 0x0d0c0b0a/imm32\n" "Entry:\n" "05 0x0d0c0b0a/imm32\n" @@ -50,7 +50,7 @@ if (SIZE(s) == 2) return true; void test_pack_immediate_ignores_single_byte_nondigit_operand() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "b9/copy a/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -63,7 +63,7 @@ void test_pack_immediate_ignores_single_byte_nondigit_operand() { void test_pack_immediate_ignores_3_hex_digit_operand() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "b9/copy aaa/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -76,7 +76,7 @@ void test_pack_immediate_ignores_3_hex_digit_operand() { void test_pack_immediate_ignores_non_hex_operand() { Hide_errors = true; transform( - "== 0x1\n" // code segment + "== code 0x1\n" "b9/copy xxx/imm32\n" ); CHECK_TRACE_CONTENTS( @@ -108,7 +108,7 @@ void check_valid_name(const string& s) { void test_map_label() { transform( - "== 0x1\n" // code segment + "== code 0x1\n" "loop:\n" " 05 0x0d0c0b0a/imm32\n" ); @@ -123,7 +123,7 @@ Transform.push_back(rewrite_labels); void rewrite_labels(program& p) { trace(3, "transform") << "-- rewrite labels" << end(); if (p.segments.empty()) return; - segment& code = p.segments.at(0); + segment& code = *find(p, "code"); map byte_index; // values are unsigned, but we're going to do subtractions on them so they need to fit in 31 bits compute_byte_indices_for_labels(code, byte_index); if (trace_contains_errors()) return; @@ -278,7 +278,7 @@ string drop_last(const string& s) { void test_multiple_labels_at() { transform( - "== 0x1\n" // code segment + "== code 0x1\n" // address 1 "loop:\n" " $loop2:\n" @@ -304,7 +304,7 @@ void test_multiple_labels_at() { void test_loading_label_as_imm32() { transform( - "== 0x1\n" + "== code 0x1\n" "label:\n" " be/copy-to-ESI label/imm32\n" ); @@ -317,7 +317,7 @@ void test_loading_label_as_imm32() { void test_duplicate_label() { Hide_errors = true; transform( - "== 0x1\n" + "== code 0x1\n" "loop:\n" "loop:\n" " 05 0x0d0c0b0a/imm32\n" @@ -330,7 +330,7 @@ void test_duplicate_label() { void test_label_too_short() { Hide_errors = true; transform( - "== 0x1\n" + "== code 0x1\n" "xz:\n" " 05 0x0d0c0b0a/imm32\n" ); @@ -342,7 +342,7 @@ void test_label_too_short() { void test_label_hex() { Hide_errors = true; transform( - "== 0x1\n" + "== code 0x1\n" "0xab:\n" " 05 0x0d0c0b0a/imm32\n" ); @@ -354,7 +354,7 @@ void test_label_hex() { void test_label_negative_hex() { Hide_errors = true; transform( - "== 0x1\n" + "== code 0x1\n" "-a:\n" " 05 0x0d0c0b0a/imm32\n" ); @@ -368,10 +368,10 @@ void test_label_negative_hex() { void test_segment_size_ignores_labels() { transform( - "== code\n" // 0x09000074 + "== code 0x09000074\n" " 05/add 0x0d0c0b0a/imm32\n" // 5 bytes "foo:\n" // 0 bytes - "== data\n" // 0x0a000079 + "== data 0x0a000000\n" "bar:\n" " 00\n" ); diff --git a/subx/036global_variables.cc b/subx/036global_variables.cc index fffabf72..c22ac3d3 100644 --- a/subx/036global_variables.cc +++ b/subx/036global_variables.cc @@ -9,14 +9,14 @@ :(code) void test_global_variable() { run( - "== code\n" + "== code 0x1\n" "b9 x/imm32\n" - "== data\n" + "== data 0x2000\n" "x:\n" " 00 00 00 00\n" ); CHECK_TRACE_CONTENTS( - "transform: global variable 'x' is at address 0x0a000079\n" + "transform: global variable 'x' is at address 0x00002000\n" ); } @@ -34,8 +34,10 @@ void rewrite_global_variables(program& p) { } void compute_addresses_for_global_variables(const program& p, map& address) { - for (int i = /*skip code segment*/1; i < SIZE(p.segments); ++i) - compute_addresses_for_global_variables(p.segments.at(i), address); + for (int i = 0; i < SIZE(p.segments); ++i) { + if (p.segments.at(i).name != "code") + compute_addresses_for_global_variables(p.segments.at(i), address); + } } void compute_addresses_for_global_variables(const segment& s, map& address) { @@ -69,15 +71,21 @@ void compute_addresses_for_global_variables(const segment& s, map& address) { if (p.segments.empty()) return; - replace_global_variables_in_code_segment(p.segments.at(0), address); - for (int i = /*skip code*/1; i < SIZE(p.segments); ++i) - replace_global_variables_in_data_segment(p.segments.at(i), address); + for (int i = 0; i < SIZE(p.segments); ++i) { + segment& curr = p.segments.at(i); + if (curr.name == "code") + replace_global_variables_in_code_segment(curr, address); + else + replace_global_variables_in_data_segment(curr, address); + } } void replace_global_variables_in_code_segment(segment& code, const map& address) { @@ -154,7 +162,7 @@ Transform.push_back(correlate_disp32_with_mod); :(code) void correlate_disp32_with_mod(program& p) { if (p.segments.empty()) return; - segment& code = p.segments.at(0); + segment& code = *find(p, "code"); for (int i = 0; i < SIZE(code.lines); ++i) { line& inst = code.lines.at(i); for (int j = 0; j < SIZE(inst.words); ++j) { @@ -182,9 +190,9 @@ bool has_metadata(const word& w, const string& m) { void test_global_variable_disallowed_in_jump() { Hide_errors = true; run( - "== code\n" + "== code 0x1\n" "eb/jump x/disp8\n" - "== data\n" + "== data 0x2000\n" "x:\n" " 00 00 00 00\n" ); @@ -198,9 +206,9 @@ void test_global_variable_disallowed_in_jump() { void test_global_variable_disallowed_in_call() { Hide_errors = true; run( - "== code\n" + "== code 0x1\n" "e8/call x/disp32\n" - "== data\n" + "== data 0x2000\n" "x:\n" " 00 00 00 00\n" ); @@ -213,9 +221,9 @@ void test_global_variable_disallowed_in_call() { void test_global_variable_in_data_segment() { run( - "== 0x1\n" + "== code 0x1\n" "b9 x/imm32\n" - "== 0x0a000000\n" + "== data 0x2000\n" "x:\n" " y/imm32\n" "y:\n" @@ -223,28 +231,28 @@ void test_global_variable_in_data_segment() { ); // check that we loaded 'x' with the address of 'y' CHECK_TRACE_CONTENTS( - "load: 0x0a000000 -> 04\n" - "load: 0x0a000001 -> 00\n" - "load: 0x0a000002 -> 00\n" - "load: 0x0a000003 -> 0a\n" + "load: 0x00002000 -> 04\n" + "load: 0x00002001 -> 20\n" + "load: 0x00002002 -> 00\n" + "load: 0x00002003 -> 00\n" ); CHECK_TRACE_COUNT("error", 0); } void test_raw_number_with_imm32_in_data_segment() { run( - "== 0x1\n" + "== code 0x1\n" "b9 x/imm32\n" - "== 0x0a000000\n" + "== data 0x2000\n" "x:\n" " 1/imm32\n" ); // check that we loaded 'x' with the address of 1 CHECK_TRACE_CONTENTS( - "load: 0x0a000000 -> 01\n" - "load: 0x0a000001 -> 00\n" - "load: 0x0a000002 -> 00\n" - "load: 0x0a000003 -> 00\n" + "load: 0x00002000 -> 01\n" + "load: 0x00002001 -> 00\n" + "load: 0x00002002 -> 00\n" + "load: 0x00002003 -> 00\n" ); CHECK_TRACE_COUNT("error", 0); } @@ -252,9 +260,9 @@ void test_raw_number_with_imm32_in_data_segment() { void test_duplicate_global_variable() { Hide_errors = true; run( - "== 0x1\n" + "== code 0x1\n" "40/increment-EAX\n" - "== 0x0a000000\n" + "== data 0x2000\n" "x:\n" "x:\n" " 00\n" @@ -266,9 +274,9 @@ void test_duplicate_global_variable() { void test_global_variable_disp32_with_modrm() { run( - "== code\n" + "== code 0x1\n" "8b/copy 0/mod/indirect 5/rm32/.disp32 2/r32/EDX x/disp32\n" - "== data\n" + "== data 0x2000\n" "x:\n" " 00 00 00 00\n" ); @@ -277,7 +285,7 @@ void test_global_variable_disp32_with_modrm() { void test_global_variable_disp32_with_call() { transform( - "== code\n" + "== code 0x1\n" "foo:\n" " e8/call bar/disp32\n" "bar:\n" diff --git a/subx/038---literal_strings.cc b/subx/038---literal_strings.cc index 9b2c3902..ecc80176 100644 --- a/subx/038---literal_strings.cc +++ b/subx/038---literal_strings.cc @@ -5,9 +5,9 @@ void test_transform_literal_string() { run( - "== code\n" + "== code 0x1\n" "b8/copy \"test\"/imm32\n" - "== data\n" // need to manually create the segment for now + "== data 0x2000\n" // need an empty segment ); CHECK_TRACE_CONTENTS( "transform: -- move literal strings to data segment\n" @@ -30,8 +30,8 @@ int Next_auto_global = 1; void transform_literal_strings(program& p) { trace(3, "transform") << "-- move literal strings to data segment" << end(); if (p.segments.empty()) return; - segment& code = p.segments.at(0); - segment data; + segment& code = *find(p, "code"); + segment& data = *find(p, "data"); for (int i = 0; i < SIZE(code.lines); ++i) { line& inst = code.lines.at(i); for (int j = 0; j < SIZE(inst.words); ++j) { @@ -45,13 +45,6 @@ void transform_literal_strings(program& p) { } trace(99, "transform") << "instruction after transform: '" << data_to_string(inst) << "'" << end(); } - if (data.lines.empty()) return; - if (SIZE(p.segments) < 2) { - p.segments.resize(2); - p.segments.at(1).lines.swap(data.lines); - } - vector& existing_data = p.segments.at(1).lines; - existing_data.insert(existing_data.end(), data.lines.begin(), data.lines.end()); } void add_global_to_data_segment(const string& name, const word& value, segment& data) { diff --git a/subx/040---tests.cc b/subx/040---tests.cc index e5949bbd..af05bff3 100644 --- a/subx/040---tests.cc +++ b/subx/040---tests.cc @@ -19,7 +19,7 @@ void test_run_test() { Mem.push_back(vma(0xbd000000)); // manually allocate memory Reg[ESP].u = 0xbd000100; run( - "== 0x1\n" // code segment + "== code 0x1\n" // code segment "main:\n" " e8/call run-tests/disp32\n" // 5 bytes " f4/halt\n" // 1 byte @@ -35,7 +35,7 @@ void test_run_test() { void create_test_function(program& p) { if (p.segments.empty()) return; - segment& code = p.segments.at(0); + segment& code = *find(p, "code"); trace(3, "transform") << "-- create 'run-tests'" << end(); vector new_insts; for (int i = 0; i < SIZE(code.lines); ++i) { diff --git a/subx/049memory_layout.subx b/subx/049memory_layout.subx new file mode 100644 index 00000000..36837ade --- /dev/null +++ b/subx/049memory_layout.subx @@ -0,0 +1,8 @@ +# Segment addresses aren't really the concern of any other layer, so we'll +# define them separately. They're approximate due to fidgety ELF alignment +# requirements, so don't get clever assuming variables are at specific +# addresses. + +== code 0x09000000 + +== data 0x0a000000 diff --git a/subx/Readme.md b/subx/Readme.md index c91d10ab..cab1a503 100644 --- a/subx/Readme.md +++ b/subx/Readme.md @@ -243,10 +243,11 @@ Use it now to follow along for a more complete tour of SubX syntax. SubX programs map to the same ELF binaries that a conventional Linux system uses. Linux ELF binaries consist of a series of _segments_. In particular, they distinguish between code and data. Correspondingly, SubX programs consist of a -series of segments, each starting with a header line: `==` followed by a name. -The first segment must be named `code`; the second must be named `data`. +series of segments, each starting with a header line: `==` followed by a name +and approximate starting address. -Execution begins at the start of the `code` segment by default. +All code must lie in a segment called 'code'. Execution begins at the start of +the `code` segment by default. You can reuse segment names: diff --git a/subx/examples/ex1.subx b/subx/examples/ex1.subx index 2c3f64eb..4b9f208e 100644 --- a/subx/examples/ex1.subx +++ b/subx/examples/ex1.subx @@ -8,7 +8,7 @@ # $ echo $? # 42 -== code +== code 0x09000000 # syscall(exit, 42) bb/copy-to-EBX 2a/imm32 # 42 in hex diff --git a/subx/examples/ex10.subx b/subx/examples/ex10.subx index 53148464..fd2ccc08 100644 --- a/subx/examples/ex10.subx +++ b/subx/examples/ex10.subx @@ -7,7 +7,7 @@ # $ echo $? # 0 # false -== code +== code 0x09000000 # 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 diff --git a/subx/examples/ex11.subx b/subx/examples/ex11.subx index 78bcf5c9..ba75c1d3 100644 --- a/subx/examples/ex11.subx +++ b/subx/examples/ex11.subx @@ -14,7 +14,7 @@ # because checking for it would require the function being tested! Breakage # would cause tests to not run, rather than to fail as we'd like.) -== code +== code 0x09000000 # 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 @@ -339,7 +339,7 @@ write-stderr: # s : (address array byte) -> 5d/pop-to-EBP c3/return -== data +== data 0x0a000000 Newline: # size diff --git a/subx/examples/ex12.subx b/subx/examples/ex12.subx index 4518aecc..4d43b033 100644 --- a/subx/examples/ex12.subx +++ b/subx/examples/ex12.subx @@ -6,7 +6,7 @@ # $ ./subx run examples/ex12 # You shouldn't get a segmentation fault. -== code +== code 0x09000000 # 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 @@ -24,7 +24,7 @@ b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -== data +== data 0x0a000000 # various constants used here were found in the Linux sources (search for file mman-common.h) Mmap-new-segment: # type mmap_arg_struct diff --git a/subx/examples/ex2.subx b/subx/examples/ex2.subx index 757c5220..3605fcc8 100644 --- a/subx/examples/ex2.subx +++ b/subx/examples/ex2.subx @@ -7,7 +7,7 @@ # $ echo $? # 2 -== code +== code 0x09000000 # EBX = 1 bb/copy-to-EBX 1/imm32 diff --git a/subx/examples/ex3.subx b/subx/examples/ex3.subx index f7352b2f..c9ad3e38 100644 --- a/subx/examples/ex3.subx +++ b/subx/examples/ex3.subx @@ -7,7 +7,7 @@ # $ echo $? # 55 -== code +== code 0x09000000 # 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 diff --git a/subx/examples/ex4 b/subx/examples/ex4 index 477dab46..66fb61e6 100755 Binary files a/subx/examples/ex4 and b/subx/examples/ex4 differ diff --git a/subx/examples/ex4.subx b/subx/examples/ex4.subx index b18a5da0..a1f042ed 100644 --- a/subx/examples/ex4.subx +++ b/subx/examples/ex4.subx @@ -4,7 +4,13 @@ # $ ./subx translate examples/ex4.subx -o examples/ex4 # $ ./subx run examples/ex4 -== code +== data 0x0a000000 + +# the global variable we save to +X: + 0/imm32 # space for read() to write to + +== code 0x09000000 # syscall(read, stdin, X, 1) # . fd = 0 (stdin) @@ -32,9 +38,4 @@ cd/syscall 0x80/imm8 b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -== data - -X: - 0/imm32 # space for read() to write to - # . . vim:nowrap:textwidth=0 diff --git a/subx/examples/ex5.subx b/subx/examples/ex5.subx index f9ad9ea8..f051a91f 100644 --- a/subx/examples/ex5.subx +++ b/subx/examples/ex5.subx @@ -4,7 +4,7 @@ # $ ./subx translate examples/ex5.subx -o examples/ex5 # $ ./subx run examples/ex5 -== code +== code 0x09000000 # 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 diff --git a/subx/examples/ex6.subx b/subx/examples/ex6.subx index 3375fb43..c5999033 100644 --- a/subx/examples/ex6.subx +++ b/subx/examples/ex6.subx @@ -5,7 +5,7 @@ # $ ./subx run examples/ex6 # Hello, world! -== code +== code 0x09000000 # 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 @@ -25,7 +25,7 @@ b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -== data +== data 0x0a000000 Size: # size of string 0x0e/imm32 # 14 diff --git a/subx/examples/ex7.subx b/subx/examples/ex7.subx index c6dd3423..ee043c86 100644 --- a/subx/examples/ex7.subx +++ b/subx/examples/ex7.subx @@ -11,7 +11,7 @@ # $ echo $? # 97 -== code +== code 0x09000000 # 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 @@ -91,7 +91,7 @@ b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -== data +== data 0x0a000000 Stream: 0/imm32 diff --git a/subx/examples/ex8.subx b/subx/examples/ex8.subx index d31786da..85fe1568 100644 --- a/subx/examples/ex8.subx +++ b/subx/examples/ex8.subx @@ -14,7 +14,7 @@ # ... # Locals start from ESP-4 downwards. -== code +== code 0x09000000 # 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 diff --git a/subx/examples/ex9.subx b/subx/examples/ex9.subx index 66fbf2ff..344c62ae 100644 --- a/subx/examples/ex9.subx +++ b/subx/examples/ex9.subx @@ -17,7 +17,7 @@ # ... # Locals start from ESP-4 downwards. -== code +== code 0x09000000 # 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 diff --git a/subx/test_apps b/subx/test_apps index 2164d1cf..3001940f 100755 --- a/subx/test_apps +++ b/subx/test_apps @@ -12,7 +12,7 @@ CFLAGS=$CFLAGS ./build echo ex1 ./subx translate examples/ex1.subx -o examples/ex1 -git diff --exit-code examples/ex1 +[ "$1" != record ] && git diff --exit-code examples/ex1 ./subx run examples/ex1 || ret=$? test $ret -eq 42 # life, the universe and everything test `uname` = 'Linux' && { @@ -22,7 +22,7 @@ test `uname` = 'Linux' && { echo ex2 ./subx translate examples/ex2.subx -o examples/ex2 -git diff --exit-code examples/ex2 +[ "$1" != record ] && git diff --exit-code examples/ex2 ./subx run examples/ex2 || ret=$? test $ret -eq 2 # 1 + 1 test `uname` = 'Linux' && { @@ -32,7 +32,7 @@ test `uname` = 'Linux' && { echo ex3 ./subx translate examples/ex3.subx -o examples/ex3 -git diff --exit-code examples/ex3 +[ "$1" != record ] && git diff --exit-code examples/ex3 ./subx run examples/ex3 || ret=$? test $ret -eq 55 # 1 + 2 + ... + 10 test `uname` = 'Linux' && { @@ -42,7 +42,7 @@ test `uname` = 'Linux' && { echo ex4 ./subx translate examples/ex4.subx -o examples/ex4 -git diff --exit-code examples/ex4 +[ "$1" != record ] && git diff --exit-code examples/ex4 echo a | ./subx run examples/ex4 >ex4.out || true test `cat ex4.out` = 'a' test `uname` = 'Linux' && { @@ -52,7 +52,7 @@ test `uname` = 'Linux' && { echo ex5 ./subx translate examples/ex5.subx -o examples/ex5 -git diff --exit-code examples/ex5 +[ "$1" != record ] && git diff --exit-code examples/ex5 echo a | ./subx run examples/ex5 >ex5.out || true test `cat ex5.out` = 'a' test `uname` = 'Linux' && { @@ -62,7 +62,7 @@ test `uname` = 'Linux' && { echo ex6 ./subx translate examples/ex6.subx -o examples/ex6 -git diff --exit-code examples/ex6 +[ "$1" != record ] && git diff --exit-code examples/ex6 ./subx run examples/ex6 >ex6.out || true test "`cat ex6.out`" = 'Hello, world!' test `uname` = 'Linux' && { @@ -72,7 +72,7 @@ test `uname` = 'Linux' && { echo ex7 ./subx translate examples/ex7.subx -o examples/ex7 -git diff --exit-code examples/ex7 +[ "$1" != record ] && git diff --exit-code examples/ex7 ./subx run examples/ex7 || ret=$? test $ret -eq 97 # 'a' test `uname` = 'Linux' && { diff --git a/subx/test_layers b/subx/test_layers index 688a5a99..ad5ab1a0 100755 --- a/subx/test_layers +++ b/subx/test_layers @@ -20,6 +20,7 @@ CFLAGS=$CFLAGS ./build # build optimized by default since we'll be running it r # add SubX files one at a time for f in [0-9]*.subx do + [ $f == '049'* ] && continue echo "=== $f" ./subx translate $(../enumerate/enumerate --until $f |grep '\.subx$') -o a.elf && ./subx run a.elf echo