switch to new syntax for segment headers in C++
This commit is contained in:
parent
4b506b630c
commit
83c6701403
141
subx/011run.cc
141
subx/011run.cc
|
@ -13,15 +13,15 @@ put_new(Help, "syntax",
|
|||
"(start of line, or following a space).\n"
|
||||
"\n"
|
||||
"Each segment starts with a header line: a '==' delimiter followed by the name of\n"
|
||||
"the segment.\n"
|
||||
"the segment and a (sometimes approximate) starting address in memory.\n"
|
||||
"The name 'code' is special; instructions to execute should always go here.\n"
|
||||
"\n"
|
||||
"The first segment contains code and should be called 'code'.\n"
|
||||
"The second segment should be called 'data'.\n"
|
||||
"The resulting binary starts running from the start of the code segment by default.\n"
|
||||
"The resulting binary starts running from the start of the segment by default.\n"
|
||||
"To start elsewhere in the code segment, define a special label called 'Entry'.\n"
|
||||
"\n"
|
||||
"Segments with the same name get merged together. This rule helps keep functions and\n"
|
||||
"their data close together in .subx files.\n"
|
||||
"You don't have to specify the starting address after the first time.\n"
|
||||
"\n"
|
||||
"Lines consist of a series of words. Words can contain arbitrary metadata\n"
|
||||
"after a '/', but they can never contain whitespace. Metadata has no effect\n"
|
||||
|
@ -35,16 +35,16 @@ put_new(Help, "syntax",
|
|||
cerr << " syntax\n";
|
||||
|
||||
:(code)
|
||||
void test_add_imm32_to_EAX() {
|
||||
void test_copy_imm32_to_EAX() {
|
||||
// At the lowest level, SubX programs are a series of hex bytes, each
|
||||
// (variable-length) instruction on one line.
|
||||
run(
|
||||
// Comments start with '#' and are ignored.
|
||||
"# comment\n"
|
||||
// Segment headers start with '==' and a name or starting hex address.
|
||||
// Segment headers start with '==', a name and a starting hex address.
|
||||
// There's usually one code and one data segment. The code segment
|
||||
// always comes first.
|
||||
"== 0x1\n" // code segment
|
||||
"== code 0x1\n" // code segment
|
||||
|
||||
// After the header, each segment consists of lines, and each line
|
||||
// consists of words separated by whitespace.
|
||||
|
@ -107,6 +107,7 @@ struct program {
|
|||
};
|
||||
:(before "struct program")
|
||||
struct segment {
|
||||
string name;
|
||||
uint32_t start;
|
||||
vector<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
|
||||
);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# $ echo $?
|
||||
# 42
|
||||
|
||||
== code
|
||||
== code 0x09000000
|
||||
|
||||
# syscall(exit, 42)
|
||||
bb/copy-to-EBX 2a/imm32 # 42 in hex
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# $ echo $?
|
||||
# 2
|
||||
|
||||
== code
|
||||
== code 0x09000000
|
||||
|
||||
# EBX = 1
|
||||
bb/copy-to-EBX 1/imm32
|
||||
|
|
|
@ -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.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' && {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue