https://github.com/akkartik/mu/blob/main/linux/bootstrap/034check_operand_bounds.cc
1
2
3 void test_check_bitfield_sizes() {
4 Hide_errors = true;
5 run(
6 "== code 0x1\n"
7 "01/add 4/mod 3/rm32 1/r32\n"
8 );
9 CHECK_TRACE_CONTENTS(
10 "error: '4/mod' too large to fit in bitfield mod\n"
11 );
12 }
13
14 :(before "End Globals")
15 map<string, uint32_t> Operand_bound;
16 :(before "End One-time Setup")
17 put_new(Operand_bound, "subop", 1<<3);
18 put_new(Operand_bound, "mod", 1<<2);
19 put_new(Operand_bound, "rm32", 1<<3);
20 put_new(Operand_bound, "base", 1<<3);
21 put_new(Operand_bound, "index", 1<<3);
22 put_new(Operand_bound, "scale", 1<<2);
23 put_new(Operand_bound, "r32", 1<<3);
24 put_new(Operand_bound, "disp8", 1<<8);
25 put_new(Operand_bound, "disp16", 1<<16);
26
27 put_new(Operand_bound, "imm8", 1<<8);
28
29
30 :(before "Pack Operands(segment code)")
31 check_argument_bounds(code);
32 if (trace_contains_errors()) return;
33 :(code)
34 void check_argument_bounds(const segment& code) {
35 trace(3, "transform") << "-- check argument bounds" << end();
36 for (int i = 0; i < SIZE(code.lines); ++i) {
37 const line& inst = code.lines.at(i);
38 for (int j = first_argument(inst); j < SIZE(inst.words); ++j)
39 check_argument_bounds(inst.words.at(j));
40 if (trace_contains_errors()) return;
41 }
42 }
43
44 void check_argument_bounds(const word& w) {
45 for (map<string, uint32_t>::iterator p = Operand_bound.begin(); p != Operand_bound.end(); ++p) {
46 if (!has_argument_metadata(w, p->first)) continue;
47 if (!looks_like_hex_int(w.data)) continue;
48 int32_t x = parse_int(w.data);
49 if (x >= 0) {
50 if (p->first == "disp8" || p->first == "disp16") {
51 if (static_cast<uint32_t>(x) >= p->second/2)
52 raise << "'" << w.original << "' too large to fit in signed bitfield " << p->first << '\n' << end();
53 }
54 else {
55 if (static_cast<uint32_t>(x) >= p->second)
56 raise << "'" << w.original << "' too large to fit in bitfield " << p->first << '\n' << end();
57 }
58 }
59 else {
60
61 if (x < -1*static_cast<int32_t>(p->second/2))
62 raise << "'" << w.original << "' too large to fit in bitfield " << p->first << '\n' << end();
63 }
64 }
65 }
66
67 void test_check_bitfield_sizes_for_imm8() {
68 run(
69 "== code 0x1\n"
70 "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0xff/imm8"
71 );
72 CHECK(!trace_contains_errors());
73 }
74
75 void test_check_bitfield_sizes_for_imm8_error() {
76 Hide_errors = true;
77 run(
78 "== code 0x1\n"
79 "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0x100/imm8"
80 );
81 CHECK_TRACE_CONTENTS(
82 "error: '0x100/imm8' too large to fit in bitfield imm8\n"
83 );
84 }
85
86 void test_check_bitfield_sizes_for_negative_imm8() {
87 run(
88 "== code 0x1\n"
89 "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x80/imm8"
90 );
91 CHECK(!trace_contains_errors());
92 }
93
94 void test_check_bitfield_sizes_for_negative_imm8_error() {
95 Hide_errors = true;
96 run(
97 "== code 0x1\n"
98 "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x81/imm8"
99 );
100 CHECK_TRACE_CONTENTS(
101 "error: '-0x81/imm8' too large to fit in bitfield imm8\n"
102 );
103 }
104
105 void test_check_bitfield_sizes_for_disp8() {
106
107 transform(
108 "== code 0x1\n"
109 "01/add 1/mod/*+disp8 3/rm32 1/r32 0x7f/disp8\n"
110 );
111 CHECK(!trace_contains_errors());
112 }
113
114 void test_check_bitfield_sizes_for_disp8_error() {
115 Hide_errors = true;
116 run(
117 "== code 0x1\n"
118 "01/add 1/mod/*+disp8 3/rm32 1/r32 0x80/disp8\n"
119 );
120 CHECK_TRACE_CONTENTS(
121 "error: '0x80/disp8' too large to fit in signed bitfield disp8\n"
122 );
123 }
124
125 void test_check_bitfield_sizes_for_negative_disp8() {
126
127 transform(
128 "== code 0x1\n"
129 "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x80/disp8\n"
130 );
131 CHECK(!trace_contains_errors());
132 }
133
134 void test_check_bitfield_sizes_for_negative_disp8_error() {
135 Hide_errors = true;
136 run(
137 "== code 0x1\n"
138 "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x81/disp8\n"
139 );
140 CHECK_TRACE_CONTENTS(
141 "error: '-0x81/disp8' too large to fit in bitfield disp8\n"
142 );
143 }