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