• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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