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 : namespace block_graph {
18 :
19 : namespace {
20 :
21 E : ValueSize ValueSizeFromConstant(uint32_t input_value) {
22 : // IA32 assembly may/will sign-extend 8-bit literals, so we attempt to encode
23 : // in 8 bits only those literals whose value will be unchanged by that
24 : // treatment.
25 E : input_value |= 0x7F;
26 :
27 E : if (input_value == 0xFFFFFFFF || input_value == 0x7F)
28 E : return assm::kSize8Bit;
29 :
30 E : return assm::kSize32Bit;
31 E : }
32 :
33 E : size_t ToBytes(assm::ReferenceSize size) {
34 E : switch (size) {
35 E : case assm::kSize8Bit: return 1;
36 E : case assm::kSize32Bit: return 4;
37 : }
38 i : NOTREACHED();
39 i : return 0;
40 E : }
41 :
42 : // Completes a UntypedReference, converting it to a BasicBlockReference
43 : // using the associated type and size information.
44 : BasicBlockReference CompleteUntypedReference(
45 E : const BasicBlockAssembler::ReferenceInfo& info) {
46 E : DCHECK(info.reference.IsValid());
47 :
48 E : size_t size = ToBytes(info.size);
49 E : BlockGraph::ReferenceType type = BlockGraph::ABSOLUTE_REF;
50 E : if (info.pc_relative)
51 E : type = BlockGraph::PC_RELATIVE_REF;
52 :
53 E : if (info.reference.referred_type() ==
54 : BasicBlockReference::REFERRED_TYPE_BLOCK) {
55 E : DCHECK(info.reference.block() != NULL);
56 E : return BasicBlockReference(type, size, info.reference.block(),
57 : info.reference.offset(), info.reference.base());
58 : }
59 :
60 E : DCHECK_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK,
61 E : info.reference.referred_type());
62 E : DCHECK(info.reference.basic_block() != NULL);
63 E : return BasicBlockReference(type, size, info.reference.basic_block());
64 E : }
65 :
66 : } // namespace
67 :
68 E : BasicBlockAssembler::Immediate Immediate() {
69 E : return BasicBlockAssembler::Immediate();
70 E : }
71 :
72 E : BasicBlockAssembler::Immediate Immediate(uint32_t value) {
73 E : return BasicBlockAssembler::Immediate(value, ValueSizeFromConstant(value));
74 E : }
75 :
76 E : BasicBlockAssembler::Immediate Immediate(uint32_t value, ValueSize size) {
77 E : return BasicBlockAssembler::Immediate(value, size);
78 E : }
79 :
80 E : BasicBlockAssembler::Immediate Immediate(BasicBlock* bb) {
81 E : return BasicBlockAssembler::Immediate(
82 : 0, assm::kSize32Bit, UntypedReference(bb));
83 E : }
84 :
85 : BasicBlockAssembler::Immediate Immediate(
86 E : BlockGraph::Block* block, BlockGraph::Offset offset) {
87 E : return BasicBlockAssembler::Immediate(
88 : 0, assm::kSize32Bit, UntypedReference(block, offset, offset));
89 E : }
90 :
91 : BasicBlockAssembler::Immediate Immediate(BlockGraph::Block* block,
92 : BlockGraph::Offset offset,
93 E : BlockGraph::Offset base) {
94 E : return BasicBlockAssembler::Immediate(
95 : 0, assm::kSize32Bit, UntypedReference(block, offset, base));
96 E : }
97 :
98 : BasicBlockAssembler::Immediate Immediate(uint32_t value,
99 : ValueSize size,
100 E : const UntypedReference& ref) {
101 E : DCHECK(ref.IsValid());
102 E : return BasicBlockAssembler::Immediate(value, size, ref);
103 E : }
104 :
105 E : BasicBlockAssembler::Displacement Displacement() {
106 E : return BasicBlockAssembler::Displacement();
107 E : }
108 :
109 E : BasicBlockAssembler::Displacement Displacement(uint32_t value) {
110 E : return BasicBlockAssembler::Displacement(value,
111 : ValueSizeFromConstant(value));
112 E : }
113 :
114 E : BasicBlockAssembler::Displacement Displacement(uint32_t value, ValueSize size) {
115 E : return BasicBlockAssembler::Displacement(value, size);
116 E : }
117 :
118 E : BasicBlockAssembler::Displacement Displacement(BasicBlock* bb) {
119 E : return BasicBlockAssembler::Displacement(
120 : 0, assm::kSize32Bit, UntypedReference(bb));
121 E : }
122 :
123 : BasicBlockAssembler::Displacement Displacement(
124 E : BlockGraph::Block* block, BlockGraph::Offset offset) {
125 E : return BasicBlockAssembler::Displacement(
126 : 0, assm::kSize32Bit, UntypedReference(block, offset, offset));
127 E : }
128 :
129 : BasicBlockAssembler::Displacement Displacement(
130 : BlockGraph::Block* block, BlockGraph::Offset offset,
131 E : BlockGraph::Offset base) {
132 E : return BasicBlockAssembler::Displacement(
133 : 0, assm::kSize32Bit, UntypedReference(block, offset, base));
134 E : }
135 :
136 : BasicBlockAssembler::Displacement Displacement(uint32_t value,
137 : ValueSize size,
138 E : const UntypedReference& ref) {
139 E : DCHECK(ref.IsValid());
140 E : return BasicBlockAssembler::Displacement(value, size, ref);
141 E : }
142 :
143 E : BasicBlockAssembler::Operand Operand(const assm::Register32& base) {
144 E : return BasicBlockAssembler::Operand(base);
145 E : }
146 :
147 : BasicBlockAssembler::Operand Operand(
148 : const assm::Register32& base,
149 E : const BasicBlockAssembler::Displacement& displ) {
150 E : return BasicBlockAssembler::Operand(base, displ);
151 E : }
152 :
153 : BasicBlockAssembler::Operand Operand(
154 E : const BasicBlockAssembler::Displacement& displ) {
155 E : return BasicBlockAssembler::Operand(displ);
156 E : }
157 :
158 : BasicBlockAssembler::Operand Operand(
159 : const assm::Register32& base, const assm::Register32& index,
160 E : assm::ScaleFactor scale, const BasicBlockAssembler::Displacement& displ) {
161 E : return BasicBlockAssembler::Operand(base, index, scale, displ);
162 E : }
163 :
164 : BasicBlockAssembler::Operand Operand(const assm::Register32& base,
165 : const assm::Register32& index,
166 E : assm::ScaleFactor scale) {
167 E : return BasicBlockAssembler::Operand(base, index, scale);
168 E : }
169 :
170 : BasicBlockAssembler::Operand Operand(
171 : const assm::Register32& index, assm::ScaleFactor scale,
172 E : const BasicBlockAssembler::Displacement& displ) {
173 E : return BasicBlockAssembler::Operand(index, scale, displ);
174 E : }
175 :
176 : BasicBlockAssembler::BasicBlockSerializer::BasicBlockSerializer(
177 : const Instructions::iterator& where, Instructions* list)
178 E : : where_(where), list_(list) {
179 E : DCHECK(list != NULL);
180 E : }
181 :
182 : void BasicBlockAssembler::BasicBlockSerializer::AppendInstruction(
183 : uint32_t location,
184 : const uint8_t* bytes,
185 : uint32_t num_bytes,
186 : const ReferenceInfo* refs,
187 E : size_t num_refs) {
188 E : Instruction instruction;
189 E : CHECK(Instruction::FromBuffer(bytes, num_bytes, &instruction));
190 E : instruction.set_source_range(source_range_);
191 :
192 E : Instructions::iterator it = list_->insert(where_, instruction);
193 :
194 E : for (size_t i = 0; i < num_refs; ++i) {
195 E : BasicBlockReference bbref = CompleteUntypedReference(refs[i]);
196 E : DCHECK(bbref.IsValid());
197 E : it->SetReference(refs[i].offset, bbref);
198 E : }
199 E : }
200 :
201 : bool BasicBlockAssembler::BasicBlockSerializer::FinalizeLabel(
202 : uint32_t location,
203 : const uint8_t* bytes,
204 i : size_t num_bytes) {
205 : // No support for labels.
206 i : return false;
207 i : }
208 :
209 : BasicBlockAssembler::BasicBlockAssembler(const Instructions::iterator& where,
210 : Instructions* list)
211 E : : Super(0, &serializer_), serializer_(where, list) {
212 E : }
213 :
214 : BasicBlockAssembler::BasicBlockAssembler(uint32_t location,
215 : const Instructions::iterator& where,
216 : Instructions* list)
217 E : : Super(location, &serializer_), serializer_(where, list) {
218 E : }
219 :
220 E : void BasicBlockAssembler::call(const Immediate& dst) {
221 : // In the context of BasicBlockAssembler it only makes sense for calls with
222 : // immediate parameters to be backed by a 32-bit reference.
223 E : DCHECK(dst.reference().IsValid());
224 E : DCHECK_EQ(assm::kSize32Bit, dst.size());
225 E : Super::call(dst);
226 E : }
227 :
228 E : void BasicBlockAssembler::call(const Operand& dst) {
229 E : const UntypedReference& ref = dst.displacement().reference();
230 E : DCHECK(!ref.IsValid() || dst.displacement().size() == assm::kSize32Bit);
231 E : Super::call(dst);
232 E : }
233 :
234 E : void BasicBlockAssembler::jmp(const Immediate& dst) {
235 E : DCHECK(dst.reference().IsValid());
236 E : Super::jmp(dst);
237 E : }
238 :
239 E : void BasicBlockAssembler::jmp(const Operand& dst) {
240 E : const UntypedReference& ref = dst.displacement().reference();
241 E : DCHECK(!ref.IsValid() || dst.displacement().size() == assm::kSize32Bit);
242 E : Super::jmp(dst);
243 E : }
244 :
245 E : void BasicBlockAssembler::j(ConditionCode code, const Immediate& dst) {
246 E : DCHECK(dst.reference().IsValid());
247 E : Super::j(code, dst);
248 E : }
249 :
250 : } // namespace block_graph
|