switch to new syntax for segment headers in C++

This commit is contained in:
Kartik Agaram 2019-05-18 00:00:18 -07:00
parent 4b506b630c
commit 83c6701403
36 changed files with 482 additions and 515 deletions

View File

@ -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<line> lines;
// End segment Fields
@ -132,6 +133,7 @@ struct word {
:(code)
void parse(istream& fin, program& out) {
segment* curr_segment = NULL;
vector<line> 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<line>& 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<line>& 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
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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</*name*/string, int> 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<line>& 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);

View File

@ -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<string, int32_t> 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"
);

View File

@ -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<string, uint32_t>& 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<string, uint32_t>& address) {
@ -69,15 +71,21 @@ void compute_addresses_for_global_variables(const segment& s, map<string, uint32
}
void drop_global_variables(program& p) {
for (int i = /*skip code segment*/1; i < SIZE(p.segments); ++i)
drop_labels(p.segments.at(i));
for (int i = 0; i < SIZE(p.segments); ++i) {
if (p.segments.at(i).name != "code")
drop_labels(p.segments.at(i));
}
}
void replace_global_variables_with_addresses(program& p, const map<string, uint32_t>& 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<string, uint32_t>& 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"

View File

@ -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<line>& 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) {

View File

@ -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<line> new_insts;
for (int i = 0; i < SIZE(code.lines); ++i) {

View File

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

View File

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

View File

@ -8,7 +8,7 @@
# $ echo $?
# 42
== code
== code 0x09000000
# syscall(exit, 42)
bb/copy-to-EBX 2a/imm32 # 42 in hex

View File

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

View File

@ -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) -> <void>
5d/pop-to-EBP
c3/return
== data
== data 0x0a000000
Newline:
# size

View File

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

View File

@ -7,7 +7,7 @@
# $ echo $?
# 2
== code
== code 0x09000000
# EBX = 1
bb/copy-to-EBX 1/imm32

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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' && {

View File

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