1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
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
16 #include "ecmascript/compiler/assembler/x64/assembler_x64.h"
17
18 namespace panda::ecmascript::x64 {
Pushq(Register x)19 void AssemblerX64::Pushq(Register x)
20 {
21 EmitRexPrefix(x);
22 // 0x50: Push r16
23 EmitU8(0x50 | LowBits(x));
24 }
25
Pushq(Immediate x)26 void AssemblerX64::Pushq(Immediate x)
27 {
28 if (InRange8(x.Value())) {
29 // 6A: Push imm8
30 EmitU8(0x6A);
31 EmitI8(static_cast<int8_t>(x.Value()));
32 } else {
33 // 68: Push imm32
34 EmitU8(0x68);
35 EmitI32(x.Value());
36 }
37 }
38
Push(Register x)39 void AssemblerX64::Push(Register x)
40 {
41 Pushq(x);
42 }
43
Popq(Register x)44 void AssemblerX64::Popq(Register x)
45 {
46 EmitRexPrefix(x);
47 // 0x58: Pop r16
48 EmitU8(0x58 | LowBits(x));
49 }
50
Pop(Register x)51 void AssemblerX64::Pop(Register x)
52 {
53 Popq(x);
54 }
55
56
Addq(Immediate src,Register dst)57 void AssemblerX64::Addq(Immediate src, Register dst)
58 {
59 EmitRexPrefixW(dst);
60 if (InRange8(src.Value())) {
61 // 83: Add r/m16, imm8
62 EmitU8(0x83);
63 // 0: 83 /0 ib
64 EmitModrm(0, dst);
65 EmitI8(static_cast<int8_t>(src.Value()));
66 } else if (dst == rax) {
67 // 0x5: Add rax, imm32
68 EmitU8(0x5);
69 EmitI32(src.Value());
70 } else {
71 // 81: Add r/m32, imm32
72 EmitU8(0x81);
73 // 0: 81 /0 id
74 EmitModrm(0, dst);
75 EmitI32(src.Value());
76 }
77 }
78
Addq(Register src,Register dst)79 void AssemblerX64::Addq(Register src, Register dst)
80 {
81 EmitRexPrefix(dst, src);
82 // 03 : add r64, r/m64
83 EmitU8(0x03);
84 EmitModrm(dst, src);
85 }
86
Addl(Immediate src,Register dst)87 void AssemblerX64::Addl(Immediate src, Register dst)
88 {
89 EmitRexPrefix(dst);
90 if (InRange8(src.Value())) {
91 // 83: Add r/m16, imm8
92 EmitU8(0x83);
93 // 0: 83 /0 ib
94 EmitModrm(0, dst);
95 EmitI8(static_cast<int8_t>(src.Value()));
96 } else if (dst == rax) {
97 // 0x5: Add rax, imm32
98 EmitU8(0x5);
99 EmitI32(src.Value());
100 } else {
101 // 81: Add r/m32, imm32
102 EmitU8(0x81);
103 // 0: 81 /0 id
104 EmitModrm(0, dst);
105 EmitI32(src.Value());
106 }
107 }
108
Subq(Immediate src,Register dst)109 void AssemblerX64::Subq(Immediate src, Register dst)
110 {
111 EmitRexPrefixW(dst);
112 if (InRange8(src.Value())) {
113 // 83: Sub r/m16, imm8
114 EmitU8(0x83);
115 // 5: 83 /5 ib
116 EmitModrm(5, dst);
117 EmitI8(static_cast<int8_t>(src.Value()));
118 } else if (dst == rax) {
119 // 0x2D: Sub rax, imm32
120 EmitU8(0x2D);
121 EmitI32(src.Value());
122 } else {
123 // 81: sub r/m32, imm32
124 EmitU8(0x81);
125 // 5: 81 /5 id
126 EmitModrm(5, dst);
127 EmitI32(src.Value());
128 }
129 }
130
Subq(Register src,Register dst)131 void AssemblerX64::Subq(Register src, Register dst)
132 {
133 EmitRexPrefix(src, dst);
134 // 29: sub r/m64, r64
135 EmitU8(0x29);
136 EmitModrm(src, dst);
137 }
138
Subl(Immediate src,Register dst)139 void AssemblerX64::Subl(Immediate src, Register dst)
140 {
141 EmitRexPrefix(dst);
142 if (InRange8(src.Value())) {
143 // 83: Sub r/m16, imm8
144 EmitU8(0x83);
145 // 5: 83 /5 ib
146 EmitModrm(5, dst);
147 EmitI8(static_cast<int8_t>(src.Value()));
148 } else if (dst == rax) {
149 // 0x2D: Sub eax, imm32
150 EmitU8(0x2D);
151 EmitI32(src.Value());
152 } else {
153 // 81: sub r/m32, imm32
154 EmitU8(0x81);
155 // 5: 81 /5 id
156 EmitModrm(5, dst);
157 EmitI32(src.Value());
158 }
159 }
160
Cmpq(Immediate src,Register dst)161 void AssemblerX64::Cmpq(Immediate src, Register dst)
162 {
163 EmitRexPrefixW(dst);
164 if (InRange8(src.Value())) {
165 // 83: cmp r/m64, imm8
166 EmitU8(0x83);
167 // 7: 83 /7 ib
168 EmitModrm(7, dst);
169 EmitI8(static_cast<int8_t>(src.Value()));
170 } else if (dst == rax) {
171 // 0x3D: cmp rax, imm32
172 EmitU8(0x3D);
173 EmitI32(src.Value());
174 } else {
175 // 81: cmp r/m32, imm32
176 EmitU8(0x81);
177 // 7: 81 /7 id
178 EmitModrm(7, dst);
179 EmitI32(src.Value());
180 }
181 }
182
Cmpb(Immediate src,Register dst)183 void AssemblerX64::Cmpb(Immediate src, Register dst)
184 {
185 EmitRexPrefix(dst);
186 if (InRange8(src.Value())) {
187 // 80: cmp r/m8, imm8
188 EmitU8(0x80);
189 // 7: /7 ib
190 EmitModrm(7, dst);
191 EmitI8(static_cast<int8_t>(src.Value()));
192 } else if (dst == rax) {
193 // 0x3C: cmp al, imm8
194 EmitU8(0x3C);
195 EmitI8(src.Value());
196 } else {
197 LOG_ECMA(FATAL) << "this branch is unreachable";
198 UNREACHABLE();
199 }
200 }
201
Cmpq(Register src,Register dst)202 void AssemblerX64::Cmpq(Register src, Register dst)
203 {
204 EmitRexPrefix(src, dst);
205 // 39: Cmp r/m64, r64
206 EmitU8(0x39);
207 EmitModrm(src, dst);
208 }
209
Cmpl(Immediate src,Register dst)210 void AssemblerX64::Cmpl(Immediate src, Register dst)
211 {
212 EmitRexPrefix(dst);
213 if (InRange8(src.Value())) {
214 // 83: cmp r/m32, imm8
215 EmitU8(0x83);
216 // 7: 83 /7 ib
217 EmitModrm(7, dst);
218 EmitI8(static_cast<int8_t>(src.Value()));
219 } else if (dst == rax) {
220 // 0x3D: cmp rax, imm32
221 EmitU8(0x3D);
222 EmitI32(src.Value());
223 } else {
224 // 81: cmp r/m32, imm32
225 EmitU8(0x81);
226 // 7: 81 /7 id
227 EmitModrm(7, dst);
228 EmitI32(src.Value());
229 }
230 }
231
Cmp(Immediate src,Register dst)232 void AssemblerX64::Cmp(Immediate src, Register dst)
233 {
234 Cmpq(src, dst);
235 }
236
Movq(Register src,Register dst)237 void AssemblerX64::Movq(Register src, Register dst)
238 {
239 EmitRexPrefix(src, dst);
240 // 0x89: Move r16 to r/m16
241 EmitU8(0x89);
242 EmitModrm(src, dst);
243 }
244
Mov(Register src,Register dst)245 void AssemblerX64::Mov(Register src, Register dst)
246 {
247 EmitRexPrefixl(dst, src);
248 // 0x89: Move r16 to r/m16
249 EmitU8(0x8B);
250 EmitModrm(dst, src);
251 }
252
Align16()253 void AssemblerX64::Align16()
254 {
255 auto pos = GetCurrentPosition();
256 // 16: align16
257 size_t x = 16;
258 size_t delta = static_cast<size_t>(x - (pos & (x - 1)));
259 for (size_t i = 0; i < delta; i++) {
260 // 0x90: NOP
261 EmitU8(0x90);
262 }
263 }
264
Movq(const Operand & src,Register dst)265 void AssemblerX64::Movq(const Operand &src, Register dst)
266 {
267 EmitRexPrefix(dst, src);
268 // 0x8B: Move r/m64 to r64
269 EmitU8(0x8B);
270 EmitOperand(dst, src);
271 }
272
Movq(Register src,const Operand & dst)273 void AssemblerX64::Movq(Register src, const Operand &dst)
274 {
275 EmitRexPrefix(src, dst);
276 // 0x89: Move r64 to r/m64
277 EmitU8(0x89);
278 EmitOperand(src, dst);
279 }
280
Movq(Immediate src,Operand dst)281 void AssemblerX64::Movq(Immediate src, Operand dst)
282 {
283 EmitRexPrefix(dst);
284 // 0xC7: Move imm32 to r/m32
285 EmitU8(0xC7);
286 // 0: C7 /0 id
287 EmitOperand(0, dst);
288 EmitI32(src.Value());
289 }
290
Movq(Immediate src,Register dst)291 void AssemblerX64::Movq(Immediate src, Register dst)
292 {
293 EmitRexPrefix(dst);
294 // B8 : mov r32, imm32
295 EmitU8(0xB8 | LowBits(dst));
296 EmitI32(src.Value());
297 }
298
Mov(const Operand & src,Register dst)299 void AssemblerX64::Mov(const Operand &src, Register dst)
300 {
301 Movq(src, dst);
302 }
303
EmitJmp(int32_t offset)304 void AssemblerX64::EmitJmp(int32_t offset)
305 {
306 offset--;
307 if (InRange8(offset - sizeof(int8_t))) {
308 // EB: Jmp rel8
309 EmitU8(0xEB);
310 EmitI8(offset - sizeof(int8_t));
311 } else {
312 // E9: Jmp rel32
313 EmitU8(0xE9);
314 EmitI32(offset - sizeof(int32_t));
315 }
316 }
317
EmitJa(int32_t offset)318 void AssemblerX64::EmitJa(int32_t offset)
319 {
320 offset--;
321 if (InRange8(offset - sizeof(int8_t))) {
322 // 77 : Ja rel8
323 EmitU8(0x77);
324 EmitI8(offset - sizeof(int8_t));
325 } else {
326 offset--;
327 // 0F 87 : ja rel32
328 EmitU8(0x0F);
329 EmitU8(0x87);
330 EmitI32(offset - sizeof(int32_t));
331 }
332 }
333
EmitJb(int32_t offset)334 void AssemblerX64::EmitJb(int32_t offset)
335 {
336 offset--;
337 if (InRange8(offset - sizeof(int8_t))) {
338 // 72 : Jb rel8
339 EmitU8(0x72);
340 EmitI8(offset - sizeof(int8_t));
341 } else {
342 offset--;
343 // 0F 82 : Jb rel32
344 EmitU8(0x0F);
345 EmitU8(0x82);
346 EmitI32(offset - sizeof(int32_t));
347 }
348 }
349
EmitJz(int32_t offset)350 void AssemblerX64::EmitJz(int32_t offset)
351 {
352 offset--;
353 if (InRange8(offset - sizeof(int8_t))) {
354 // 74 : Jz rel8
355 EmitU8(0x74);
356 EmitI8(offset - sizeof(int8_t));
357 } else {
358 offset--;
359 // 0F 84 : Jz rel32
360 EmitU8(0x0F);
361 EmitU8(0x84);
362 EmitI32(offset - sizeof(int32_t));
363 }
364 }
365
EmitJne(int32_t offset)366 void AssemblerX64::EmitJne(int32_t offset)
367 {
368 offset--;
369 if (InRange8(offset - sizeof(int8_t))) {
370 // 75 : Jne rel8;
371 EmitU8(0x75);
372 EmitI8(offset - sizeof(int8_t));
373 } else {
374 offset--;
375 // 0F 85 : Jne rel32
376 EmitU8(0x0F);
377 EmitU8(0x85);
378 EmitI32(offset - sizeof(int32_t));
379 }
380 }
381
EmitJbe(int32_t offset)382 void AssemblerX64::EmitJbe(int32_t offset)
383 {
384 offset--;
385 if (InRange8(offset - sizeof(int8_t))) {
386 // 76 : Jbe rel8;
387 EmitU8(0x76);
388 EmitI8(offset - sizeof(int8_t));
389 } else {
390 offset--;
391 // 0F 86 : Jne rel32
392 EmitU8(0x0F);
393 EmitU8(0x86);
394 EmitI32(offset - sizeof(int32_t));
395 }
396 }
397
EmitJnz(int32_t offset)398 void AssemblerX64::EmitJnz(int32_t offset)
399 {
400 offset--;
401 if (InRange8(offset)) {
402 // 75 : Jnz rel8
403 EmitU8(0x75);
404 EmitI8(offset - sizeof(int8_t));
405 } else {
406 offset--;
407 // 0F 85: Jnz rel32
408 EmitU8(0x0F);
409 EmitU8(0x85);
410 EmitI32(offset - sizeof(int32_t));
411 }
412 }
413
EmitJle(int32_t offset)414 void AssemblerX64::EmitJle(int32_t offset)
415 {
416 offset--;
417 if (InRange8(offset)) {
418 // 7E : Jle rel8
419 EmitU8(0x7E);
420 EmitI8(offset - sizeof(int8_t));
421 } else {
422 offset--;
423 // 0F 8E: Jle rel32
424 EmitU8(0x0F);
425 EmitU8(0x8E);
426 EmitI32(offset - sizeof(int32_t));
427 }
428 }
429
EmitJae(int32_t offset)430 void AssemblerX64::EmitJae(int32_t offset)
431 {
432 offset--;
433 if (InRange8(offset)) {
434 // 73 : Jae rel8
435 EmitU8(0x73);
436 EmitI8(offset - sizeof(int8_t));
437 } else {
438 offset--;
439 // 0F 83: Jae rel32
440 EmitU8(0x0F);
441 EmitU8(0x83);
442 EmitI32(offset - sizeof(int32_t));
443 }
444 }
445
EmitJg(int32_t offset)446 void AssemblerX64::EmitJg(int32_t offset)
447 {
448 offset--;
449 if (InRange8(offset)) {
450 // 7F : Jg rel8
451 EmitU8(0x7F);
452 EmitI8(offset - sizeof(int8_t));
453 } else {
454 offset--;
455 // 0F 8F: Jg rel32
456 EmitU8(0x0F);
457 EmitU8(0x8F);
458 EmitI32(offset - sizeof(int32_t));
459 }
460 }
461
EmitJge(int32_t offset)462 void AssemblerX64::EmitJge(int32_t offset)
463 {
464 offset--;
465 if (InRange8(offset)) {
466 // 7D : Jg rel8
467 EmitU8(0x7D);
468 EmitI8(offset - sizeof(int8_t));
469 } else {
470 offset--;
471 // 0F 8F: Jg rel32
472 EmitU8(0x0F);
473 EmitU8(0x8D);
474 EmitI32(offset - sizeof(int32_t));
475 }
476 }
477
EmitJe(int32_t offset)478 void AssemblerX64::EmitJe(int32_t offset)
479 {
480 offset--;
481 if (InRange8(offset)) {
482 // 74 : Je rel8
483 EmitU8(0x74);
484 EmitI8(offset - sizeof(int8_t));
485 } else {
486 offset--;
487 // 0F 84: Je rel32
488 EmitU8(0x0F);
489 EmitU8(0x84);
490 EmitI32(offset - sizeof(int32_t));
491 }
492 }
493
EmitCall(int32_t offset)494 void AssemblerX64::EmitCall(int32_t offset)
495 {
496 offset--;
497 // E8: call rel32
498 EmitU8(0xE8);
499 EmitI32(offset - sizeof(int32_t));
500 }
501
EmitJnb(int32_t offset)502 void AssemblerX64::EmitJnb(int32_t offset)
503 {
504 offset--;
505 if (InRange8(offset)) {
506 // 73 : Jnb rel8
507 EmitU8(0x73);
508 EmitI8(offset - sizeof(int8_t));
509 } else {
510 offset--;
511 // 0F 83: Jnb rel32
512 EmitU8(0x0F);
513 EmitU8(0x83);
514 EmitI32(offset - sizeof(int32_t));
515 }
516 }
517
Callq(Register addr)518 void AssemblerX64::Callq(Register addr)
519 {
520 // C3: RET Near return to calling procedure
521 EmitRexPrefix(addr);
522 // FF: Call r/m16
523 EmitU8(0xFF);
524 // 0x2: FF /2
525 EmitModrm(0x2, addr);
526 }
527
Callq(Label * target)528 void AssemblerX64::Callq(Label *target)
529 {
530 if (target->IsBound()) {
531 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
532 EmitCall(offset);
533 return;
534 }
535
536 auto pos = GetCurrentPosition();
537 int32_t emitPos = 0;
538 if (target->IsLinked()) {
539 emitPos = static_cast<int32_t>(target->GetLinkedPos());
540 }
541 // +1: skip opcode
542 target->LinkTo(pos + 1);
543 // E8: call rel32
544 EmitU8(0xE8);
545 EmitI32(emitPos);
546 }
547
Ret()548 void AssemblerX64::Ret()
549 {
550 // C3: RET Near return to calling procedure
551 EmitU8(0xC3);
552 }
553
Jmp(Label * target,Distance distance)554 void AssemblerX64::Jmp(Label *target, Distance distance)
555 {
556 if (target->IsBound()) {
557 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
558 EmitJmp(offset);
559 return;
560 }
561
562 auto pos = GetCurrentPosition();
563 int32_t emitPos = 0;
564 if (distance == Distance::Near) {
565 if (target->IsLinkedNear()) {
566 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
567 }
568 // +1: skip opcode
569 target->LinkNearPos(pos + 1);
570 ASSERT(InRange8(emitPos));
571 // EB: Jmp rel8
572 EmitU8(0xEB);
573 EmitI8(static_cast<int8_t>(emitPos));
574 } else {
575 if (target->IsLinked()) {
576 emitPos = static_cast<int32_t>(target->GetLinkedPos());
577 }
578 // +1: skip opcode
579 target->LinkTo(pos + 1);
580 // E9: Jmp rel32
581 EmitU8(0xE9);
582 EmitI32(emitPos);
583 }
584 }
585
Jmp(Register dst)586 void AssemblerX64::Jmp(Register dst)
587 {
588 EmitRexPrefix(dst);
589 // opcode FF/4 : jmp r/m64
590 EmitU8(0xFF);
591 // 4 means register
592 EmitModrm(4, dst);
593 }
594
Jmp(Immediate offset)595 void AssemblerX64::Jmp(Immediate offset)
596 {
597 if (InRange8(offset.Value())) {
598 // opcode EB : jmp rel8
599 EmitU8(0xEB);
600 EmitI8(static_cast<int8_t>(offset.Value()));
601 } else {
602 // opcode E9 : jmp rel32
603 EmitU8(0xE9);
604 EmitI32(offset.Value());
605 }
606 }
607
Ja(Label * target,Distance distance)608 void AssemblerX64::Ja(Label *target, Distance distance)
609 {
610 if (target->IsBound()) {
611 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
612 EmitJa(offset);
613 return;
614 }
615 auto pos = GetCurrentPosition();
616 int32_t emitPos = 0;
617 if (distance == Distance::Near) {
618 if (target->IsLinkedNear()) {
619 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
620 }
621 // +1: skip opcode
622 target->LinkNearPos(pos + 1);
623 ASSERT(InRange8(emitPos));
624 // 77: ja rel8
625 EmitU8(0x77);
626 EmitI8(static_cast<int8_t>(emitPos));
627 } else {
628 if (target->IsLinked()) {
629 emitPos = static_cast<int32_t>(target->GetLinkedPos());
630 }
631 // 2: skip opcode
632 target->LinkTo(pos + 2);
633 // 0F 87: ja rel32
634 EmitU8(0X0F);
635 EmitU8(0x87);
636 EmitI32(emitPos);
637 }
638 }
639
Jb(Label * target,Distance distance)640 void AssemblerX64::Jb(Label *target, Distance distance)
641 {
642 if (target->IsBound()) {
643 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
644 EmitJb(offset);
645 return;
646 }
647 auto pos = GetCurrentPosition();
648 int32_t emitPos = 0;
649 if (distance == Distance::Near) {
650 if (target->IsLinkedNear()) {
651 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
652 }
653 // +1: skip opcode
654 target->LinkNearPos(pos + 1);
655 ASSERT(InRange8(emitPos));
656 // 72 : Jb rel8
657 EmitU8(0x72);
658 EmitI8(static_cast<int8_t>(emitPos));
659 } else {
660 if (target->IsLinked()) {
661 emitPos = static_cast<int32_t>(target->GetLinkedPos());
662 }
663 // 2: skip opcode
664 target->LinkTo(pos + 2);
665 // 0F 82: jb rel32
666 EmitU8(0X0F);
667 EmitU8(0x82);
668 EmitI32(emitPos);
669 }
670 }
Jz(Label * target,Distance distance)671 void AssemblerX64::Jz(Label *target, Distance distance)
672 {
673 if (target->IsBound()) {
674 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
675 EmitJz(offset);
676 return;
677 }
678 auto pos = GetCurrentPosition();
679 int32_t emitPos = 0;
680 if (distance == Distance::Near) {
681 if (target->IsLinkedNear()) {
682 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
683 }
684 // +1: skip opcode
685 target->LinkNearPos(pos + 1);
686 ASSERT(InRange8(emitPos));
687 // 74 : Jz rel8
688 EmitU8(0x74);
689 EmitI8(static_cast<int8_t>(emitPos));
690 } else {
691 if (target->IsLinked()) {
692 emitPos = static_cast<int32_t>(target->GetLinkedPos());
693 }
694 // 2: skip opcode
695 target->LinkTo(pos + 2);
696 // 0F 84: Jz rel32
697 EmitU8(0X0F);
698 EmitU8(0x84);
699 EmitI32(emitPos);
700 }
701 }
702
Je(Label * target,Distance distance)703 void AssemblerX64::Je(Label *target, Distance distance)
704 {
705 if (target->IsBound()) {
706 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
707 EmitJe(offset);
708 return;
709 }
710 auto pos = GetCurrentPosition();
711 int32_t emitPos = 0;
712 if (distance == Distance::Near) {
713 if (target->IsLinkedNear()) {
714 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
715 }
716 // +1: skip opcode
717 target->LinkNearPos(pos + 1);
718 ASSERT(InRange8(emitPos));
719 // 74 : Je rel8
720 EmitU8(0x74);
721 EmitI8(static_cast<int8_t>(emitPos));
722 } else {
723 if (target->IsLinked()) {
724 emitPos = static_cast<int32_t>(target->GetLinkedPos());
725 }
726 // 2: skip opcode
727 target->LinkTo(pos + 2);
728 // 0F 84: Je rel32
729 EmitU8(0X0F);
730 EmitU8(0x84);
731 EmitI32(emitPos);
732 }
733 }
734
Bind(Label * target)735 void AssemblerX64::Bind(Label *target)
736 {
737 size_t pos = GetCurrentPosition();
738 ASSERT(!target->IsBound());
739
740 if (target->IsLinked()) {
741 uint32_t linkPos = target->GetLinkedPos();
742 while (linkPos != 0) {
743 uint32_t preLinkPos = GetU32(linkPos);
744 int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int32_t));
745 PutI32(linkPos, disp);
746 linkPos = preLinkPos;
747 }
748 }
749
750 if (target->IsLinkedNear()) {
751 uint32_t linkPos = target->GetLinkedNearPos();
752 while (linkPos != 0) {
753 int8_t offsetToNext = GetI8(static_cast<size_t>(linkPos));
754 int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int8_t));
755 ASSERT(InRange8(disp));
756 PutI8(linkPos, static_cast<int8_t>(disp));
757 if (offsetToNext == 0) {
758 break;
759 }
760 linkPos += static_cast<uint32_t>(offsetToNext);
761 }
762 target->UnlinkNearPos();
763 }
764
765 target->BindTo(pos);
766 }
767
Operand(Register base,int32_t disp)768 Operand::Operand(Register base, int32_t disp)
769 {
770 if (base == rsp || base == r12) {
771 BuildSIB(Times1, rsp, base);
772 }
773 if (disp == 0 && base != rbp && base != r13) {
774 // 0: mode 00 [r/m]
775 BuildModerm(0, base);
776 } else if (AssemblerX64::InRange8(disp)) {
777 // 1: mode 01 [r/m + disp8]
778 BuildModerm(1, base);
779 BuildDisp8(disp);
780 } else {
781 // 2: mode 10 [r/m + disp32]
782 BuildModerm(2, base);
783 BuildDisp32(disp);
784 }
785 }
786
Operand(Register base,Register index,Scale scale,int32_t disp)787 Operand::Operand(Register base, Register index, Scale scale, int32_t disp)
788 {
789 BuildSIB(scale, index, base);
790 if (disp == 0 && base != rbp && base != r13) {
791 // 0: mode 00 [r/m]
792 BuildModerm(0, rsp);
793 } else if (AssemblerX64::InRange8(disp)) {
794 // 1: mode 01 [r/m + disp8]
795 BuildModerm(1, rsp);
796 BuildDisp8(disp);
797 } else {
798 // 2: mode 10 [r/m + disp32]
799 BuildModerm(2, rsp);
800 BuildDisp32(disp);
801 }
802 }
803
804 // [index * scale + disp]
Operand(Register index,Scale scale,int32_t disp)805 Operand::Operand(Register index, Scale scale, int32_t disp)
806 {
807 ASSERT(index != rsp);
808 BuildModerm(0, rsp);
809 BuildSIB(scale, index, rbp);
810 BuildDisp32(disp);
811 }
812
BuildSIB(Scale scale,Register index,Register base)813 void Operand::BuildSIB(Scale scale, Register index, Register base)
814 {
815 sib_ = AssemblerX64::GetSIB(scale, index, base);
816 rex_ |= AssemblerX64::GetSIBRex(index, base);
817 hasSIB_ = true;
818 }
819
BuildModerm(int32_t mode,Register rm)820 void Operand::BuildModerm(int32_t mode, Register rm)
821 {
822 rex_ |= AssemblerX64::GetModrmRex(rm);
823 moderm_ = AssemblerX64::GetModrm(mode, rm);
824 }
825
BuildDisp8(int32_t disp)826 void Operand::BuildDisp8(int32_t disp)
827 {
828 disp_ = disp;
829 hasDisp8_ = true;
830 }
831
BuildDisp32(int32_t disp)832 void Operand::BuildDisp32(int32_t disp)
833 {
834 disp_ = disp;
835 hasDisp32_ = true;
836 }
837
EmitOperand(int32_t reg,Operand rm)838 void AssemblerX64::EmitOperand(int32_t reg, Operand rm)
839 {
840 // moderm
841 EmitU8(rm.moderm_ | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE));
842 if (rm.hasSIB_) {
843 EmitU8(rm.sib_);
844 }
845
846 if (rm.hasDisp8_) {
847 EmitI8(static_cast<int8_t>(rm.disp_));
848 } else if (rm.hasDisp32_) {
849 EmitI32(rm.disp_);
850 }
851 }
852
Movl(Register src,Register dst)853 void AssemblerX64::Movl(Register src, Register dst)
854 {
855 EmitRexPrefixl(src, dst);
856 // 0x89: Move r16 to r/m16
857 EmitU8(0x89);
858 EmitModrm(src, dst);
859 }
860
Movl(const Operand & src,Register dst)861 void AssemblerX64::Movl(const Operand &src, Register dst)
862 {
863 EmitRexPrefixl(dst, src);
864 // 0x8B: Move r/m64 to r64
865 EmitU8(0x8B);
866 EmitOperand(dst, src);
867 }
868
Testq(Immediate src,Register dst)869 void AssemblerX64::Testq(Immediate src, Register dst)
870 {
871 if (InRange8(src.Value())) {
872 Testb(src, dst);
873 } else if (dst == rax) {
874 // A9: Test rax, imm32
875 EmitU8(0xA9);
876 EmitI32(src.Value());
877 } else {
878 EmitRexPrefixW(dst);
879 // F7: Test r/m64, imm32
880 EmitU8(0xF7);
881 // 0: F7 0 id
882 EmitModrm(0, dst);
883 EmitI32(src.Value());
884 }
885 }
886
Testb(Immediate src,Register dst)887 void AssemblerX64::Testb(Immediate src, Register dst)
888 {
889 ASSERT(InRange8(src.Value()));
890 if (dst == rax) {
891 // A8: Test al, imm8
892 EmitU8(0xA8);
893 } else {
894 // AH BH CG DH can not be encoded to access if REX prefix used.
895 if (dst >= rsp) {
896 EmitRexPrefixL(dst);
897 }
898 // F6: Test r/m8, imm8
899 // REX F6: Test r/m8*, imm8
900 EmitU8(0xF6);
901 // 0: F6 /0 ib
902 EmitModrm(0, dst);
903 }
904 EmitI8(static_cast<int8_t>(src.Value()));
905 }
906
Jne(Label * target,Distance distance)907 void AssemblerX64::Jne(Label *target, Distance distance)
908 {
909 if (target->IsBound()) {
910 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
911 EmitJne(offset);
912 return;
913 }
914 auto pos = GetCurrentPosition();
915 int32_t emitPos = 0;
916 if (distance == Distance::Near) {
917 if (target->IsLinkedNear()) {
918 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
919 }
920 // +1: skip opcode
921 target->LinkNearPos(pos + 1);
922 ASSERT(InRange8(emitPos));
923 // 75 : Jne rel8;
924 EmitU8(0x75);
925 EmitI8(static_cast<int8_t>(emitPos));
926 } else {
927 if (target->IsLinked()) {
928 emitPos = static_cast<int32_t>(target->GetLinkedPos());
929 }
930 // 2: skip opcode
931 target->LinkTo(pos + 2);
932 // 0F 85 : Jne rel32
933 EmitU8(0x0F);
934 EmitU8(0x85);
935 EmitI32(emitPos);
936 }
937 }
938
Cmpl(Register src,Register dst)939 void AssemblerX64::Cmpl(Register src, Register dst)
940 {
941 EmitRexPrefixl(src, dst);
942 // 39: Cmp r16 to r/m16
943 EmitU8(0x39);
944 EmitModrm(src, dst);
945 }
946
Jbe(Label * target,Distance distance)947 void AssemblerX64::Jbe(Label *target, Distance distance)
948 {
949 if (target->IsBound()) {
950 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
951 EmitJbe(offset);
952 return;
953 }
954 auto pos = GetCurrentPosition();
955 int32_t emitPos = 0;
956 if (distance == Distance::Near) {
957 if (target->IsLinkedNear()) {
958 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
959 }
960 // +1: skip opcode
961 target->LinkNearPos(pos + 1);
962 ASSERT(InRange8(emitPos));
963 // 76 : Jbe rel8;
964 EmitU8(0x76);
965 EmitI8(static_cast<int8_t>(emitPos));
966 } else {
967 if (target->IsLinked()) {
968 emitPos = static_cast<int32_t>(target->GetLinkedPos());
969 }
970 // 2: skip opcode
971 target->LinkTo(pos + 2);
972 // 0F 86 : Jbe rel32
973 EmitU8(0x0F);
974 EmitU8(0x86);
975 EmitI32(emitPos);
976 }
977 }
978
CMovbe(Register src,Register dst)979 void AssemblerX64::CMovbe(Register src, Register dst)
980 {
981 EmitRexPrefixl(dst, src);
982 // 0f 46: CMovbe r32, r/m32
983 EmitU8(0x0F);
984 EmitU8(0x46);
985 EmitModrm(dst, src);
986 }
987
Leaq(const Operand & src,Register dst)988 void AssemblerX64::Leaq(const Operand &src, Register dst)
989 {
990 EmitRexPrefix(dst, src);
991 // 8D : lea r64, m
992 EmitU8(0x8D);
993 EmitOperand(dst, src);
994 }
995
Leal(const Operand & src,Register dst)996 void AssemblerX64::Leal(const Operand &src, Register dst)
997 {
998 EmitRexPrefixl(dst, src);
999 // 8D : lea r64, m
1000 EmitU8(0x8D);
1001 EmitOperand(dst, src);
1002 }
1003
Shrq(Immediate src,Register dst)1004 void AssemblerX64::Shrq(Immediate src, Register dst)
1005 {
1006 EmitRexPrefixW(dst);
1007 // C1 : Shr r/m64, imm8;
1008 EmitU8(0xc1);
1009 // 5: C1 /5 id
1010 EmitModrm(5, dst);
1011 EmitI8(static_cast<int8_t>(src.Value()));
1012 }
1013
Shr(Immediate src,Register dst)1014 void AssemblerX64::Shr(Immediate src, Register dst)
1015 {
1016 Shrq(src, dst);
1017 }
1018
Andq(Immediate src,Register dst)1019 void AssemblerX64::Andq(Immediate src, Register dst)
1020 {
1021 EmitRexPrefixW(dst);
1022 if (InRange8(src.Value())) {
1023 // 83: and r/m64, imm8
1024 EmitU8(0x83);
1025 // 4: 83 /4 ib
1026 EmitModrm(4, dst);
1027 EmitI8(static_cast<int8_t>(src.Value()));
1028 } else if (dst == rax) {
1029 // 0x25: and rax, imm32
1030 EmitU8(0x25);
1031 EmitI32(src.Value());
1032 } else {
1033 // 81: and r/m64, imm32
1034 EmitU8(0x81);
1035 // 4: 81 /4 id
1036 EmitModrm(4, dst);
1037 EmitI32(src.Value());
1038 }
1039 }
1040
Andl(Immediate src,Register dst)1041 void AssemblerX64::Andl(Immediate src, Register dst)
1042 {
1043 EmitRexPrefix(dst);
1044 if (InRange8(src.Value())) {
1045 // 83: and r/m64, imm8
1046 EmitU8(0x83);
1047 // 4: 83 /4 ib
1048 EmitModrm(4, dst);
1049 EmitI8(static_cast<int8_t>(src.Value()));
1050 } else if (dst == rax) {
1051 // 0x25: and rax, imm32
1052 EmitU8(0x25);
1053 EmitI32(src.Value());
1054 } else {
1055 // 81: and r/m64, imm32
1056 EmitU8(0x81);
1057 // 4: 81 /4 id
1058 EmitModrm(4, dst);
1059 EmitI32(src.Value());
1060 }
1061 }
1062
And(Register src,Register dst)1063 void AssemblerX64::And(Register src, Register dst)
1064 {
1065 EmitRexPrefix(src, dst);
1066 // 21 : And r/m64, r64
1067 EmitU8(0x21);
1068 EmitModrm(src, dst);
1069 }
1070
Or(Immediate src,Register dst)1071 void AssemblerX64::Or(Immediate src, Register dst)
1072 {
1073 EmitRexPrefixW(dst);
1074 if (InRange8(src.Value())) {
1075 // 83: or r/m64, imm8
1076 EmitU8(0x83);
1077 // 1: 83 /1 ib
1078 EmitModrm(1, dst);
1079 EmitI8(static_cast<int8_t>(src.Value()));
1080 } else if (dst == rax) {
1081 // 0x0D: or rax, imm32
1082 EmitU8(0x0D);
1083 EmitI32(src.Value());
1084 } else {
1085 // 81: or r/m64, imm32
1086 EmitU8(0x81);
1087 // 1: 81 /1 id
1088 EmitModrm(1, dst);
1089 EmitI32(src.Value());
1090 }
1091 }
1092
Orq(Register src,Register dst)1093 void AssemblerX64::Orq(Register src, Register dst)
1094 {
1095 EmitRexPrefix(src, dst);
1096 // 09 : Or r/m64, r64
1097 EmitU8(0x09);
1098 EmitModrm(src, dst);
1099 }
1100
Jnz(Label * target,Distance distance)1101 void AssemblerX64::Jnz(Label *target, Distance distance)
1102 {
1103 if (target->IsBound()) {
1104 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1105 EmitJnz(offset);
1106 return;
1107 }
1108 auto pos = GetCurrentPosition();
1109 int32_t emitPos = 0;
1110 if (distance == Distance::Near) {
1111 if (target->IsLinkedNear()) {
1112 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1113 }
1114 // +1: skip opcode
1115 target->LinkNearPos(pos + 1);
1116 ASSERT(InRange8(emitPos));
1117 // 75 : Jnz rel8;
1118 EmitU8(0x75);
1119 EmitI8(static_cast<int8_t>(emitPos));
1120 } else {
1121 if (target->IsLinked()) {
1122 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1123 }
1124 // 2: skip opcode
1125 target->LinkTo(pos + 2);
1126 // 0F 85 : Jnz rel32
1127 EmitU8(0x0F);
1128 EmitU8(0x85);
1129 EmitI32(emitPos);
1130 }
1131 }
1132
Jle(Label * target,Distance distance)1133 void AssemblerX64::Jle(Label *target, Distance distance)
1134 {
1135 if (target->IsBound()) {
1136 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1137 EmitJle(offset);
1138 return;
1139 }
1140 auto pos = GetCurrentPosition();
1141 int32_t emitPos = 0;
1142 if (distance == Distance::Near) {
1143 if (target->IsLinkedNear()) {
1144 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1145 }
1146 // +1: skip opcode
1147 target->LinkNearPos(pos + 1);
1148 ASSERT(InRange8(emitPos));
1149 // 7E : Jle rel8;
1150 EmitU8(0x7E);
1151 EmitI8(static_cast<int8_t>(emitPos));
1152 } else {
1153 if (target->IsLinked()) {
1154 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1155 }
1156 // 2: skip opcode
1157 target->LinkTo(pos + 2);
1158 // 0F 8E: Jle rel32
1159 EmitU8(0x0F);
1160 EmitU8(0x8E);
1161 EmitI32(emitPos);
1162 }
1163 }
1164
Jae(Label * target,Distance distance)1165 void AssemblerX64::Jae(Label *target, Distance distance)
1166 {
1167 if (target->IsBound()) {
1168 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1169 EmitJae(offset);
1170 return;
1171 }
1172 auto pos = GetCurrentPosition();
1173 int32_t emitPos = 0;
1174 if (distance == Distance::Near) {
1175 if (target->IsLinkedNear()) {
1176 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1177 }
1178 // +1: skip opcode
1179 target->LinkNearPos(pos + 1);
1180 ASSERT(InRange8(emitPos));
1181 // 73 : Jae rel8
1182 EmitU8(0x73);
1183 EmitI8(static_cast<int8_t>(emitPos));
1184 } else {
1185 if (target->IsLinked()) {
1186 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1187 }
1188 // 2: skip opcode
1189 target->LinkTo(pos + 2);
1190 // 0F 83: Jae rel32
1191 EmitU8(0x0F);
1192 EmitU8(0x83);
1193 EmitI32(emitPos);
1194 }
1195 }
1196
Jg(Label * target,Distance distance)1197 void AssemblerX64::Jg(Label *target, Distance distance)
1198 {
1199 if (target->IsBound()) {
1200 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1201 EmitJg(offset);
1202 return;
1203 }
1204 auto pos = GetCurrentPosition();
1205 int32_t emitPos = 0;
1206 if (distance == Distance::Near) {
1207 if (target->IsLinkedNear()) {
1208 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1209 }
1210 // +1: skip opcode
1211 target->LinkNearPos(pos + 1);
1212 ASSERT(InRange8(emitPos));
1213 // 7F : Jg rel8
1214 EmitU8(0x7F);
1215 EmitI8(static_cast<int8_t>(emitPos));
1216 } else {
1217 if (target->IsLinked()) {
1218 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1219 }
1220 // 2: skip opcode
1221 target->LinkTo(pos + 2);
1222 // 0F 8F: Jae rel32
1223 EmitU8(0x0F);
1224 EmitU8(0x8F);
1225 EmitI32(emitPos);
1226 }
1227 }
1228
Jge(Label * target,Distance distance)1229 void AssemblerX64::Jge(Label *target, Distance distance)
1230 {
1231 if (target->IsBound()) {
1232 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1233 EmitJge(offset);
1234 return;
1235 }
1236 auto pos = GetCurrentPosition();
1237 int32_t emitPos = 0;
1238 if (distance == Distance::Near) {
1239 if (target->IsLinkedNear()) {
1240 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1241 }
1242 // +1: skip opcode
1243 target->LinkNearPos(pos + 1);
1244 ASSERT(InRange8(emitPos));
1245 // 7F : Jg rel8
1246 EmitU8(0x7D);
1247 EmitI8(static_cast<int8_t>(emitPos));
1248 } else {
1249 if (target->IsLinked()) {
1250 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1251 }
1252 // 2: skip opcode
1253 target->LinkTo(pos + 2);
1254 // 0F 8F: Jae rel32
1255 EmitU8(0x0F);
1256 EmitU8(0x8D);
1257 EmitI32(emitPos);
1258 }
1259 }
1260
Movzbq(const Operand & src,Register dst)1261 void AssemblerX64::Movzbq(const Operand &src, Register dst)
1262 {
1263 EmitRexPrefix(dst, src);
1264 // 0F B6 : Movzx r64, r/m16
1265 EmitU8(0x0F);
1266 EmitU8(0xB6);
1267 // 0F B6 /r: Movzx r64, r/m16
1268 EmitOperand(dst, src);
1269 }
1270
Btq(Immediate src,Register dst)1271 void AssemblerX64::Btq(Immediate src, Register dst)
1272 {
1273 EmitRexPrefixW(dst);
1274 // 0F BA: bt r/m32, imm8;
1275 EmitU8(0x0F);
1276 EmitU8(0xBA);
1277 // /4: 0F BA bt r/m32, imm8
1278 EmitModrm(4, dst);
1279 EmitI8(static_cast<int8_t>(src.Value()));
1280 }
Btl(Immediate src,Register dst)1281 void AssemblerX64::Btl(Immediate src, Register dst)
1282 {
1283 EmitRexPrefix(dst);
1284 // 0F BA: bt r/m32, imm8;
1285 EmitU8(0x0F);
1286 EmitU8(0xBA);
1287 // /4: 0F BA bt r/m32, imm8
1288 EmitModrm(4, dst);
1289 EmitI8(static_cast<int8_t>(src.Value()));
1290 }
1291
Movabs(uint64_t src,Register dst)1292 void AssemblerX64::Movabs(uint64_t src, Register dst)
1293 {
1294 // REX.W + B8 + rd io : Mov r64, imm64
1295 EmitRexPrefixW(dst);
1296 EmitU8(0xB8 | LowBits(dst));
1297 EmitU64(src);
1298 }
1299
Shll(Immediate src,Register dst)1300 void AssemblerX64::Shll(Immediate src, Register dst)
1301 {
1302 EmitRexPrefix(dst);
1303 // C1 : shl r/m32, imm8
1304 EmitU8(0xC1);
1305 // C1 /4
1306 EmitModrm(4, dst);
1307 EmitI8(static_cast<int8_t>(src.Value()));
1308 }
1309
Shlq(Immediate src,Register dst)1310 void AssemblerX64::Shlq(Immediate src, Register dst)
1311 {
1312 EmitRexPrefixW(dst);
1313 // C1 : shl r/m64, imm8
1314 EmitU8(0xC1);
1315 // C1 /4
1316 EmitModrm(4, dst);
1317 EmitI8(static_cast<int8_t>(src.Value()));
1318 }
1319
Int3()1320 void AssemblerX64::Int3()
1321 {
1322 // CC :: INT3
1323 EmitU8(0xCC);
1324 }
1325
Movzwq(const Operand & src,Register dst)1326 void AssemblerX64::Movzwq(const Operand &src, Register dst)
1327 {
1328 EmitRexPrefixW(dst);
1329 EmitU8(0x0F);
1330 EmitU8(0xB7);
1331 EmitOperand(dst, src);
1332 }
1333
Jnb(Label * target,Distance distance)1334 void AssemblerX64::Jnb(Label *target, Distance distance)
1335 {
1336 if (target->IsBound()) {
1337 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1338 EmitJnb(offset);
1339 return;
1340 }
1341 auto pos = GetCurrentPosition();
1342 int32_t emitPos = 0;
1343 if (distance == Distance::Near) {
1344 if (target->IsLinkedNear()) {
1345 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1346 }
1347 // +1: skip opcode
1348 target->LinkNearPos(pos + 1);
1349 ASSERT(InRange8(emitPos));
1350 // 73 : Jnb rel8
1351 EmitU8(0x73);
1352 EmitI8(static_cast<int8_t>(emitPos));
1353 } else {
1354 if (target->IsLinked()) {
1355 emitPos = static_cast<int32_t>(target->GetLinkedPos());
1356 }
1357 // 2: skip opcode
1358 target->LinkTo(pos + 2);
1359 // 0F 83: Jnb rel32
1360 EmitU8(0x0F);
1361 EmitU8(0x83);
1362 EmitI32(emitPos);
1363 }
1364 }
1365 } // panda::ecmascript::x64
1366