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