https://github.com/akkartik/mu/blob/main/021byte_addressing.cc
1
2
3
4
5
6 :(code)
7 string rname_8bit(uint8_t r) {
8 switch (r) {
9 case 0: return "AL";
10 case 1: return "CL";
11 case 2: return "DL";
12 case 3: return "BL";
13 case 4: return "AH";
14 case 5: return "CH";
15 case 6: return "DH";
16 case 7: return "BH";
17 default: raise << "invalid 8-bit register " << r << '\n' << end(); return "";
18 }
19 }
20
21 uint8_t* effective_byte_address(uint8_t modrm) {
22 uint8_t mod = (modrm>>6);
23 uint8_t rm = modrm & 0x7;
24 if (mod == 3) {
25
26 trace(Callstack_depth+1, "run") << "r/m8 is " << rname_8bit(rm) << end();
27 return reg_8bit(rm);
28 }
29
30 return mem_addr_u8(effective_address_number(modrm));
31 }
32
33 uint8_t* reg_8bit(uint8_t rm) {
34 uint8_t* result = reinterpret_cast<uint8_t*>(&Reg[rm & 0x3].i);
35 if (rm & 0x4)
36 ++result;
37 return result;
38 }
39
40 :(before "End Initialize Op Names")
41 put_new(Name, "88", "copy r8 to r8/m8-at-r32");
42
43 :(code)
44 void test_copy_r8_to_mem_at_r32() {
45 Reg[EBX].i = 0x224488ab;
46 Reg[EAX].i = 0x2000;
47 run(
48 "== code 0x1\n"
49
50 " 88 18 \n"
51
52 "== data 0x2000\n"
53 "f0 cc bb aa\n"
54 );
55 CHECK_TRACE_CONTENTS(
56 "run: copy BL to r8/m8-at-r32\n"
57 "run: effective address is 0x00002000 (EAX)\n"
58 "run: storing 0xab\n"
59 );
60 CHECK_EQ(0xaabbccab, read_mem_u32(0x2000));
61 }
62
63 :(before "End Single-Byte Opcodes")
64 case 0x88: {
65 const uint8_t modrm = next();
66 const uint8_t rsrc = (modrm>>3)&0x7;
67 trace(Callstack_depth+1, "run") << "copy " << rname_8bit(rsrc) << " to r8/m8-at-r32" << end();
68
69 uint8_t* dest = effective_byte_address(modrm);
70 const uint8_t* src = reg_8bit(rsrc);
71 *dest = *src;
72 trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end();
73 break;
74 }
75
76
77
78 :(before "End Initialize Op Names")
79 put_new(Name, "8a", "copy r8/m8-at-r32 to r8");
80
81 :(code)
82 void test_copy_mem_at_r32_to_r8() {
83 Reg[EBX].i = 0xaabbcc0f;
84 Reg[EAX].i = 0x2000;
85 run(
86 "== code 0x1\n"
87
88 " 8a 18 \n"
89
90 "== data 0x2000\n"
91 "ab ff ff ff\n"
92 );
93 CHECK_TRACE_CONTENTS(
94 "run: copy r8/m8-at-r32 to BL\n"
95 "run: effective address is 0x00002000 (EAX)\n"
96 "run: storing 0xab\n"
97
98 "run: EBX now contains 0xaabbccab\n"
99 );
100 }
101
102 :(before "End Single-Byte Opcodes")
103 case 0x8a: {
104 const uint8_t modrm = next();
105 const uint8_t rdest = (modrm>>3)&0x7;
106 trace(Callstack_depth+1, "run") << "copy r8/m8-at-r32 to " << rname_8bit(rdest) << end();
107
108 const uint8_t* src = effective_byte_address(modrm);
109 uint8_t* dest = reg_8bit(rdest);
110 trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*src) << end();
111 *dest = *src;
112 const uint8_t rdest_32bit = rdest & 0x3;
113 trace(Callstack_depth+1, "run") << rname(rdest_32bit) << " now contains 0x" << HEXWORD << Reg[rdest_32bit].u << end();
114 break;
115 }
116
117 :(code)
118 void test_cannot_copy_byte_to_ESP_EBP_ESI_EDI() {
119 Reg[ESI].u = 0xaabbccdd;
120 Reg[EBX].u = 0x11223344;
121 run(
122 "== code 0x1\n"
123
124 " 8a f3 \n"
125
126 );
127 CHECK_TRACE_CONTENTS(
128
129 "run: copy r8/m8-at-r32 to DH\n"
130 "run: storing 0x44\n"
131 );
132
133 CHECK_EQ(Reg[ESI].u, 0xaabbccdd);
134 }
135
136
137
138 :(before "End Initialize Op Names")
139 put_new(Name, "c6", "copy imm8 to r8/m8-at-r32 (mov)");
140
141 :(code)
142 void test_copy_imm8_to_mem_at_r32() {
143 Reg[EAX].i = 0x2000;
144 run(
145 "== code 0x1\n"
146
147 " c6 00 dd \n"
148
149 "== data 0x2000\n"
150 "f0 cc bb aa\n"
151 );
152 CHECK_TRACE_CONTENTS(
153 "run: copy imm8 to r8/m8-at-r32\n"
154 "run: effective address is 0x00002000 (EAX)\n"
155 "run: storing 0xdd\n"
156 );
157 CHECK_EQ(0xaabbccdd, read_mem_u32(0x2000));
158 }
159
160 :(before "End Single-Byte Opcodes")
161 case 0xc6: {
162 const uint8_t modrm = next();
163 const uint8_t src = next();
164 trace(Callstack_depth+1, "run") << "copy imm8 to r8/m8-at-r32" << end();
165 trace(Callstack_depth+1, "run") << "imm8 is 0x" << HEXWORD << NUM(src) << end();
166 const uint8_t subop = (modrm>>3)&0x7;
167 if (subop != 0) {
168 cerr << "unrecognized subop for opcode c6: " << NUM(subop) << " (only 0/copy currently implemented)\n";
169 exit(1);
170 }
171
172 uint8_t* dest = effective_byte_address(modrm);
173 *dest = src;
174 trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end();
175 break;
176 }
177
178
179
180 :(before "End Initialize Op Names")
181 put_new(Name_0f, "94", "set r8/m8-at-rm32 to 1 if equal, if ZF is set, 0 otherwise (setcc/setz/sete)");
182 put_new(Name_0f, "95", "set r8/m8-at-rm32 to 1 if not equal, if ZF is not set, 0 otherwise (setcc/setnz/setne)");
183 put_new(Name_0f, "9f", "set r8/m8-at-rm32 to 1 if greater (signed), if ZF is unset and SF == OF, 0 otherwise (setcc/setg/setnle)");
184 put_new(Name_0f, "97", "set r8/m8-at-rm32 to 1 if greater (unsigned), if ZF is unset and CF is unset, 0 otherwise (setcc/seta/setnbe)");
185 put_new(Name_0f, "9d", "set r8/m8-at-rm32 to 1 if greater or equal (signed), if SF == OF, 0 otherwise (setcc/setge/setnl)");
186 put_new(Name_0f, "93", "set r8/m8-at-rm32 to 1 if greater or equal (unsigned), if CF is unset, 0 otherwise (setcc/setae/setnb)");
187 put_new(Name_0f, "9c", "set r8/m8-at-rm32 to 1 if lesser (signed), if SF != OF, 0 otherwise (setcc/setl/setnge)");
188 put_new(Name_0f, "92", "set r8/m8-at-rm32 to 1 if lesser (unsigned), if CF is set, 0 otherwise (setcc/setb/setnae)");
189 put_new(Name_0f, "9e", "set r8/m8-at-rm32 to 1 if lesser or equal (signed), if ZF is set or SF != OF, 0 otherwise (setcc/setle/setng)");
190 put_new(Name_0f, "96", "set r8/m8-at-rm32 to 1 if lesser or equal (unsigned), if ZF is set or CF is set, 0 otherwise (setcc/setbe/setna)");
191
192 :(before "End Two-Byte Opcodes Starting With 0f")
193 case 0x94: {
194 const uint8_t modrm = next();
195 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
196 uint8_t* dest = effective_byte_address(modrm);
197 *dest = ZF;
198 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
199 break;
200 }
201 case 0x95: {
202 const uint8_t modrm = next();
203 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
204 uint8_t* dest = effective_byte_address(modrm);
205 *dest = !ZF;
206 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
207 break;
208 }
209 case 0x9f: {
210 const uint8_t modrm = next();
211 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
212 uint8_t* dest = effective_byte_address(modrm);
213 *dest = !ZF && SF == OF;
214 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
215 break;
216 }
217 case 0x97: {
218 const uint8_t modrm = next();
219 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
220 uint8_t* dest = effective_byte_address(modrm);
221 *dest = (!CF && !ZF);
222 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
223 break;
224 }
225 case 0x9d: {
226 const uint8_t modrm = next();
227 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
228 uint8_t* dest = effective_byte_address(modrm);
229 *dest = (SF == OF);
230 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
231 break;
232 }
233 case 0x93: {
234 const uint8_t modrm = next();
235 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
236 uint8_t* dest = effective_byte_address(modrm);
237 *dest = !CF;
238 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
239 break;
240 }
241 case 0x9c: {
242 const uint8_t modrm = next();
243 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
244 uint8_t* dest = effective_byte_address(modrm);
245 *dest = (SF != OF);
246 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
247 break;
248 }
249 case 0x92: {
250 const uint8_t modrm = next();
251 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
252 uint8_t* dest = effective_byte_address(modrm);
253 *dest = CF;
254 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
255 break;
256 }
257 case 0x9e: {
258 const uint8_t modrm = next();
259 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
260 uint8_t* dest = effective_byte_address(modrm);
261 *dest = (ZF || SF != OF);
262 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
263 break;
264 }
265 case 0x96: {
266 const uint8_t modrm = next();
267 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end();
268 uint8_t* dest = effective_byte_address(modrm);
269 *dest = (ZF || CF);
270 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end();
271 break;
272 }