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 18namespace panda::ecmascript::x64 { 19void AssemblerX64::Pushq(Register x) 20{ 21 EmitRexPrefix(x); 22 // 0x50: Push r16 23 EmitU8(0x50 | LowBits(x)); 24} 25 26void 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 39void AssemblerX64::Push(Register x) 40{ 41 Pushq(x); 42} 43 44void AssemblerX64::Popq(Register x) 45{ 46 EmitRexPrefix(x); 47 // 0x58: Pop r16 48 EmitU8(0x58 | LowBits(x)); 49} 50 51void AssemblerX64::Pop(Register x) 52{ 53 Popq(x); 54} 55 56 57void 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 79void 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 87void 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 109void 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 131void 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 139void 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 161void 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 183void 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 202void 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 210void 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 232void AssemblerX64::Cmp(Immediate src, Register dst) 233{ 234 Cmpq(src, dst); 235} 236 237void 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 245void 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 253void 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 265void 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 273void 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 281void 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 291void 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 299void AssemblerX64::Mov(const Operand &src, Register dst) 300{ 301 Movq(src, dst); 302} 303 304void AssemblerX64::EmitJmp(int32_t offset) 305{ 306 offset--; 307 if (InRange8(offset - SIZE_OF_INT8)) { 308 // EB: Jmp rel8 309 EmitU8(0xEB); 310 EmitI8(offset - SIZE_OF_INT8); 311 } else { 312 // E9: Jmp rel32 313 EmitU8(0xE9); 314 EmitI32(offset - SIZE_OF_INT32); 315 } 316} 317 318void AssemblerX64::EmitJa(int32_t offset) 319{ 320 offset--; 321 if (InRange8(offset - SIZE_OF_INT8)) { 322 // 77 : Ja rel8 323 EmitU8(0x77); 324 EmitI8(offset - SIZE_OF_INT8); 325 } else { 326 offset--; 327 // 0F 87 : ja rel32 328 EmitU8(0x0F); 329 EmitU8(0x87); 330 EmitI32(offset - SIZE_OF_INT32); 331 } 332} 333 334void AssemblerX64::EmitJb(int32_t offset) 335{ 336 offset--; 337 if (InRange8(offset - SIZE_OF_INT8)) { 338 // 72 : Jb rel8 339 EmitU8(0x72); 340 EmitI8(offset - SIZE_OF_INT8); 341 } else { 342 offset--; 343 // 0F 82 : Jb rel32 344 EmitU8(0x0F); 345 EmitU8(0x82); 346 EmitI32(offset - SIZE_OF_INT32); 347 } 348} 349 350void AssemblerX64::EmitJz(int32_t offset) 351{ 352 offset--; 353 if (InRange8(offset - SIZE_OF_INT8)) { 354 // 74 : Jz rel8 355 EmitU8(0x74); 356 EmitI8(offset - SIZE_OF_INT8); 357 } else { 358 offset--; 359 // 0F 84 : Jz rel32 360 EmitU8(0x0F); 361 EmitU8(0x84); 362 EmitI32(offset - SIZE_OF_INT32); 363 } 364} 365 366void AssemblerX64::EmitJne(int32_t offset) 367{ 368 offset--; 369 if (InRange8(offset - SIZE_OF_INT8)) { 370 // 75 : Jne rel8; 371 EmitU8(0x75); 372 EmitI8(offset - SIZE_OF_INT8); 373 } else { 374 offset--; 375 // 0F 85 : Jne rel32 376 EmitU8(0x0F); 377 EmitU8(0x85); 378 EmitI32(offset - SIZE_OF_INT32); 379 } 380} 381 382void AssemblerX64::EmitJbe(int32_t offset) 383{ 384 offset--; 385 if (InRange8(offset - SIZE_OF_INT8)) { 386 // 76 : Jbe rel8; 387 EmitU8(0x76); 388 EmitI8(offset - SIZE_OF_INT8); 389 } else { 390 offset--; 391 // 0F 86 : Jne rel32 392 EmitU8(0x0F); 393 EmitU8(0x86); 394 EmitI32(offset - SIZE_OF_INT32); 395 } 396} 397 398void AssemblerX64::EmitJnz(int32_t offset) 399{ 400 offset--; 401 if (InRange8(offset)) { 402 // 75 : Jnz rel8 403 EmitU8(0x75); 404 EmitI8(offset - SIZE_OF_INT8); 405 } else { 406 offset--; 407 // 0F 85: Jnz rel32 408 EmitU8(0x0F); 409 EmitU8(0x85); 410 EmitI32(offset - SIZE_OF_INT32); 411 } 412} 413 414void AssemblerX64::EmitJle(int32_t offset) 415{ 416 offset--; 417 if (InRange8(offset)) { 418 // 7E : Jle rel8 419 EmitU8(0x7E); 420 EmitI8(offset - SIZE_OF_INT8); 421 } else { 422 offset--; 423 // 0F 8E: Jle rel32 424 EmitU8(0x0F); 425 EmitU8(0x8E); 426 EmitI32(offset - SIZE_OF_INT32); 427 } 428} 429 430void AssemblerX64::EmitJae(int32_t offset) 431{ 432 offset--; 433 if (InRange8(offset)) { 434 // 73 : Jae rel8 435 EmitU8(0x73); 436 EmitI8(offset - SIZE_OF_INT8); 437 } else { 438 offset--; 439 // 0F 83: Jae rel32 440 EmitU8(0x0F); 441 EmitU8(0x83); 442 EmitI32(offset - SIZE_OF_INT32); 443 } 444} 445 446void AssemblerX64::EmitJg(int32_t offset) 447{ 448 offset--; 449 if (InRange8(offset)) { 450 // 7F : Jg rel8 451 EmitU8(0x7F); 452 EmitI8(offset - SIZE_OF_INT8); 453 } else { 454 offset--; 455 // 0F 8F: Jg rel32 456 EmitU8(0x0F); 457 EmitU8(0x8F); 458 EmitI32(offset - SIZE_OF_INT32); 459 } 460} 461 462void AssemblerX64::EmitJge(int32_t offset) 463{ 464 offset--; 465 if (InRange8(offset)) { 466 // 7D : Jg rel8 467 EmitU8(0x7D); 468 EmitI8(offset - SIZE_OF_INT8); 469 } else { 470 offset--; 471 // 0F 8F: Jg rel32 472 EmitU8(0x0F); 473 EmitU8(0x8D); 474 EmitI32(offset - SIZE_OF_INT32); 475 } 476} 477 478void AssemblerX64::EmitJe(int32_t offset) 479{ 480 offset--; 481 if (InRange8(offset)) { 482 // 74 : Je rel8 483 EmitU8(0x74); 484 EmitI8(offset - SIZE_OF_INT8); 485 } else { 486 offset--; 487 // 0F 84: Je rel32 488 EmitU8(0x0F); 489 EmitU8(0x84); 490 EmitI32(offset - SIZE_OF_INT32); 491 } 492} 493 494void AssemblerX64::EmitCall(int32_t offset) 495{ 496 offset--; 497 // E8: call rel32 498 EmitU8(0xE8); 499 EmitI32(offset - SIZE_OF_INT32); 500} 501 502void AssemblerX64::EmitJnb(int32_t offset) 503{ 504 offset--; 505 if (InRange8(offset)) { 506 // 73 : Jnb rel8 507 EmitU8(0x73); 508 EmitI8(offset - SIZE_OF_INT8); 509 } else { 510 offset--; 511 // 0F 83: Jnb rel32 512 EmitU8(0x0F); 513 EmitU8(0x83); 514 EmitI32(offset - SIZE_OF_INT32); 515 } 516} 517 518void 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 528void 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 548void AssemblerX64::Ret() 549{ 550 // C3: RET Near return to calling procedure 551 EmitU8(0xC3); 552} 553 554void 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 586void 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 595void 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 608void 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 640void 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} 671void 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 703void 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 735void 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 768Operand::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 787Operand::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] 805Operand::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 813void 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 820void Operand::BuildModerm(int32_t mode, Register rm) 821{ 822 rex_ |= AssemblerX64::GetModrmRex(rm); 823 moderm_ = AssemblerX64::GetModrm(mode, rm); 824} 825 826void Operand::BuildDisp8(int32_t disp) 827{ 828 disp_ = disp; 829 hasDisp8_ = true; 830} 831 832void Operand::BuildDisp32(int32_t disp) 833{ 834 disp_ = disp; 835 hasDisp32_ = true; 836} 837 838void 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 853void 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 861void 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 869void AssemblerX64::Movl(Register src, const Operand& dst) 870{ 871 EmitRexPrefixl(src, dst); 872 // 0x89: Move r32 to r/m64 873 EmitU8(0x89); 874 EmitOperand(src, dst); 875} 876 877void AssemblerX64::Testq(Immediate src, Register dst) 878{ 879 if (InRange8(src.Value())) { 880 Testb(src, dst); 881 } else if (dst == rax) { 882 // A9: Test rax, imm32 883 EmitU8(0xA9); 884 EmitI32(src.Value()); 885 } else { 886 EmitRexPrefixW(dst); 887 // F7: Test r/m64, imm32 888 EmitU8(0xF7); 889 // 0: F7 0 id 890 EmitModrm(0, dst); 891 EmitI32(src.Value()); 892 } 893} 894 895void AssemblerX64::Testb(Immediate src, Register dst) 896{ 897 ASSERT(InRange8(src.Value())); 898 if (dst == rax) { 899 // A8: Test al, imm8 900 EmitU8(0xA8); 901 } else { 902 // AH BH CG DH can not be encoded to access if REX prefix used. 903 if (dst >= rsp) { 904 EmitRexPrefixL(dst); 905 } 906 // F6: Test r/m8, imm8 907 // REX F6: Test r/m8*, imm8 908 EmitU8(0xF6); 909 // 0: F6 /0 ib 910 EmitModrm(0, dst); 911 } 912 EmitI8(static_cast<int8_t>(src.Value())); 913} 914 915void AssemblerX64::Jne(Label *target, Distance distance) 916{ 917 if (target->IsBound()) { 918 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 919 EmitJne(offset); 920 return; 921 } 922 auto pos = GetCurrentPosition(); 923 int32_t emitPos = 0; 924 if (distance == Distance::Near) { 925 if (target->IsLinkedNear()) { 926 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 927 } 928 // +1: skip opcode 929 target->LinkNearPos(pos + 1); 930 ASSERT(InRange8(emitPos)); 931 // 75 : Jne rel8; 932 EmitU8(0x75); 933 EmitI8(static_cast<int8_t>(emitPos)); 934 } else { 935 if (target->IsLinked()) { 936 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 937 } 938 // 2: skip opcode 939 target->LinkTo(pos + 2); 940 // 0F 85 : Jne rel32 941 EmitU8(0x0F); 942 EmitU8(0x85); 943 EmitI32(emitPos); 944 } 945} 946 947void AssemblerX64::Cmpl(Register src, Register dst) 948{ 949 EmitRexPrefixl(src, dst); 950 // 39: Cmp r16 to r/m16 951 EmitU8(0x39); 952 EmitModrm(src, dst); 953} 954 955void AssemblerX64::Jbe(Label *target, Distance distance) 956{ 957 if (target->IsBound()) { 958 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 959 EmitJbe(offset); 960 return; 961 } 962 auto pos = GetCurrentPosition(); 963 int32_t emitPos = 0; 964 if (distance == Distance::Near) { 965 if (target->IsLinkedNear()) { 966 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 967 } 968 // +1: skip opcode 969 target->LinkNearPos(pos + 1); 970 ASSERT(InRange8(emitPos)); 971 // 76 : Jbe rel8; 972 EmitU8(0x76); 973 EmitI8(static_cast<int8_t>(emitPos)); 974 } else { 975 if (target->IsLinked()) { 976 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 977 } 978 // 2: skip opcode 979 target->LinkTo(pos + 2); 980 // 0F 86 : Jbe rel32 981 EmitU8(0x0F); 982 EmitU8(0x86); 983 EmitI32(emitPos); 984 } 985} 986 987void AssemblerX64::CMovbe(Register src, Register dst) 988{ 989 EmitRexPrefixl(dst, src); 990 // 0f 46: CMovbe r32, r/m32 991 EmitU8(0x0F); 992 EmitU8(0x46); 993 EmitModrm(dst, src); 994} 995 996void AssemblerX64::Leaq(const Operand &src, Register dst) 997{ 998 EmitRexPrefix(dst, src); 999 // 8D : lea r64, m 1000 EmitU8(0x8D); 1001 EmitOperand(dst, src); 1002} 1003 1004void AssemblerX64::Leal(const Operand &src, Register dst) 1005{ 1006 EmitRexPrefixl(dst, src); 1007 // 8D : lea r64, m 1008 EmitU8(0x8D); 1009 EmitOperand(dst, src); 1010} 1011 1012void AssemblerX64::Shrq(Immediate src, Register dst) 1013{ 1014 EmitRexPrefixW(dst); 1015 // C1 : Shr r/m64, imm8; 1016 EmitU8(0xc1); 1017 // 5: C1 /5 id 1018 EmitModrm(5, dst); 1019 EmitI8(static_cast<int8_t>(src.Value())); 1020} 1021 1022void AssemblerX64::Shrl(Immediate src, Register dst) 1023{ 1024 EmitRexPrefix(dst); 1025 // C1 : Shr r/m32, imm8; 1026 EmitU8(0xc1); 1027 // 5: C1 /5 id 1028 EmitModrm(5, dst); 1029 EmitI8(static_cast<int8_t>(src.Value())); 1030} 1031 1032void AssemblerX64::Shr(Immediate src, Register dst) 1033{ 1034 Shrq(src, dst); 1035} 1036 1037void AssemblerX64::Andq(Immediate src, Register dst) 1038{ 1039 EmitRexPrefixW(dst); 1040 if (InRange8(src.Value())) { 1041 // 83: and r/m64, imm8 1042 EmitU8(0x83); 1043 // 4: 83 /4 ib 1044 EmitModrm(4, dst); 1045 EmitI8(static_cast<int8_t>(src.Value())); 1046 } else if (dst == rax) { 1047 // 0x25: and rax, imm32 1048 EmitU8(0x25); 1049 EmitI32(src.Value()); 1050 } else { 1051 // 81: and r/m64, imm32 1052 EmitU8(0x81); 1053 // 4: 81 /4 id 1054 EmitModrm(4, dst); 1055 EmitI32(src.Value()); 1056 } 1057} 1058 1059void AssemblerX64::Andl(Immediate src, Register dst) 1060{ 1061 EmitRexPrefix(dst); 1062 if (InRange8(src.Value())) { 1063 // 83: and r/m64, imm8 1064 EmitU8(0x83); 1065 // 4: 83 /4 ib 1066 EmitModrm(4, dst); 1067 EmitI8(static_cast<int8_t>(src.Value())); 1068 } else if (dst == rax) { 1069 // 0x25: and rax, imm32 1070 EmitU8(0x25); 1071 EmitI32(src.Value()); 1072 } else { 1073 // 81: and r/m64, imm32 1074 EmitU8(0x81); 1075 // 4: 81 /4 id 1076 EmitModrm(4, dst); 1077 EmitI32(src.Value()); 1078 } 1079} 1080 1081void AssemblerX64::And(Register src, Register dst) 1082{ 1083 EmitRexPrefix(src, dst); 1084 // 21 : And r/m64, r64 1085 EmitU8(0x21); 1086 EmitModrm(src, dst); 1087} 1088 1089void AssemblerX64::Or(Immediate src, Register dst) 1090{ 1091 EmitRexPrefixW(dst); 1092 if (InRange8(src.Value())) { 1093 // 83: or r/m64, imm8 1094 EmitU8(0x83); 1095 // 1: 83 /1 ib 1096 EmitModrm(1, dst); 1097 EmitI8(static_cast<int8_t>(src.Value())); 1098 } else if (dst == rax) { 1099 // 0x0D: or rax, imm32 1100 EmitU8(0x0D); 1101 EmitI32(src.Value()); 1102 } else { 1103 // 81: or r/m64, imm32 1104 EmitU8(0x81); 1105 // 1: 81 /1 id 1106 EmitModrm(1, dst); 1107 EmitI32(src.Value()); 1108 } 1109} 1110 1111void AssemblerX64::Orq(Register src, Register dst) 1112{ 1113 EmitRexPrefix(src, dst); 1114 // 09 : Or r/m64, r64 1115 EmitU8(0x09); 1116 EmitModrm(src, dst); 1117} 1118 1119void AssemblerX64::Jnz(Label *target, Distance distance) 1120{ 1121 if (target->IsBound()) { 1122 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1123 EmitJnz(offset); 1124 return; 1125 } 1126 auto pos = GetCurrentPosition(); 1127 int32_t emitPos = 0; 1128 if (distance == Distance::Near) { 1129 if (target->IsLinkedNear()) { 1130 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1131 } 1132 // +1: skip opcode 1133 target->LinkNearPos(pos + 1); 1134 ASSERT(InRange8(emitPos)); 1135 // 75 : Jnz rel8; 1136 EmitU8(0x75); 1137 EmitI8(static_cast<int8_t>(emitPos)); 1138 } else { 1139 if (target->IsLinked()) { 1140 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1141 } 1142 // 2: skip opcode 1143 target->LinkTo(pos + 2); 1144 // 0F 85 : Jnz rel32 1145 EmitU8(0x0F); 1146 EmitU8(0x85); 1147 EmitI32(emitPos); 1148 } 1149} 1150 1151void AssemblerX64::Jle(Label *target, Distance distance) 1152{ 1153 if (target->IsBound()) { 1154 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1155 EmitJle(offset); 1156 return; 1157 } 1158 auto pos = GetCurrentPosition(); 1159 int32_t emitPos = 0; 1160 if (distance == Distance::Near) { 1161 if (target->IsLinkedNear()) { 1162 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1163 } 1164 // +1: skip opcode 1165 target->LinkNearPos(pos + 1); 1166 ASSERT(InRange8(emitPos)); 1167 // 7E : Jle rel8; 1168 EmitU8(0x7E); 1169 EmitI8(static_cast<int8_t>(emitPos)); 1170 } else { 1171 if (target->IsLinked()) { 1172 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1173 } 1174 // 2: skip opcode 1175 target->LinkTo(pos + 2); 1176 // 0F 8E: Jle rel32 1177 EmitU8(0x0F); 1178 EmitU8(0x8E); 1179 EmitI32(emitPos); 1180 } 1181} 1182 1183void AssemblerX64::Jae(Label *target, Distance distance) 1184{ 1185 if (target->IsBound()) { 1186 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1187 EmitJae(offset); 1188 return; 1189 } 1190 auto pos = GetCurrentPosition(); 1191 int32_t emitPos = 0; 1192 if (distance == Distance::Near) { 1193 if (target->IsLinkedNear()) { 1194 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1195 } 1196 // +1: skip opcode 1197 target->LinkNearPos(pos + 1); 1198 ASSERT(InRange8(emitPos)); 1199 // 73 : Jae rel8 1200 EmitU8(0x73); 1201 EmitI8(static_cast<int8_t>(emitPos)); 1202 } else { 1203 if (target->IsLinked()) { 1204 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1205 } 1206 // 2: skip opcode 1207 target->LinkTo(pos + 2); 1208 // 0F 83: Jae rel32 1209 EmitU8(0x0F); 1210 EmitU8(0x83); 1211 EmitI32(emitPos); 1212 } 1213} 1214 1215void AssemblerX64::Jg(Label *target, Distance distance) 1216{ 1217 if (target->IsBound()) { 1218 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1219 EmitJg(offset); 1220 return; 1221 } 1222 auto pos = GetCurrentPosition(); 1223 int32_t emitPos = 0; 1224 if (distance == Distance::Near) { 1225 if (target->IsLinkedNear()) { 1226 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1227 } 1228 // +1: skip opcode 1229 target->LinkNearPos(pos + 1); 1230 ASSERT(InRange8(emitPos)); 1231 // 7F : Jg rel8 1232 EmitU8(0x7F); 1233 EmitI8(static_cast<int8_t>(emitPos)); 1234 } else { 1235 if (target->IsLinked()) { 1236 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1237 } 1238 // 2: skip opcode 1239 target->LinkTo(pos + 2); 1240 // 0F 8F: Jae rel32 1241 EmitU8(0x0F); 1242 EmitU8(0x8F); 1243 EmitI32(emitPos); 1244 } 1245} 1246 1247void AssemblerX64::Jge(Label *target, Distance distance) 1248{ 1249 if (target->IsBound()) { 1250 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1251 EmitJge(offset); 1252 return; 1253 } 1254 auto pos = GetCurrentPosition(); 1255 int32_t emitPos = 0; 1256 if (distance == Distance::Near) { 1257 if (target->IsLinkedNear()) { 1258 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1259 } 1260 // +1: skip opcode 1261 target->LinkNearPos(pos + 1); 1262 ASSERT(InRange8(emitPos)); 1263 // 7F : Jg rel8 1264 EmitU8(0x7D); 1265 EmitI8(static_cast<int8_t>(emitPos)); 1266 } else { 1267 if (target->IsLinked()) { 1268 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1269 } 1270 // 2: skip opcode 1271 target->LinkTo(pos + 2); 1272 // 0F 8F: Jae rel32 1273 EmitU8(0x0F); 1274 EmitU8(0x8D); 1275 EmitI32(emitPos); 1276 } 1277} 1278 1279void AssemblerX64::Movzbq(const Operand &src, Register dst) 1280{ 1281 EmitRexPrefix(dst, src); 1282 // 0F B6 : Movzx r64, r/m16 1283 EmitU8(0x0F); 1284 EmitU8(0xB6); 1285 // 0F B6 /r: Movzx r64, r/m16 1286 EmitOperand(dst, src); 1287} 1288 1289void AssemblerX64::Movzbl(const Operand &src, Register dst) 1290{ 1291 EmitRexPrefixl(dst, src); 1292 // 0F B6 : Movzx r64, r/m16 1293 EmitU8(0x0F); 1294 EmitU8(0xB6); 1295 // 0F B6 /r: Movzx r64, r/m16 1296 EmitOperand(dst, src); 1297} 1298 1299void AssemblerX64::Movzbl(Register src, Register dst) 1300{ 1301 EmitRexPrefixl(dst, src); 1302 // 0F B6 : Movzx r64, r/m16 1303 EmitU8(0x0F); 1304 EmitU8(0xB6); 1305 // 0F B6 /r: Movzx r64, r/m16 1306 EmitModrm(dst, src); 1307} 1308 1309void AssemblerX64::Btq(Immediate src, Register dst) 1310{ 1311 EmitRexPrefixW(dst); 1312 // 0F BA: bt r/m32, imm8; 1313 EmitU8(0x0F); 1314 EmitU8(0xBA); 1315 // /4: 0F BA bt r/m32, imm8 1316 EmitModrm(4, dst); 1317 EmitI8(static_cast<int8_t>(src.Value())); 1318} 1319void AssemblerX64::Btl(Immediate src, Register dst) 1320{ 1321 EmitRexPrefix(dst); 1322 // 0F BA: bt r/m32, imm8; 1323 EmitU8(0x0F); 1324 EmitU8(0xBA); 1325 // /4: 0F BA bt r/m32, imm8 1326 EmitModrm(4, dst); 1327 EmitI8(static_cast<int8_t>(src.Value())); 1328} 1329 1330void AssemblerX64::Movabs(uint64_t src, Register dst) 1331{ 1332 // REX.W + B8 + rd io : Mov r64, imm64 1333 EmitRexPrefixW(dst); 1334 EmitU8(0xB8 | LowBits(dst)); 1335 EmitU64(src); 1336} 1337 1338void AssemblerX64::Shll(Immediate src, Register dst) 1339{ 1340 EmitRexPrefix(dst); 1341 // C1 : shl r/m32, imm8 1342 EmitU8(0xC1); 1343 // C1 /4 1344 EmitModrm(4, dst); 1345 EmitI8(static_cast<int8_t>(src.Value())); 1346} 1347 1348void AssemblerX64::Shlq(Immediate src, Register dst) 1349{ 1350 EmitRexPrefixW(dst); 1351 // C1 : shl r/m64, imm8 1352 EmitU8(0xC1); 1353 // C1 /4 1354 EmitModrm(4, dst); 1355 EmitI8(static_cast<int8_t>(src.Value())); 1356} 1357 1358void AssemblerX64::Btsl(Register src, Register dst) 1359{ 1360 EmitRexPrefixl(src, dst); 1361 // 0F AB: bts r32, r32; 1362 EmitU8(0x0F); 1363 EmitU8(0xAB); 1364 1365 EmitModrm(src, dst); 1366} 1367 1368void AssemblerX64::Int3() 1369{ 1370 // CC :: INT3 1371 EmitU8(0xCC); 1372} 1373 1374void AssemblerX64::Movzwq(const Operand &src, Register dst) 1375{ 1376 EmitRexPrefix(dst, src); 1377 EmitU8(0x0F); 1378 EmitU8(0xB7); 1379 EmitOperand(dst, src); 1380} 1381 1382void AssemblerX64::Jnb(Label *target, Distance distance) 1383{ 1384 if (target->IsBound()) { 1385 int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition()); 1386 EmitJnb(offset); 1387 return; 1388 } 1389 auto pos = GetCurrentPosition(); 1390 int32_t emitPos = 0; 1391 if (distance == Distance::Near) { 1392 if (target->IsLinkedNear()) { 1393 emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos); 1394 } 1395 // +1: skip opcode 1396 target->LinkNearPos(pos + 1); 1397 ASSERT(InRange8(emitPos)); 1398 // 73 : Jnb rel8 1399 EmitU8(0x73); 1400 EmitI8(static_cast<int8_t>(emitPos)); 1401 } else { 1402 if (target->IsLinked()) { 1403 emitPos = static_cast<int32_t>(target->GetLinkedPos()); 1404 } 1405 // 2: skip opcode 1406 target->LinkTo(pos + 2); 1407 // 0F 83: Jnb rel32 1408 EmitU8(0x0F); 1409 EmitU8(0x83); 1410 EmitI32(emitPos); 1411 } 1412} 1413} // panda::ecmascript::x64 1414