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 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 : if (info.reference.referred_type() ==
54 E : BasicBlockReference::REFERRED_TYPE_BLOCK) {
55 E : DCHECK(info.reference.block() != NULL);
56 : return BasicBlockReference(type, size, info.reference.block(),
57 E : info.reference.offset(), info.reference.base());
58 : }
59 :
60 : 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 value) {
73 E : return BasicBlockAssembler::Immediate(value, ValueSizeFromConstant(value));
74 E : }
75 :
76 E : BasicBlockAssembler::Immediate Immediate(uint32 value, ValueSize size) {
77 E : return BasicBlockAssembler::Immediate(value, size);
78 E : }
79 :
80 E : BasicBlockAssembler::Immediate Immediate(BasicBlock* bb) {
81 : return BasicBlockAssembler::Immediate(
82 E : 0, assm::kSize32Bit, UntypedReference(bb));
83 E : }
84 :
85 : BasicBlockAssembler::Immediate Immediate(
86 E : BlockGraph::Block* block, BlockGraph::Offset offset) {
87 : return BasicBlockAssembler::Immediate(
88 E : 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 : return BasicBlockAssembler::Immediate(
95 E : 0, assm::kSize32Bit, UntypedReference(block, offset, base));
96 E : }
97 :
98 : BasicBlockAssembler::Immediate Immediate(
99 E : uint32 value, ValueSize size, const UntypedReference& ref) {
100 E : DCHECK(ref.IsValid());
101 E : return BasicBlockAssembler::Immediate(value, size, ref);
102 E : }
103 :
104 E : BasicBlockAssembler::Displacement Displacement() {
105 E : return BasicBlockAssembler::Displacement();
106 E : }
107 :
108 E : BasicBlockAssembler::Displacement Displacement(uint32 value) {
109 : return BasicBlockAssembler::Displacement(value,
110 E : ValueSizeFromConstant(value));
111 E : }
112 :
113 E : BasicBlockAssembler::Displacement Displacement(uint32 value, ValueSize size) {
114 E : return BasicBlockAssembler::Displacement(value, size);
115 E : }
116 :
117 E : BasicBlockAssembler::Displacement Displacement(BasicBlock* bb) {
118 : return BasicBlockAssembler::Displacement(
119 E : 0, assm::kSize32Bit, UntypedReference(bb));
120 E : }
121 :
122 : BasicBlockAssembler::Displacement Displacement(
123 E : BlockGraph::Block* block, BlockGraph::Offset offset) {
124 : return BasicBlockAssembler::Displacement(
125 E : 0, assm::kSize32Bit, UntypedReference(block, offset, offset));
126 E : }
127 :
128 : BasicBlockAssembler::Displacement Displacement(
129 : BlockGraph::Block* block, BlockGraph::Offset offset,
130 E : BlockGraph::Offset base) {
131 : return BasicBlockAssembler::Displacement(
132 E : 0, assm::kSize32Bit, UntypedReference(block, offset, base));
133 E : }
134 :
135 : BasicBlockAssembler::Displacement Displacement(
136 E : uint32 value, ValueSize size, const UntypedReference& ref) {
137 E : DCHECK(ref.IsValid());
138 E : return BasicBlockAssembler::Displacement(value, size, ref);
139 E : }
140 :
141 E : BasicBlockAssembler::Operand Operand(const assm::Register32& base) {
142 E : return BasicBlockAssembler::Operand(base);
143 E : }
144 :
145 : BasicBlockAssembler::Operand Operand(
146 : const assm::Register32& base,
147 E : const BasicBlockAssembler::Displacement& displ) {
148 E : return BasicBlockAssembler::Operand(base, displ);
149 E : }
150 :
151 : BasicBlockAssembler::Operand Operand(
152 E : const BasicBlockAssembler::Displacement& displ) {
153 E : return BasicBlockAssembler::Operand(displ);
154 E : }
155 :
156 : BasicBlockAssembler::Operand Operand(
157 : const assm::Register32& base, const assm::Register32& index,
158 E : assm::ScaleFactor scale, const BasicBlockAssembler::Displacement& displ) {
159 E : return BasicBlockAssembler::Operand(base, index, scale, displ);
160 E : }
161 :
162 : BasicBlockAssembler::Operand Operand(const assm::Register32& base,
163 : const assm::Register32& index,
164 E : assm::ScaleFactor scale) {
165 E : return BasicBlockAssembler::Operand(base, index, scale);
166 E : }
167 :
168 : BasicBlockAssembler::Operand Operand(
169 : const assm::Register32& index, assm::ScaleFactor scale,
170 E : const BasicBlockAssembler::Displacement& displ) {
171 E : return BasicBlockAssembler::Operand(index, scale, displ);
172 E : }
173 :
174 : BasicBlockAssembler::BasicBlockSerializer::BasicBlockSerializer(
175 : const Instructions::iterator& where, Instructions* list)
176 E : : where_(where), list_(list) {
177 E : DCHECK(list != NULL);
178 E : }
179 :
180 : void BasicBlockAssembler::BasicBlockSerializer::AppendInstruction(
181 : uint32 location, const uint8* bytes, size_t num_bytes,
182 E : const ReferenceInfo* refs, size_t num_refs) {
183 E : Instruction instruction;
184 E : CHECK(Instruction::FromBuffer(bytes, num_bytes, &instruction));
185 E : instruction.set_source_range(source_range_);
186 :
187 E : Instructions::iterator it = list_->insert(where_, instruction);
188 :
189 E : for (size_t i = 0; i < num_refs; ++i) {
190 E : BasicBlockReference bbref = CompleteUntypedReference(refs[i]);
191 E : DCHECK(bbref.IsValid());
192 E : it->SetReference(refs[i].offset, bbref);
193 E : }
194 E : }
195 :
196 : bool BasicBlockAssembler::BasicBlockSerializer::FinalizeLabel(
197 i : uint32 location, const uint8* bytes, size_t num_bytes) {
198 : // No support for labels.
199 i : return false;
200 i : }
201 :
202 : BasicBlockAssembler::BasicBlockAssembler(const Instructions::iterator& where,
203 : Instructions* list)
204 E : : Super(0, &serializer_), serializer_(where, list) {
205 E : }
206 :
207 : BasicBlockAssembler::BasicBlockAssembler(uint32 location,
208 : const Instructions::iterator& where,
209 : Instructions* list)
210 E : : Super(location, &serializer_), serializer_(where, list) {
211 E : }
212 :
213 E : void BasicBlockAssembler::call(const Immediate& dst) {
214 : // In the context of BasicBlockAssembler it only makes sense for calls with
215 : // immediate parameters to be backed by a 32-bit reference.
216 E : DCHECK(dst.reference().IsValid());
217 E : DCHECK_EQ(assm::kSize32Bit, dst.size());
218 E : Super::call(dst);
219 E : }
220 :
221 E : void BasicBlockAssembler::call(const Operand& dst) {
222 E : const UntypedReference& ref = dst.displacement().reference();
223 E : DCHECK(!ref.IsValid() || dst.displacement().size() == assm::kSize32Bit);
224 E : Super::call(dst);
225 E : }
226 :
227 E : void BasicBlockAssembler::jmp(const Immediate& dst) {
228 E : DCHECK(dst.reference().IsValid());
229 E : Super::jmp(dst);
230 E : }
231 :
232 E : void BasicBlockAssembler::jmp(const Operand& dst) {
233 E : const UntypedReference& ref = dst.displacement().reference();
234 E : DCHECK(!ref.IsValid() || dst.displacement().size() == assm::kSize32Bit);
235 E : Super::jmp(dst);
236 E : }
237 :
238 E : void BasicBlockAssembler::j(ConditionCode code, const Immediate& dst) {
239 E : DCHECK(dst.reference().IsValid());
240 E : Super::j(code, dst);
241 E : }
242 :
243 : } // namespace block_graph
|