1 : // Copyright 2015 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/pe/transforms/pe_hot_patching_basic_block_transform.h"
16 :
17 : #include "syzygy/block_graph/basic_block_assembler.h"
18 :
19 : namespace pe {
20 : namespace transforms {
21 :
22 : const char PEHotPatchingBasicBlockTransform::kTransformName[] =
23 : "PEHotPatchingBasicBlockTransform";
24 :
25 : // This is the size of an x86 jump instruction: 0xEA [32-bit absolute address]
26 : // The padding inserted at the beginning of the blocks must be big enough to
27 : // contain this instruction.
28 : const size_t PEHotPatchingBasicBlockTransform::kLongJumpInstructionLength = 5U;
29 :
30 : namespace {
31 :
32 : using block_graph::BlockGraph;
33 : using block_graph::BasicBlockAssembler;
34 : using block_graph::BasicBlockSubGraph;
35 : typedef BasicBlockSubGraph::BasicBlock BasicBlock;
36 : typedef BasicBlockSubGraph::BasicCodeBlock BasicCodeBlock;
37 :
38 : } // namespace
39 :
40 : bool PEHotPatchingBasicBlockTransform::TransformBasicBlockSubGraph(
41 : const TransformPolicyInterface* policy,
42 : BlockGraph* block_graph,
43 E : BasicBlockSubGraph* basic_block_subgraph) {
44 E : EnsureAtomicallyReplaceableFirstInstruction(basic_block_subgraph);
45 E : EnsurePaddingForJumpBeforeBlock(basic_block_subgraph);
46 E : return true;
47 E : }
48 :
49 : void PEHotPatchingBasicBlockTransform::InsertTwoByteNopAtBlockBeginning(
50 E : BasicCodeBlock* bb) {
51 : // Insert a two-byte NOP at the beginning.
52 E : BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
53 E : assm.nop(2U);
54 E : }
55 :
56 : bool PEHotPatchingBasicBlockTransform::IsAtomicallyReplaceableFirstInstruction(
57 E : BasicCodeBlock* bb) {
58 : // If there are no instructions in the first basic code block it means that
59 : // the block begins with a jump which is either 2 or 5 bytes so therefore
60 : // atomically replaceable.
61 E : if (bb->instructions().size() == 0)
62 E : return true;
63 :
64 : // An at least two-byte aligned and at least two-byte long instruction is
65 : // atomically replaceable.
66 E : return bb->instructions().front().size() >= 2;
67 E : }
68 :
69 : void PEHotPatchingBasicBlockTransform::
70 : EnsureAtomicallyReplaceableFirstInstruction(
71 E : BasicBlockSubGraph* bbsg) {
72 E : DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
73 E : CHECK_EQ(1U, bbsg->block_descriptions().size());
74 :
75 : // Ensure proper alignment for the first instruction. An alignment of 2
76 : // allows to atomically replace the first 2 bytes of a 2-byte or longer
77 : // instruction.
78 E : if (bbsg->block_descriptions().front().alignment < 2)
79 E : bbsg->block_descriptions().front().alignment = 2;
80 :
81 E : BasicCodeBlock* first_bb = GetFirstBasicCodeBlock(bbsg);
82 :
83 E : if (!IsAtomicallyReplaceableFirstInstruction(first_bb))
84 E : InsertTwoByteNopAtBlockBeginning(first_bb);
85 E : }
86 :
87 : void PEHotPatchingBasicBlockTransform::EnsurePaddingForJumpBeforeBlock(
88 E : BasicBlockSubGraph* bbsg) {
89 E : DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
90 :
91 E : CHECK_EQ(1U, bbsg->block_descriptions().size());
92 : BasicBlockSubGraph::BlockDescription& block_description =
93 E : bbsg->block_descriptions().front();
94 :
95 : // If padding_before is not 0, it means that some other task wants to use
96 : // that place for some other purpose.
97 E : CHECK_EQ(0U, block_description.padding_before);
98 :
99 E : block_description.padding_before = kLongJumpInstructionLength;
100 E : }
101 :
102 : BasicCodeBlock* PEHotPatchingBasicBlockTransform::GetFirstBasicCodeBlock(
103 E : BasicBlockSubGraph* bbsg) {
104 E : DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
105 :
106 : // Get the description of the block.
107 E : CHECK_EQ(1U, bbsg->block_descriptions().size());
108 : BasicBlockSubGraph::BlockDescription& block_description =
109 E : bbsg->block_descriptions().front();
110 :
111 : // Get the first basic block.
112 E : CHECK_EQ(false, block_description.basic_block_order.empty());
113 E : BasicBlock* first_block = block_description.basic_block_order.front();
114 :
115 : // Convert to a basic code block.
116 E : BasicCodeBlock* first_code_block = BasicCodeBlock::Cast(first_block);
117 E : CHECK_NE(static_cast<BasicCodeBlock*>(nullptr), first_code_block);
118 E : return first_code_block;
119 E : }
120 :
121 : } // namespace transforms
122 : } // namespace pe
|