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