1 : // Copyright 2012 Google Inc.
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/core/assembler.h"
16 :
17 : #include <limits>
18 :
19 : #include "base/logging.h"
20 :
21 : namespace core {
22 :
23 E : const Register eax(kRegisterEax);
24 E : const Register ecx(kRegisterEcx);
25 E : const Register edx(kRegisterEdx);
26 E : const Register ebx(kRegisterEbx);
27 E : const Register esp(kRegisterEsp);
28 E : const Register ebp(kRegisterEbp);
29 E : const Register esi(kRegisterEsi);
30 E : const Register edi(kRegisterEdi);
31 :
32 : namespace {
33 :
34 : enum Mod {
35 : Reg1Ind = 0, // Register indirect mode.
36 : Reg1ByteDisp = 1, // Register + byte displacement.
37 : Reg1WordDisp = 2, // Register + word displacement.
38 : Reg1 = 3, // Register + word displacement.
39 : };
40 :
41 : // Returns true if @p operand is a displacment only - e.g.
42 : // specifies neither a base, nor an index register.
43 E : bool IsDisplacementOnly(const OperandImpl& operand) {
44 : return operand.displacement().size() != kSizeNone &&
45 : operand.base() == kRegisterNone &&
46 E : operand.index() == kRegisterNone;
47 E : }
48 :
49 : } // namespace
50 :
51 : // No instruction on x86 can exceed 15 bytes, per specs.
52 : const size_t AssemblerImpl::kMaxInstructionLength = 15;
53 :
54 : OperandImpl::OperandImpl(Register base)
55 : : base_(base.code()),
56 : index_(kRegisterNone),
57 E : scale_(kTimes1) {
58 E : }
59 :
60 : OperandImpl::OperandImpl(Register base,
61 : const DisplacementImpl& displacement)
62 : : base_(base.code()),
63 : index_(kRegisterNone),
64 : scale_(kTimes1),
65 E : displacement_(displacement) {
66 : // There must be a base register.
67 E : DCHECK_NE(kRegisterNone, base_);
68 E : }
69 :
70 : OperandImpl::OperandImpl(const DisplacementImpl& displacement)
71 : : base_(kRegisterNone),
72 : index_(kRegisterNone),
73 : scale_(kTimes1),
74 E : displacement_(displacement) {
75 E : DCHECK_NE(kSizeNone, displacement.size());
76 E : }
77 :
78 : OperandImpl::OperandImpl(Register base,
79 : Register index,
80 : ScaleFactor scale,
81 : const DisplacementImpl& displacement)
82 : : base_(base.code()),
83 : index_(index.code()),
84 : scale_(scale),
85 E : displacement_(displacement) {
86 : // ESP cannot be used as an index register.
87 E : DCHECK_NE(kRegisterEsp, index.code());
88 E : DCHECK_NE(kSizeNone, displacement.size());
89 E : }
90 :
91 : OperandImpl::OperandImpl(Register base,
92 : Register index,
93 : ScaleFactor scale)
94 : : base_(base.code()),
95 : index_(index.code()),
96 E : scale_(scale) {
97 : // ESP cannot be used as an index register.
98 E : DCHECK_NE(kRegisterEsp, index.code());
99 E : DCHECK_EQ(kSizeNone, displacement_.size());
100 E : }
101 :
102 : OperandImpl::OperandImpl(Register index,
103 : ScaleFactor scale,
104 : const DisplacementImpl& displacement)
105 : : base_(kRegisterNone),
106 : index_(index.code()),
107 : scale_(scale),
108 E : displacement_(displacement) {
109 : // ESP cannot be used as an index register.
110 E : DCHECK_NE(kRegisterEsp, index.code());
111 E : DCHECK_NE(kSizeNone, displacement.size());
112 E : }
113 :
114 : OperandImpl::OperandImpl(RegisterCode base,
115 : RegisterCode index,
116 : ScaleFactor scale,
117 : const DisplacementImpl& displacement)
118 : : base_(base),
119 : index_(index),
120 : scale_(scale),
121 E : displacement_(displacement) {
122 E : }
123 :
124 : ValueImpl::ValueImpl()
125 E : : value_(0), reference_(NULL), size_(kSizeNone) {
126 E : }
127 :
128 : ValueImpl::ValueImpl(uint32 value, ValueSize size)
129 E : : value_(value), reference_(NULL), size_(size) {
130 E : }
131 :
132 : ValueImpl::ValueImpl(uint32 value,
133 : ValueSize size,
134 : const void* value_ref)
135 E : : value_(value), reference_(value_ref), size_(size) {
136 E : }
137 :
138 : // This class is used to buffer a single instruction during it's creation.
139 : // TODO(siggi): Add a small state machine in debug mode to ensure the
140 : // correct order of invocation to opcode/modrm etc.
141 : class AssemblerImpl::InstructionBuffer {
142 : public:
143 : explicit InstructionBuffer(AssemblerImpl* assm);
144 : ~InstructionBuffer();
145 :
146 : // @name Accessors.
147 : // @{
148 E : size_t len() const { return len_; }
149 E : const uint8* buf() const { return buf_; }
150 E : size_t num_references() const { return num_references_; }
151 E : const size_t *reference_offsets() const { return reference_offsets_; }
152 E : const void*const* references() const { return references_; }
153 : // @}
154 :
155 : // Emit an opcode byte.
156 : void EmitOpCodeByte(uint8 opcode);
157 : // Emit a ModR/M byte, reg_op is either a register or an opcode
158 : // extension, as fits the instruction being generated.
159 : void EmitModRMByte(Mod mod, uint8 reg_op, RegisterCode reg1);
160 : // Emit a SIB byte.
161 : void EmitScaleIndexBaseByte(ScaleFactor scale,
162 : RegisterCode index,
163 : RegisterCode base);
164 : // Emit an operand.
165 : void EmitOperand(uint8 reg_op, const OperandImpl& op);
166 :
167 : // Emit an 8-bit displacement, with optional reference info.
168 : void Emit8BitDisplacement(const DisplacementImpl& disp);
169 :
170 : // Emit a 32-bit displacement with optional reference info.
171 : void Emit32BitDisplacement(const DisplacementImpl& disp);
172 :
173 : // Emit an 8-bit PC-relative value.
174 : void Emit8BitPCRelative(uint32 location, const ValueImpl& disp);
175 :
176 : // Emit a 32-bit PC-relative value.
177 : void Emit32BitPCRelative(uint32 location, const ValueImpl& disp);
178 :
179 : // Emit a 16-bit immediate value.
180 : void Emit16BitValue(uint16 value);
181 :
182 : // Add reference at current location.
183 : void AddReference(const void* reference);
184 :
185 : protected:
186 : void EmitByte(uint8 byte);
187 :
188 : AssemblerImpl* asm_;
189 : size_t num_references_;
190 : const void* (references_)[2];
191 : size_t reference_offsets_[2];
192 : size_t len_;
193 : uint8 buf_[kMaxInstructionLength];
194 : };
195 :
196 : AssemblerImpl::InstructionBuffer::InstructionBuffer(AssemblerImpl* assm)
197 E : : asm_(assm), len_(0), num_references_(0) {
198 E : DCHECK(assm != NULL);
199 : #ifndef NDEBUG
200 : // Initialize the buffer in debug mode for easier debugging.
201 E : ::memset(buf_, 0xCC, sizeof(buf_));
202 : #endif
203 E : }
204 :
205 E : AssemblerImpl::InstructionBuffer::~InstructionBuffer() {
206 E : asm_->Output(*this);
207 E : }
208 :
209 E : void AssemblerImpl::InstructionBuffer::EmitOpCodeByte(uint8 opcode) {
210 E : EmitByte(opcode);
211 E : }
212 :
213 : void AssemblerImpl::InstructionBuffer::EmitModRMByte(
214 E : Mod mod, uint8 reg_op, RegisterCode reg1) {
215 E : DCHECK_LE(reg_op, 8);
216 E : DCHECK_NE(kRegisterNone, reg1);
217 :
218 E : EmitByte((mod << 6) | (reg_op << 3) | reg1);
219 E : }
220 :
221 : void AssemblerImpl::InstructionBuffer::EmitScaleIndexBaseByte(
222 E : ScaleFactor scale, RegisterCode index, RegisterCode base) {
223 E : DCHECK_NE(kRegisterNone, index);
224 E : DCHECK_NE(kRegisterNone, base);
225 :
226 E : EmitByte((scale << 6) | (index << 3) | base);
227 E : }
228 :
229 : void AssemblerImpl::InstructionBuffer::EmitOperand(
230 E : uint8 reg_op, const OperandImpl& op) {
231 E : DCHECK_GE(8, reg_op);
232 :
233 : // The op operand can encode any one of the following things:
234 : // An indirect register access [EAX].
235 : // An indirect 32-bit displacement only [0xDEADBEEF].
236 : // An indirect base register + 32/8-bit displacement [EAX+0xDEADBEEF].
237 : // An indirect base + index register*scale [EAX+ECX*4].
238 : // An indirect base + index register*scale + 32/8-bit displacement
239 : // [EAX+ECX*4+0xDEADBEEF].
240 : // To complicate things, there are certain combinations that can't be encoded
241 : // canonically. The mode [ESP] or [ESP+disp] can never be encoded in a
242 : // ModR/M byte alone, as ESP in the ModR/M byte for any of the indirect modes
243 : // is overloaded to select the SIB representation.
244 : // Likewise [EBP] is overloaded to encode the [disp32] case.
245 : // See e.g. http://ref.x86asm.net/geek32-abc.html#modrm_byte_32 for a nice
246 : // overview table of the ModR/M byte encoding.
247 :
248 : // ESP can never be used as an index register on X86.
249 E : DCHECK_NE(kRegisterEsp, op.index());
250 :
251 : // Is there an index register?
252 E : if (op.index() == kRegisterNone) {
253 E : DCHECK_EQ(kTimes1, op.scale());
254 :
255 : // No index register, is there a base register?
256 E : if (op.base() == kRegisterNone) {
257 : // No base register, this is a displacement only.
258 E : DCHECK_NE(kSizeNone, op.displacement().size());
259 E : DCHECK_EQ(kTimes1, op.scale());
260 :
261 : // The [disp32] mode is encoded by overloading [EBP].
262 E : EmitModRMByte(Reg1Ind, reg_op, kRegisterEbp);
263 E : Emit32BitDisplacement(op.displacement());
264 E : } else {
265 : // Base register only, is it ESP?
266 E : if (op.base() == kRegisterEsp) {
267 : // The [ESP] and [ESP+disp] cases cannot be encoded without a SIB byte.
268 E : if (op.displacement().size() == kSizeNone) {
269 E : EmitModRMByte(Reg1Ind, reg_op, kRegisterEsp);
270 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
271 E : } else if (op.displacement().size() == kSize8Bit) {
272 E : EmitModRMByte(Reg1ByteDisp, reg_op, kRegisterEsp);
273 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
274 E : Emit8BitDisplacement(op.displacement());
275 E : } else {
276 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
277 E : EmitModRMByte(Reg1WordDisp, reg_op, kRegisterEsp);
278 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
279 E : Emit32BitDisplacement(op.displacement());
280 E : }
281 E : } else if (op.displacement().size() == kSizeNone) {
282 E : if (op.base() == kRegisterEbp) {
283 : // The [EBP] case cannot be encoded canonically, there always must
284 : // be a (zero) displacement.
285 E : EmitModRMByte(Reg1ByteDisp, reg_op, op.base());
286 E : Emit8BitDisplacement(DisplacementImpl(0, kSize8Bit, NULL));
287 E : } else {
288 E : EmitModRMByte(Reg1Ind, reg_op, op.base());
289 E : }
290 E : } else if (op.displacement().size() == kSize8Bit) {
291 : // It's [base+disp8], or possibly [EBP].
292 E : EmitModRMByte(Reg1ByteDisp, reg_op, op.base());
293 E : Emit8BitDisplacement(op.displacement());
294 E : } else {
295 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
296 : // It's [base+disp32].
297 E : EmitModRMByte(Reg1WordDisp, reg_op, op.base());
298 E : Emit32BitDisplacement(op.displacement());
299 : }
300 E : }
301 E : } else if (op.base() == kRegisterNone) {
302 : // Index, no base.
303 E : DCHECK_NE(kRegisterNone, op.index());
304 E : DCHECK_EQ(kRegisterNone, op.base());
305 :
306 : // This mode always has a 32 bit displacement.
307 E : EmitModRMByte(Reg1Ind, reg_op, kRegisterEsp);
308 E : EmitScaleIndexBaseByte(op.scale(), op.index(), kRegisterEbp);
309 E : Emit32BitDisplacement(op.displacement());
310 E : } else {
311 : // Index and base case.
312 E : DCHECK_NE(kRegisterNone, op.index());
313 E : DCHECK_NE(kRegisterNone, op.base());
314 :
315 : // Is there a displacement?
316 E : if (op.displacement().size() == kSizeNone) {
317 E : EmitModRMByte(Reg1Ind, reg_op, kRegisterEsp);
318 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
319 E : } else if (op.displacement().size() == kSize8Bit) {
320 E : EmitModRMByte(Reg1ByteDisp, reg_op, kRegisterEsp);
321 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
322 E : Emit8BitDisplacement(op.displacement());
323 E : } else {
324 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
325 E : EmitModRMByte(Reg1WordDisp, reg_op, kRegisterEsp);
326 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
327 E : Emit32BitDisplacement(op.displacement());
328 : }
329 : }
330 E : }
331 :
332 : void AssemblerImpl::InstructionBuffer::Emit8BitDisplacement(
333 E : const DisplacementImpl& disp) {
334 E : DCHECK(disp.size() == kSize8Bit);
335 :
336 E : AddReference(disp.reference());
337 :
338 E : EmitByte(disp.value());
339 E : }
340 :
341 : void AssemblerImpl::InstructionBuffer::Emit32BitDisplacement(
342 E : const DisplacementImpl& disp) {
343 E : AddReference(disp.reference());
344 :
345 E : uint32 value = disp.value();
346 E : EmitByte(value);
347 E : EmitByte(value >> 8);
348 E : EmitByte(value >> 16);
349 E : EmitByte(value >> 24);
350 E : }
351 :
352 : void AssemblerImpl::InstructionBuffer::Emit8BitPCRelative(
353 E : uint32 location, const ValueImpl& value) {
354 E : DCHECK_EQ(kSize8Bit, value.size());
355 :
356 E : AddReference(value.reference());
357 :
358 : // Turn the absolute value into a value relative to the address of
359 : // the end of the emitted constant.
360 E : int32 relative_value = value.value() - (location + len_ + 1);
361 E : DCHECK_LE(std::numeric_limits<int8>::min(), relative_value);
362 E : DCHECK_GE(std::numeric_limits<int8>::max(), relative_value);
363 E : EmitByte(relative_value);
364 E : }
365 :
366 : void AssemblerImpl::InstructionBuffer::Emit32BitPCRelative(
367 E : uint32 location, const ValueImpl& value) {
368 E : DCHECK_EQ(kSize32Bit, value.size());
369 :
370 E : AddReference(value.reference());
371 :
372 : // Turn the absolute value into a value relative to the address of
373 : // the end of the emitted constant.
374 E : uint32 relative_value = value.value() - (location + len_ + 4);
375 E : EmitByte(relative_value);
376 E : EmitByte(relative_value >> 8);
377 E : EmitByte(relative_value >> 16);
378 E : EmitByte(relative_value >> 24);
379 E : }
380 :
381 E : void AssemblerImpl::InstructionBuffer::Emit16BitValue(uint16 value) {
382 E : EmitByte(value);
383 E : EmitByte(value >> 8);
384 E : }
385 :
386 E : void AssemblerImpl::InstructionBuffer::AddReference(const void* reference) {
387 E : if (reference == NULL)
388 E : return;
389 :
390 E : DCHECK_GT(arraysize(references_), num_references_);
391 E : reference_offsets_[num_references_] = len();
392 E : references_[num_references_] = reference;
393 E : ++num_references_;
394 E : }
395 :
396 E : void AssemblerImpl::InstructionBuffer::EmitByte(uint8 byte) {
397 E : DCHECK_GT(sizeof(buf_), len_);
398 E : buf_[len_++] = byte;
399 E : }
400 :
401 : AssemblerImpl::AssemblerImpl(uint32 location, InstructionSerializer* serializer)
402 E : : location_(location), serializer_(serializer) {
403 E : DCHECK(serializer != NULL);
404 E : }
405 :
406 E : void AssemblerImpl::call(const ImmediateImpl& dst) {
407 E : InstructionBuffer instr(this);
408 :
409 E : instr.EmitOpCodeByte(0xE8);
410 E : instr.Emit32BitPCRelative(location_, dst);
411 E : }
412 :
413 E : void AssemblerImpl::call(const OperandImpl& dst) {
414 E : InstructionBuffer instr(this);
415 :
416 E : instr.EmitOpCodeByte(0xFF);
417 E : instr.EmitOperand(0x2, dst);
418 E : }
419 :
420 E : void AssemblerImpl::j(ConditionCode cc, const ImmediateImpl& dst) {
421 E : DCHECK_LE(0, cc);
422 E : DCHECK_GE(15, cc);
423 :
424 E : InstructionBuffer instr(this);
425 E : if (dst.size() == kSize32Bit) {
426 E : instr.EmitOpCodeByte(0x0F);
427 E : instr.EmitOpCodeByte(0x80 | cc);
428 E : instr.Emit32BitPCRelative(location_, dst);
429 E : } else {
430 E : DCHECK_EQ(kSize8Bit, dst.size());
431 E : instr.EmitOpCodeByte(0x70 | cc);
432 E : instr.Emit8BitPCRelative(location_, dst);
433 : }
434 E : }
435 :
436 E : void AssemblerImpl::jecxz(const ImmediateImpl& dst) {
437 E : DCHECK_EQ(kSize8Bit, dst.size());
438 E : InstructionBuffer instr(this);
439 E : instr.EmitOpCodeByte(0xE3);
440 E : instr.Emit8BitPCRelative(location_, dst);
441 E : }
442 :
443 E : void AssemblerImpl::jmp(const ImmediateImpl& dst) {
444 E : DCHECK_EQ(kSize32Bit, dst.size());
445 E : InstructionBuffer instr(this);
446 :
447 E : instr.EmitOpCodeByte(0xE9);
448 E : instr.Emit32BitPCRelative(location_, dst);
449 E : }
450 :
451 E : void AssemblerImpl::jmp(const OperandImpl& dst) {
452 E : InstructionBuffer instr(this);
453 :
454 E : instr.EmitOpCodeByte(0xFF);
455 E : instr.EmitOperand(0x4, dst);
456 E : }
457 :
458 E : void AssemblerImpl::l(LoopCode lc, const ImmediateImpl& dst) {
459 E : DCHECK_EQ(kSize8Bit, dst.size());
460 E : DCHECK_LE(0, lc);
461 E : DCHECK_GE(2, lc);
462 E : InstructionBuffer instr(this);
463 :
464 E : instr.EmitOpCodeByte(0xE0 | lc);
465 E : instr.Emit8BitPCRelative(location_, dst);
466 E : }
467 :
468 E : void AssemblerImpl::ret() {
469 E : InstructionBuffer instr(this);
470 :
471 E : instr.EmitOpCodeByte(0xC3);
472 E : }
473 :
474 E : void AssemblerImpl::ret(uint16 n) {
475 E : InstructionBuffer instr(this);
476 :
477 E : instr.EmitOpCodeByte(0xC2);
478 E : instr.Emit16BitValue(n);
479 E : }
480 :
481 E : void AssemblerImpl::mov_b(const OperandImpl& dst, const ImmediateImpl& src) {
482 E : InstructionBuffer instr(this);
483 :
484 E : instr.EmitOpCodeByte(0xC6);
485 E : instr.EmitOperand(0, dst);
486 E : instr.Emit8BitDisplacement(src);
487 E : }
488 :
489 E : void AssemblerImpl::mov(Register dst, Register src) {
490 E : InstructionBuffer instr(this);
491 :
492 E : instr.EmitOpCodeByte(0x8B);
493 E : instr.EmitModRMByte(Reg1, dst.code(), src.code());
494 E : }
495 :
496 E : void AssemblerImpl::mov(Register dst, const OperandImpl& src) {
497 E : InstructionBuffer instr(this);
498 :
499 E : if (dst.code() == kRegisterEax && IsDisplacementOnly(src)) {
500 : // Special encoding for indirect displacement only to EAX.
501 E : instr.EmitOpCodeByte(0xA1);
502 E : instr.Emit32BitDisplacement(src.displacement());
503 E : } else {
504 E : instr.EmitOpCodeByte(0x8B);
505 E : instr.EmitOperand(dst.code(), src);
506 : }
507 E : }
508 :
509 E : void AssemblerImpl::mov(const OperandImpl& dst, Register src) {
510 E : InstructionBuffer instr(this);
511 :
512 E : if (src.code() == kRegisterEax && IsDisplacementOnly(dst)) {
513 : // Special encoding for indirect displacement only from EAX.
514 E : instr.EmitOpCodeByte(0xA3);
515 E : instr.Emit32BitDisplacement(dst.displacement());
516 E : } else {
517 E : instr.EmitOpCodeByte(0x89);
518 E : instr.EmitOperand(src.code(), dst);
519 : }
520 E : }
521 :
522 E : void AssemblerImpl::mov(Register dst, const ValueImpl& src) {
523 E : DCHECK_NE(kSizeNone, src.size());
524 E : InstructionBuffer instr(this);
525 :
526 E : instr.EmitOpCodeByte(0xB8 | dst.code());
527 E : instr.Emit32BitDisplacement(src);
528 E : }
529 :
530 E : void AssemblerImpl::mov(const OperandImpl& dst, const ImmediateImpl& src) {
531 E : InstructionBuffer instr(this);
532 :
533 E : instr.EmitOpCodeByte(0xC7);
534 E : instr.EmitOperand(0, dst);
535 E : instr.Emit32BitDisplacement(src);
536 E : }
537 :
538 E : void AssemblerImpl::lea(Register dst, const OperandImpl& src) {
539 E : InstructionBuffer instr(this);
540 :
541 E : instr.EmitOpCodeByte(0x8D);
542 E : instr.EmitOperand(dst.code(), src);
543 E : }
544 :
545 E : void AssemblerImpl::push(Register src) {
546 E : InstructionBuffer instr(this);
547 :
548 E : instr.EmitOpCodeByte(0x50 | src.code());
549 E : }
550 :
551 E : void AssemblerImpl::push(const ImmediateImpl& src) {
552 E : DCHECK_EQ(kSize32Bit, src.size());
553 E : InstructionBuffer instr(this);
554 :
555 E : instr.EmitOpCodeByte(0x68);
556 E : instr.Emit32BitDisplacement(src);
557 E : }
558 :
559 E : void AssemblerImpl::push(const OperandImpl& dst) {
560 E : InstructionBuffer instr(this);
561 :
562 E : instr.EmitOpCodeByte(0xFF);
563 E : instr.EmitOperand(0x6, dst);
564 E : }
565 :
566 E : void AssemblerImpl::pop(Register src) {
567 E : InstructionBuffer instr(this);
568 :
569 E : instr.EmitOpCodeByte(0x58 | src.code());
570 E : }
571 :
572 E : void AssemblerImpl::pop(const OperandImpl& dst) {
573 E : InstructionBuffer instr(this);
574 :
575 E : instr.EmitOpCodeByte(0x8F);
576 E : instr.EmitOperand(0, dst);
577 E : }
578 :
579 :
580 E : void AssemblerImpl::Output(const InstructionBuffer& instr) {
581 : serializer_->AppendInstruction(location_,
582 : instr.buf(),
583 : instr.len(),
584 : instr.reference_offsets(),
585 : instr.references(),
586 E : instr.num_references());
587 :
588 E : location_ += instr.len();
589 E : }
590 : } // namespace core
|