1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : #include "syzygy/block_graph/basic_block_assembler.h"
16 :
17 : #include "gtest/gtest.h"
18 : #include "syzygy/block_graph/basic_block_subgraph.h"
19 :
20 : namespace block_graph {
21 :
22 : namespace {
23 :
24 : class BasicBlockAssemblerTest : public testing::Test {
25 : public:
26 : typedef BlockGraph::RelativeAddress RelativeAddress;
27 : typedef BlockGraph::Block::SourceRange SourceRange;
28 :
29 : BasicBlockAssemblerTest();
30 :
31 E : void SetUp() override {}
32 :
33 E : void TearDown() override {}
34 :
35 : protected:
36 : struct Ref {
37 : size_t offset;
38 : BasicBlockReference::ReferredType type;
39 : const void* reference;
40 : };
41 :
42 : template <size_t N>
43 E : void AssertRefs(const Ref(& refs)[N]) {
44 E : ASSERT_EQ(1, instructions_.size());
45 E : const Instruction& instr = instructions_.front();
46 :
47 E : for (size_t i = 0; i < N; ++i) {
48 : BasicBlock::BasicBlockReferenceMap::const_iterator it =
49 E : instr.references().find(refs[i].offset);
50 E : ASSERT_NE(instr.references().end(), it);
51 E : ASSERT_EQ(refs[i].type, it->second.referred_type());
52 E : switch (refs[i].type) {
53 : case BasicBlockReference::REFERRED_TYPE_BLOCK:
54 E : ASSERT_EQ(refs[i].reference, it->second.block());
55 E : break;
56 : case BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK:
57 E : ASSERT_EQ(refs[i].reference, it->second.basic_block());
58 E : break;
59 : default:
60 i : ASSERT_TRUE(false);
61 : }
62 :
63 E : ASSERT_EQ(refs[i].type, it->second.referred_type());
64 E : }
65 :
66 E : instructions_.clear();
67 E : }
68 :
69 E : void AssertNoRefs() {
70 E : ASSERT_EQ(1, instructions_.size());
71 E : ASSERT_EQ(0, instructions_.front().references().size());
72 E : instructions_.clear();
73 E : }
74 :
75 : BlockGraph block_graph_;
76 : BlockGraph::Block* test_block_;
77 : BasicBlockSubGraph subgraph_;
78 : BasicCodeBlock* test_bb_;
79 : BasicBlock::Instructions instructions_;
80 : BasicBlockAssembler asm_;
81 : };
82 :
83 : #define ASSERT_REFS(...) \
84 : do { \
85 : const Ref refs[] = { __VA_ARGS__ }; \
86 : ASSERT_NO_FATAL_FAILURE(AssertRefs(refs)); \
87 : } while (0)
88 :
89 : #define ASSERT_NO_REFS() ASSERT_NO_FATAL_FAILURE(AssertNoRefs())
90 :
91 : BasicBlockAssemblerTest::BasicBlockAssemblerTest()
92 : : test_block_(NULL),
93 : test_bb_(NULL),
94 E : asm_(instructions_.end(), &instructions_) {
95 E : test_block_ = block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 10, "test block");
96 E : test_bb_ = subgraph_.AddBasicCodeBlock("foo");
97 E : }
98 :
99 : } // namespace
100 :
101 E : TEST(UntypedReferenceTest, DefaultConstructor) {
102 E : UntypedReference r;
103 E : EXPECT_EQ(NULL, r.basic_block());
104 E : EXPECT_EQ(NULL, r.block());
105 E : EXPECT_EQ(0, r.offset());
106 E : EXPECT_EQ(0, r.base());
107 E : EXPECT_FALSE(r.IsValid());
108 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN, r.referred_type());
109 E : }
110 :
111 E : TEST(UntypedReferenceTest, BasicBlockReferenceToBasicBlockConstructor) {
112 E : BasicBlockSubGraph subgraph;
113 E : BasicCodeBlock* bcb = subgraph.AddBasicCodeBlock("foo");
114 E : BasicBlock* bb = bcb;
115 E : BasicBlockReference bbref(BlockGraph::ABSOLUTE_REF, 4, bcb);
116 E : UntypedReference r(bbref);
117 E : EXPECT_EQ(bb, r.basic_block());
118 E : EXPECT_EQ(NULL, r.block());
119 E : EXPECT_EQ(0, r.offset());
120 E : EXPECT_EQ(0, r.base());
121 E : EXPECT_TRUE(r.IsValid());
122 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, r.referred_type());
123 E : }
124 :
125 E : TEST(UntypedReferenceTest, BasicBlockReferenceToBlockConstructor) {
126 E : BlockGraph block_graph;
127 : BlockGraph::Block* b =
128 E : block_graph.AddBlock(BlockGraph::CODE_BLOCK, 20, "foo");
129 E : BasicBlockReference bbref(BlockGraph::ABSOLUTE_REF, 4, b, 4, 10);
130 E : UntypedReference r(bbref);
131 E : EXPECT_EQ(NULL, r.basic_block());
132 E : EXPECT_EQ(b, r.block());
133 E : EXPECT_EQ(4, r.offset());
134 E : EXPECT_EQ(10, r.base());
135 E : EXPECT_TRUE(r.IsValid());
136 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK, r.referred_type());
137 E : }
138 :
139 E : TEST(UntypedReferenceTest, BasicBlockConstructor) {
140 E : BasicBlockSubGraph subgraph;
141 E : BasicCodeBlock* bcb = subgraph.AddBasicCodeBlock("foo");
142 E : BasicBlock* bb = bcb;
143 E : UntypedReference r(bcb);
144 E : EXPECT_EQ(bb, r.basic_block());
145 E : EXPECT_EQ(NULL, r.block());
146 E : EXPECT_EQ(0, r.offset());
147 E : EXPECT_EQ(0, r.base());
148 E : EXPECT_TRUE(r.IsValid());
149 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, r.referred_type());
150 E : }
151 :
152 E : TEST(UntypedReferenceTest, BlockConstructor) {
153 E : BlockGraph block_graph;
154 : BlockGraph::Block* b =
155 E : block_graph.AddBlock(BlockGraph::CODE_BLOCK, 0, "dummy");
156 E : UntypedReference r(b, 4, 10);
157 E : EXPECT_EQ(NULL, r.basic_block());
158 E : EXPECT_EQ(b, r.block());
159 E : EXPECT_EQ(4, r.offset());
160 E : EXPECT_EQ(10, r.base());
161 E : EXPECT_TRUE(r.IsValid());
162 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK, r.referred_type());
163 E : }
164 :
165 E : TEST(UntypedReferenceTest, CopyConstructor) {
166 E : BlockGraph block_graph;
167 : BlockGraph::Block* b =
168 E : block_graph.AddBlock(BlockGraph::CODE_BLOCK, 0, "dummy");
169 E : UntypedReference r1(b, 4, 10);
170 :
171 E : UntypedReference r2(r1);
172 E : EXPECT_EQ(r1.basic_block(), r2.basic_block());
173 E : EXPECT_EQ(r1.block(), r2.block());
174 E : EXPECT_EQ(r1.offset(), r2.offset());
175 E : EXPECT_EQ(r1.base(), r2.base());
176 E : EXPECT_EQ(r1.IsValid(), r2.IsValid());
177 E : }
178 :
179 E : TEST(UntypedReferenceTest, Comparison) {
180 E : BlockGraph block_graph;
181 E : BasicBlockSubGraph subgraph;
182 : BlockGraph::Block* b =
183 E : block_graph.AddBlock(BlockGraph::CODE_BLOCK, 0, "dummy");
184 E : UntypedReference r1(b, 4, 10);
185 :
186 E : UntypedReference r2(b, 0, 0);
187 E : EXPECT_FALSE(r1 == r2);
188 :
189 E : BasicCodeBlock* bcb = subgraph.AddBasicCodeBlock("foo");
190 E : UntypedReference r3(bcb);
191 E : EXPECT_FALSE(r1 == r3);
192 E : EXPECT_FALSE(r2 == r3);
193 :
194 E : UntypedReference r4(r1);
195 E : EXPECT_TRUE(r1 == r4);
196 :
197 E : UntypedReference r5(r2);
198 E : EXPECT_TRUE(r2 == r5);
199 E : }
200 :
201 : namespace {
202 :
203 : template <typename ValueTraits>
204 : class ValueTest : public BasicBlockAssemblerTest {
205 : public:
206 : typedef typename ValueTraits ValueTraits;
207 : typedef typename ValueTraits::ValueType ValueType;
208 :
209 : void TestValue(const ValueType& value,
210 : uint32 expected_value,
211 E : assm::ValueSize expected_size) {
212 E : EXPECT_EQ(expected_size, value.size());
213 E : EXPECT_EQ(expected_value, value.value());
214 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
215 E : value.reference().referred_type());
216 :
217 E : auto value_copy(value);
218 E : EXPECT_EQ(expected_size, value_copy.size());
219 E : EXPECT_EQ(expected_value, value_copy.value());
220 E : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
221 E : value_copy.reference().referred_type());
222 :
223 E : EXPECT_TRUE(value == value_copy);
224 :
225 E : auto value_diff(ValueTraits::Factory(expected_value - 1));
226 E : EXPECT_FALSE(value == value_diff);
227 E : }
228 :
229 E : void Test8BitValue(uint32 input_value, uint32 expected_value) {
230 : TestValue(ValueTraits::Factory(input_value),
231 E : expected_value, assm::kSize8Bit);
232 : TestValue(ValueTraits::Factory(input_value, assm::kSize8Bit),
233 E : expected_value, assm::kSize8Bit);
234 E : }
235 :
236 E : void Test32BitValue(uint32 input_value, uint32 expected_value) {
237 : TestValue(ValueTraits::Factory(input_value),
238 E : expected_value, assm::kSize32Bit);
239 : TestValue(ValueTraits::Factory(input_value, assm::kSize32Bit),
240 E : expected_value, assm::kSize32Bit);
241 E : }
242 : };
243 :
244 : struct ImmediateTestTraits {
245 : typedef BasicBlockAssembler::Immediate ValueType;
246 :
247 E : static ValueType Factory() { return Immediate(); }
248 E : static ValueType Factory(uint32 value) { return Immediate(value); }
249 E : static ValueType Factory(uint32 value, assm::ValueSize size) {
250 E : return Immediate(value, size);
251 E : }
252 E : static ValueType Factory(BasicBlock* bb) { return Immediate(bb); }
253 : static ValueType Factory(BlockGraph::Block* block,
254 E : BlockGraph::Offset offset) {
255 E : return Immediate(block, offset);
256 E : }
257 : static ValueType Factory(BlockGraph::Block* block,
258 : BlockGraph::Offset offset,
259 : BlockGraph::Offset base) {
260 : return Immediate(block, offset, base);
261 : }
262 : static ValueType Factory(uint32 value,
263 : ValueSize size,
264 E : const UntypedReference& ref) {
265 E : return Immediate(value, size, ref);
266 E : }
267 : };
268 :
269 : struct DisplacementTestTraits {
270 : typedef BasicBlockAssembler::Displacement ValueType;
271 :
272 E : static ValueType Factory() { return Displacement(); }
273 E : static ValueType Factory(uint32 value) { return Displacement(value); }
274 E : static ValueType Factory(uint32 value, assm::ValueSize size) {
275 E : return Displacement(value, size);
276 E : }
277 E : static ValueType Factory(BasicBlock* bb) { return Displacement(bb); }
278 : static ValueType Factory(BlockGraph::Block* block,
279 E : BlockGraph::Offset offset) {
280 E : return Displacement(block, offset);
281 E : }
282 : static ValueType Factory(BlockGraph::Block* block,
283 : BlockGraph::Offset offset,
284 : BlockGraph::Offset base) {
285 : return Displacement(block, offset, base);
286 : }
287 : static ValueType Factory(uint32 value,
288 : ValueSize size,
289 E : const UntypedReference& ref) {
290 E : return Displacement(value, size, ref);
291 E : }
292 : };
293 :
294 : } // namespace
295 :
296 : typedef ::testing::Types<ImmediateTestTraits, DisplacementTestTraits>
297 : ValueTestTypes;
298 : TYPED_TEST_CASE(ValueTest, ValueTestTypes);
299 :
300 E : TYPED_TEST(ValueTest, Factories) {
301 : {
302 E : auto imm_empty(ValueTraits::Factory());
303 E : ASSERT_EQ(0, imm_empty.value());
304 E : ASSERT_EQ(assm::kSizeNone, imm_empty.size());
305 E : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
306 : imm_empty.reference().referred_type());
307 : }
308 :
309 E : Test8BitValue(0, 0);
310 E : Test8BitValue(127, 127);
311 :
312 E : Test8BitValue(static_cast<uint32>(-128), 0xFFFFFF80);
313 E : Test8BitValue(0, 0);
314 E : Test8BitValue(127, 0x0000007F);
315 :
316 E : Test32BitValue(128, 0x00000080);
317 E : Test32BitValue(0xCAFEBABE, 0xCAFEBABE);
318 :
319 E : Test32BitValue(static_cast<uint32>(-129), 0xFFFFFF7F);
320 E : Test32BitValue(128, 0x000000080);
321 E : Test32BitValue(0xBABE, 0xBABE);
322 :
323 : {
324 E : const BlockGraph::Offset kOffs = 10;
325 E : auto imm_block_ref(ValueTraits::Factory(test_block_, kOffs));
326 :
327 E : ASSERT_EQ(0, imm_block_ref.value());
328 E : ASSERT_EQ(assm::kSize32Bit, imm_block_ref.size());
329 E : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
330 : imm_block_ref.reference().referred_type());
331 E : ASSERT_EQ(test_block_, imm_block_ref.reference().block());
332 E : ASSERT_EQ(kOffs, imm_block_ref.reference().offset());
333 E : ASSERT_EQ(kOffs, imm_block_ref.reference().base());
334 : }
335 :
336 : {
337 E : auto imm_bb_ref(ValueTraits::Factory(test_bb_));
338 :
339 E : ASSERT_EQ(0, imm_bb_ref.value());
340 E : ASSERT_EQ(assm::kSize32Bit, imm_bb_ref.size());
341 E : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK,
342 : imm_bb_ref.reference().referred_type());
343 E : ASSERT_EQ(test_bb_, imm_bb_ref.reference().basic_block());
344 E : ASSERT_EQ(0, imm_bb_ref.reference().offset());
345 E : ASSERT_EQ(0, imm_bb_ref.reference().base());
346 : }
347 :
348 : {
349 : // Explicitly specified size and reference info.
350 E : UntypedReference ref(test_block_, 1, 2);
351 E : auto imm_expl_ref(ValueTraits::Factory(0xBE, assm::kSize8Bit, ref));
352 :
353 E : ASSERT_EQ(0xBE, imm_expl_ref.value());
354 E : ASSERT_EQ(assm::kSize8Bit, imm_expl_ref.size());
355 E : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
356 : imm_expl_ref.reference().referred_type());
357 E : ASSERT_EQ(test_block_, imm_expl_ref.reference().block());
358 E : ASSERT_EQ(1, imm_expl_ref.reference().offset());
359 E : ASSERT_EQ(2, imm_expl_ref.reference().base());
360 : }
361 E : }
362 :
363 : namespace {
364 :
365 : // Asserts that @p op.displacement() is equal to @p displ.
366 : void TestEqualDisplacement(const BasicBlockAssembler::Operand& op,
367 E : const BasicBlockAssembler::Displacement& displ) {
368 E : ASSERT_EQ(displ.value(), op.displacement().value());
369 E : ASSERT_EQ(displ.size(), op.displacement().size());
370 :
371 : ASSERT_EQ(displ.reference().IsValid(),
372 E : op.displacement().reference().IsValid());
373 E : if (!displ.reference().IsValid())
374 E : return;
375 :
376 : ASSERT_EQ(displ.reference().IsValid(),
377 E : op.displacement().reference().IsValid());
378 :
379 : ASSERT_EQ(displ.reference().basic_block(),
380 E : op.displacement().reference().basic_block());
381 : ASSERT_EQ(displ.reference().block(),
382 E : op.displacement().reference().block());
383 : ASSERT_EQ(displ.reference().offset(),
384 E : op.displacement().reference().offset());
385 : ASSERT_EQ(displ.reference().base(),
386 E : op.displacement().reference().base());
387 E : }
388 :
389 : } // namespace
390 :
391 : typedef BasicBlockAssemblerTest OperandTest;
392 :
393 E : TEST_F(OperandTest, Factories) {
394 : {
395 E : auto op(Operand(assm::eax));
396 :
397 E : ASSERT_EQ(assm::kRegisterEax, op.base());
398 E : ASSERT_EQ(assm::kRegisterNone, op.index());
399 E : ASSERT_EQ(assm::kTimes1, op.scale());
400 E : ASSERT_EQ(assm::kSizeNone, op.displacement().size());
401 :
402 E : TestEqualDisplacement(op, Displacement());
403 : }
404 :
405 : {
406 : // Register-indirect with displacement.
407 E : auto op(Operand(assm::eax, Displacement(100)));
408 E : ASSERT_EQ(assm::kRegisterEax, op.base());
409 E : ASSERT_EQ(assm::kRegisterNone, op.index());
410 E : ASSERT_EQ(assm::kTimes1, op.scale());
411 E : ASSERT_EQ(assm::kSize8Bit, op.displacement().size());
412 :
413 E : TestEqualDisplacement(op, Displacement(100));
414 :
415 : TestEqualDisplacement(Operand(assm::eax, Displacement(test_block_, 2)),
416 E : Displacement(test_block_, 2));
417 : TestEqualDisplacement(Operand(assm::eax, Displacement(test_bb_)),
418 E : Displacement(test_bb_));
419 : }
420 :
421 : {
422 : // Displacement-only mode.
423 E : auto op(Operand(Displacement(100)));
424 E : ASSERT_EQ(assm::kRegisterNone, op.base());
425 E : ASSERT_EQ(assm::kRegisterNone, op.index());
426 E : ASSERT_EQ(assm::kTimes1, op.scale());
427 E : ASSERT_EQ(assm::kSize8Bit, op.displacement().size());
428 E : TestEqualDisplacement(op, Displacement(100));
429 :
430 : TestEqualDisplacement(Operand(Displacement(test_block_, 2)),
431 E : Displacement(test_block_, 2));
432 : TestEqualDisplacement(Operand(Displacement(test_bb_)),
433 E : Displacement(test_bb_));
434 : }
435 :
436 : {
437 : // The [base + index * scale] mode with displ.
438 E : auto op(Operand(assm::eax, assm::ebp, assm::kTimes2, Displacement(100)));
439 E : ASSERT_EQ(assm::kRegisterEax, op.base());
440 E : ASSERT_EQ(assm::kRegisterEbp, op.index());
441 E : ASSERT_EQ(assm::kTimes2, op.scale());
442 E : ASSERT_EQ(assm::kSize8Bit, op.displacement().size());
443 :
444 : TestEqualDisplacement(
445 : Operand(assm::eax, assm::ebp, assm::kTimes2,
446 : Displacement(test_block_, 2)),
447 E : Displacement(test_block_, 2));
448 : TestEqualDisplacement(
449 : Operand(assm::eax, assm::ebp, assm::kTimes2, Displacement(test_bb_)),
450 E : Displacement(test_bb_));
451 : }
452 :
453 : {
454 : // The [base + index * scale] mode - no displ.
455 E : auto op(Operand(assm::eax, assm::ebp, assm::kTimes2));
456 E : ASSERT_EQ(assm::kRegisterEax, op.base());
457 E : ASSERT_EQ(assm::kRegisterEbp, op.index());
458 E : ASSERT_EQ(assm::kTimes2, op.scale());
459 E : ASSERT_EQ(assm::kSizeNone, op.displacement().size());
460 :
461 : // The [index * scale + displ32] mode - no base.
462 : TestEqualDisplacement(Operand(assm::eax, assm::ebp, assm::kTimes2),
463 E : Displacement());
464 : }
465 E : }
466 :
467 E : TEST_F(BasicBlockAssemblerTest, nop) {
468 : // We can't use ASSERT_NO_REFS here as nop may generate more than 1
469 : // instruction, an exception to the rule of 1 instruction that ASSERT_NO_REFS
470 : // enforces.
471 E : asm_.nop(0);
472 E : ASSERT_EQ(0u, instructions_.size());
473 :
474 : // Exactly 1 or 2 instructions should be emitted per NOP length from
475 : // 1 to 15.
476 E : for (size_t i = 1; i <= 15; ++i) {
477 E : asm_.nop(i);
478 E : ASSERT_LT(0u, instructions_.size());
479 E : ASSERT_GE(2u, instructions_.size());
480 :
481 : // NOP instructions should have no references.
482 E : for (BasicCodeBlock::Instructions::const_iterator inst_it =
483 : instructions_.begin();
484 E : inst_it != instructions_.end();
485 E : ++inst_it) {
486 E : ASSERT_EQ(0u, inst_it->references().size());
487 E : }
488 E : instructions_.clear();
489 E : }
490 E : }
491 :
492 E : TEST_F(BasicBlockAssemblerTest, call) {
493 E : asm_.call(Immediate(test_block_, 0));
494 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
495 :
496 E : asm_.call(Operand(Displacement(test_bb_)));
497 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
498 E : }
499 :
500 E : TEST_F(BasicBlockAssemblerTest, jmp) {
501 E : asm_.jmp(Immediate(test_block_, 0));
502 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
503 :
504 E : asm_.jmp(Operand(Displacement(test_bb_)));
505 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
506 E : }
507 :
508 E : TEST_F(BasicBlockAssemblerTest, mov_b) {
509 : // mov BYTE PTR [base + index * scale + displ], immediate
510 : asm_.mov_b(Operand(assm::eax, assm::ebx, assm::kTimes4,
511 : Displacement(test_block_, 0)),
512 E : Immediate(10));
513 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
514 E : }
515 :
516 E : TEST_F(BasicBlockAssemblerTest, movzx_b) {
517 : // movzx eax, BYTE PTR [base + index * scale + displ]
518 : asm_.movzx_b(assm::eax,
519 : Operand(assm::eax, assm::ebx, assm::kTimes4,
520 E : Displacement(test_block_, 0)));
521 E : ASSERT_REFS(4, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
522 E : }
523 :
524 E : TEST_F(BasicBlockAssemblerTest, mov) {
525 : // Simple register-register move.
526 E : asm_.mov(assm::eax, assm::ebx);
527 E : ASSERT_NO_REFS();
528 :
529 : // Simple immediate-register move.
530 E : asm_.mov(assm::eax, Immediate(10));
531 E : ASSERT_NO_REFS();
532 :
533 : // Immediate-with reference to register.
534 E : asm_.mov(assm::eax, Immediate(test_block_, 0));
535 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
536 :
537 : // Torture test; mov [displ], immediate,
538 : // both src and dst contain references.
539 E : asm_.mov(Operand(Displacement(test_block_, 0)), Immediate(test_bb_));
540 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
541 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
542 :
543 : // Torture test; mov [base + index * scale + displ], immediate,
544 : // both src and dst contain references.
545 : asm_.mov(Operand(assm::eax, assm::ebx, assm::kTimes4,
546 : Displacement(test_block_, 0)),
547 E : Immediate(test_bb_));
548 : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
549 E : 7, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
550 E : }
551 :
552 E : TEST_F(BasicBlockAssemblerTest, mov_fs) {
553 : asm_.mov_fs(Operand(assm::eax, assm::ebx, assm::kTimes4,
554 : Displacement(test_block_, 0)),
555 E : assm::eax);
556 E : ASSERT_REFS(4, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
557 :
558 : asm_.mov_fs(assm::eax,
559 : Operand(assm::eax, assm::ebx, assm::kTimes4,
560 E : Displacement(test_block_, 0)));
561 E : ASSERT_REFS(4, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
562 E : }
563 :
564 E : TEST_F(BasicBlockAssemblerTest, lea) {
565 E : asm_.lea(assm::eax, Operand(assm::eax));
566 E : ASSERT_NO_REFS();
567 :
568 : asm_.lea(assm::eax,
569 : Operand(assm::eax, assm::ebx, assm::kTimes4,
570 E : Displacement(test_bb_)));
571 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
572 E : }
573 :
574 E : TEST_F(BasicBlockAssemblerTest, push) {
575 E : asm_.push(assm::esp);
576 E : ASSERT_NO_REFS();
577 :
578 E : asm_.push(Immediate(test_block_, 0));
579 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
580 :
581 : asm_.push(Operand(assm::eax, assm::ebx, assm::kTimes4,
582 E : Displacement(test_bb_)));
583 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
584 E : }
585 :
586 E : TEST_F(BasicBlockAssemblerTest, pop) {
587 E : asm_.pop(assm::ebp);
588 E : ASSERT_NO_REFS();
589 :
590 : asm_.pop(Operand(assm::eax, assm::ebx, assm::kTimes4,
591 E : Displacement(test_bb_)));
592 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
593 E : }
594 :
595 E : TEST_F(BasicBlockAssemblerTest, pushfd) {
596 E : asm_.pushfd();
597 E : ASSERT_NO_REFS();
598 E : }
599 :
600 E : TEST_F(BasicBlockAssemblerTest, popfd) {
601 E : asm_.popfd();
602 E : ASSERT_NO_REFS();
603 E : }
604 :
605 E : TEST_F(BasicBlockAssemblerTest, lahf) {
606 E : asm_.lahf();
607 E : ASSERT_NO_REFS();
608 E : }
609 :
610 E : TEST_F(BasicBlockAssemblerTest, sahf) {
611 E : asm_.sahf();
612 E : ASSERT_NO_REFS();
613 E : }
614 :
615 E : TEST_F(BasicBlockAssemblerTest, setxx) {
616 : // Simple register-register operation.
617 E : asm_.set(assm::kParityEven, assm::eax);
618 E : ASSERT_NO_REFS();
619 :
620 E : asm_.set(assm::kOverflow, assm::ebx);
621 E : ASSERT_NO_REFS();
622 E : }
623 :
624 E : TEST_F(BasicBlockAssemblerTest, test) {
625 : // Simple register-register operation.
626 E : asm_.test(assm::al, assm::bl);
627 E : ASSERT_NO_REFS();
628 :
629 : // Simple immediate-register operation.
630 E : asm_.test(assm::al, Immediate(10, assm::kSize8Bit));
631 E : ASSERT_NO_REFS();
632 :
633 : // Simple register-register operation.
634 E : asm_.test(assm::eax, assm::ebx);
635 E : ASSERT_NO_REFS();
636 :
637 : // Simple immediate-register operation.
638 E : asm_.test(assm::eax, Immediate(10));
639 E : ASSERT_NO_REFS();
640 :
641 : // Immediate-with reference to register.
642 E : asm_.test(assm::eax, Immediate(test_block_, 0));
643 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
644 :
645 : // Torture test: both src and dst contain references.
646 E : asm_.test(Operand(Displacement(test_block_, 0)), Immediate(test_bb_));
647 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
648 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
649 :
650 E : asm_.test(Operand(Displacement(test_block_, 0)), Immediate(10));
651 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
652 E : }
653 :
654 E : TEST_F(BasicBlockAssemblerTest, cmp) {
655 : // Simple register-register operation.
656 E : asm_.cmp(assm::al, assm::bl);
657 E : ASSERT_NO_REFS();
658 :
659 : // Simple immediate-register operation.
660 E : asm_.cmp(assm::al, Immediate(10, assm::kSize8Bit));
661 E : ASSERT_NO_REFS();
662 :
663 : // Simple register-register operation.
664 E : asm_.cmp(assm::eax, assm::ebx);
665 E : ASSERT_NO_REFS();
666 :
667 : // Simple immediate-register operation.
668 E : asm_.cmp(assm::eax, Immediate(10));
669 E : ASSERT_NO_REFS();
670 :
671 : // Immediate-with reference to register.
672 E : asm_.cmp(assm::eax, Immediate(test_block_, 0));
673 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
674 :
675 : // Torture test: both src and dst contain references.
676 E : asm_.cmp(Operand(Displacement(test_block_, 0)), Immediate(test_bb_));
677 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
678 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
679 :
680 E : asm_.cmp(Operand(Displacement(test_block_, 0)), Immediate(10));
681 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
682 E : }
683 :
684 E : TEST_F(BasicBlockAssemblerTest, add) {
685 : // Simple register-register operation.
686 E : asm_.add(assm::al, assm::bl);
687 E : ASSERT_NO_REFS();
688 :
689 : // Simple immediate-register operation.
690 E : asm_.add(assm::al, Immediate(10, assm::kSize8Bit));
691 E : ASSERT_NO_REFS();
692 :
693 : // Simple register-register operation.
694 E : asm_.add(assm::eax, assm::ebx);
695 E : ASSERT_NO_REFS();
696 :
697 : // Simple immediate-register operation.
698 E : asm_.add(assm::eax, Immediate(10));
699 E : ASSERT_NO_REFS();
700 :
701 : // Immediate-with reference to register.
702 E : asm_.add(assm::eax, Immediate(test_block_, 0));
703 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
704 :
705 : // Torture test: both src and dst contain references.
706 E : asm_.add(Operand(Displacement(test_block_, 0)), Immediate(test_bb_));
707 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
708 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
709 :
710 E : asm_.add(Operand(Displacement(test_block_, 0)), Immediate(10));
711 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
712 E : }
713 :
714 E : TEST_F(BasicBlockAssemblerTest, sub) {
715 : // Simple register-register operation.
716 E : asm_.sub(assm::al, assm::bl);
717 E : ASSERT_NO_REFS();
718 :
719 : // Simple immediate-register operation.
720 E : asm_.sub(assm::al, Immediate(10, assm::kSize8Bit));
721 E : ASSERT_NO_REFS();
722 :
723 : // Simple register-register operation.
724 E : asm_.sub(assm::eax, assm::ebx);
725 E : ASSERT_NO_REFS();
726 :
727 : // Simple immediate-register operation.
728 E : asm_.sub(assm::eax, Immediate(10));
729 E : ASSERT_NO_REFS();
730 :
731 : // Immediate-with reference to register.
732 E : asm_.sub(assm::eax, Immediate(test_block_, 0));
733 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
734 :
735 : // Torture test: both src and dst contain references.
736 E : asm_.sub(Operand(Displacement(test_block_, 0)), Immediate(test_bb_));
737 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_,
738 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, test_bb_);
739 :
740 E : asm_.sub(Operand(Displacement(test_block_, 0)), Immediate(10));
741 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, test_block_);
742 E : }
743 :
744 E : TEST_F(BasicBlockAssemblerTest, shl) {
745 : // Simple immediate-register operation.
746 E : asm_.shl(assm::eax, Immediate(1));
747 E : ASSERT_NO_REFS();
748 E : }
749 :
750 E : TEST_F(BasicBlockAssemblerTest, shr) {
751 : // Simple immediate-register operation.
752 E : asm_.shr(assm::eax, Immediate(1));
753 E : ASSERT_NO_REFS();
754 E : }
755 :
756 E : TEST_F(BasicBlockAssemblerTest, ret) {
757 E : asm_.ret();
758 E : ASSERT_NO_REFS();
759 :
760 E : asm_.ret(4);
761 E : ASSERT_NO_REFS();
762 E : }
763 :
764 E : TEST_F(BasicBlockAssemblerTest, xchg) {
765 E : asm_.xchg(assm::eax, assm::ecx);
766 E : ASSERT_NO_REFS();
767 :
768 E : asm_.xchg(assm::esp, assm::edx);
769 E : ASSERT_NO_REFS();
770 :
771 E : asm_.xchg(assm::ax, assm::cx);
772 E : ASSERT_NO_REFS();
773 :
774 E : asm_.xchg(assm::sp, assm::dx);
775 E : ASSERT_NO_REFS();
776 :
777 E : asm_.xchg(assm::al, assm::ch);
778 E : ASSERT_NO_REFS();
779 :
780 E : asm_.xchg(assm::dh, assm::bl);
781 E : ASSERT_NO_REFS();
782 E : }
783 :
784 E : TEST_F(BasicBlockAssemblerTest, UndefinedSourceRange) {
785 E : ASSERT_EQ(asm_.source_range(), SourceRange());
786 E : asm_.call(Immediate(test_block_, 0));
787 E : ASSERT_EQ(instructions_.back().source_range(), SourceRange());
788 E : }
789 :
790 E : TEST_F(BasicBlockAssemblerTest, SetSourceRange) {
791 E : SourceRange range(RelativeAddress(10), 10);
792 E : asm_.set_source_range(range);
793 E : asm_.call(Immediate(test_block_, 0));
794 E : ASSERT_EQ(instructions_.back().source_range(), range);
795 E : }
796 :
797 E : TEST_F(BasicBlockAssemblerTest, SetMultipleSourceRange) {
798 E : SourceRange range1(RelativeAddress(10), 10);
799 E : SourceRange range2(RelativeAddress(20), 20);
800 :
801 E : asm_.set_source_range(range1);
802 E : asm_.call(Immediate(test_block_, 0));
803 E : ASSERT_EQ(instructions_.back().source_range(), range1);
804 :
805 E : asm_.set_source_range(range2);
806 E : asm_.pop(assm::ebp);
807 E : ASSERT_EQ(instructions_.back().source_range(), range2);
808 :
809 E : asm_.ret(4);
810 E : ASSERT_EQ(instructions_.back().source_range(), range2);
811 E : }
812 :
813 : } // namespace block_graph
|