1 2;++ 3; 4; Copyright (c) Microsoft Corporation. All rights reserved. 5; 6; 7; Module: 8; 9; kxamd64.w 10; 11; Astract: 12; 13; Contains AMD64 architecture constants and assembly macros. 14; 15; 16;-- 17 18include macamd64.inc 19 20; 21; If the actual CFG dispatch code is not being assembled, then declare the 22; guard dispatch function as external. 23; 24 25ifdef CAPXCALL_VIA_CFG 26ifndef CFG_ASM 27 28 extern _guard_dispatch_icall:proc 29 30endif ; CFG_ASM 31endif 32 33; 34; 35 36; 37; Retpoline macros 38; 39 40RETPOLINEDIRECTIVE macro RetpolineType 41 42ifdef _RETPOLINE 43 ifidn <RetpolineType>,<RetpolineRax> 44 .retpolinerax 45 elseifidn <RetpolineType>,<RetpolineSwitchTable> 46 .retpolineswitchtable 47 elseifidn <RetpolineType>,<RetpolineImport> 48 .retpolineimport 49 elseifidn <RetpolineType>,<RetpolineCfgDispatch> 50 .retpolineguardicall 51 elseifidn <RetpolineType>,<RetpolineIgnore> 52 .retpolineignore 53 elseifnb <RetpolineType> 54 .err @catstr(<Invalid retpoline type >, <RetpolineType>) 55 endif 56endif ; _RETPOLINE 57 58 ENDM 59 60; 61; IceCAP macros 62; 63 64ifdef _CAPKERN 65 66; 67; Define kernel icecap macros for tracing assembly routines. 68; 69 70 extern __CAP_Start_DirectCall_Profiling_ASM:proc 71 extern __CAP_Start_IndirectCall_Profiling_ASM:proc 72 extern __CAP_Start_DirectCall_Tail_Profiling_ASM:proc 73 extern __CAP_Start_IndirectCall_Tail_Profiling_ASM:proc 74 extern __CAP_Start_DirectJmp_Profiling_ASM:proc 75 extern __CAP_Start_IndirectJmp_Profiling_ASM:proc 76 extern __CAP_End_Profiling:proc 77 78endif ; _CAPKERN 79 80; 81; CAPDCALL - Perform an IceCAP instrumented direct function call. 82; 83; Do NOT use this macro directly. Use CAPCALL instead. 84; 85; Instrumenation is disabled on non-IceCAP builds. 86; 87; Arguments: 88; 89; Callee - A function label. 90; 91; NoRet - If set, the function does not return to the caller. 92; 93; Return value: 94; 95; Returns the value of the function specified by Callee. 96; 97 98CAPDCALL macro Callee, NoRet 99 100ifdef _CAPKERN 101 102ifnb <NoRet> 103 104 call __CAP_Start_DirectCall_Tail_Profiling_ASM ; record profiling information 105 106else 107 108 call __CAP_Start_DirectCall_Profiling_ASM ; record profiling information 109 110endif 111 112endif ; _CAPKERN 113 114 call Callee 115 116ifdef _CAPKERN 117 118ifb <NoRet> 119 120 call __CAP_End_Profiling ; record profiling information 121 122endif 123 124endif ; _CAPKERN 125 126 endm 127 128; 129; CAPICALL - Perform an IceCAP instrumented indirect function call. 130; 131; Do NOT use this macro directly. Use CAPCALL instead. 132; 133; Instrumenation is disabled on non-IceCAP builds. 134; 135; Arguments: 136; 137; Callee - A register or a memory location. 138; 139; NoRet - If set, the function does not return to the caller. 140; 141; Return value: 142; 143; Returns the value of the function specified by Callee. 144; 145 146CAPICALL macro Callee, NoRet, RetpolineType 147 148ifdef _CAPKERN 149 150ifnb <NoRet> 151 152 call __CAP_Start_IndirectCall_Tail_Profiling_ASM ; record profiling information 153 154else 155 156 call __CAP_Start_IndirectCall_Profiling_ASM ; record profiling information 157 158endif 159 160endif ; _CAPKERN 161 162 RETPOLINEDIRECTIVE RetpolineType 163 164 call Callee 165 166 167ifdef _CAPKERN 168 169ifb <NoRet> 170 171 call __CAP_End_Profiling ; record profiling information 172 173endif 174 175endif ; _CAPKERN 176 177 endm 178 179; 180; CAPXCALL - Perform a CFG IceCAP instrumented indirect function call. 181; 182; This macro MUST be used to call CFG checked functions. 183; 184; Instrumenation is disabled on non-IceCAP builds. 185; 186; Arguments: 187; 188; Callee - A register or a memory location. 189; 190; NoRet - If set, the function does not return to the caller. 191; 192; Return value: 193; 194; Returns the value of the function specified by Callee. 195; 196 197CAPXCALL macro Callee, NoRet 198 199ifdifi <Callee>, <rax> 200 201 mov rax, Callee 202 203endif 204 205ifdef CAPXCALL_VIA_CFG 206 207 CAPDCALL _guard_dispatch_icall, <NoRet> 208 209else 210 211 CAPICALL rax, <NoRet>, RetpolineRax 212endif 213 214 endm 215 216; 217; CAPCALL - Perform an IceCAP instrumented function call. 218; 219; Instrumenation is disabled on non-IceCAP builds. 220; 221; Arguments: 222; 223; Callee - A function label, a register, or a memory location. 224; 225; NoRet - If set, the function does not return to the caller. 226; 227; Return value: 228; 229; Returns the value of the function specified by Callee. 230; 231 232CAPCALL macro Callee, NoRet, RetpolineType 233 234; 235; The documentation surrounding the .type operator is very poor. 236; Here is the significance of each of the bits. 237; 238; 0 - References a label in the code segment if set. 239; 1 - References a memory variable or relocatable data object if set. 240; 2 - Is an immediate (absolute/constant) value if set. 241; 3 - Uses direct memory addressing if set. 242; 4 - Is a register name, if set. 243; 5 - References no undefined symbols and there is no error, if set. 244; 6 - Is an SS: relative reference, if set. 245; 7 - References an external name. 246; 247 248if (.type(Callee)) eq 000h ; direct via local label 249 250 CAPDCALL Callee, NoRet 251 252elseif (.type(Callee)) eq 022h ; register-direct call 253 254 CAPICALL Callee, NoRet, RetpolineType 255 256elseif (.type(Callee)) eq 025h ; direct via extern proc 257 258 CAPDCALL Callee, NoRet 259 260elseif (.type(Callee)) eq 030h ; register-indirect call 261 262 CAPICALL Callee, NoRet, RetpolineType 263 264elseif (.type(Callee)) eq 062h ; indirect via offset from register 265 266 CAPICALL Callee, NoRet, RetpolineType 267 268elseif (.type(Callee)) eq 0A5h ; direct via extern proc 269 270 CAPDCALL Callee, NoRet 271 272elseif (.type(Callee)) eq 0AAh ; indirect via extern qword 273 274 CAPICALL Callee, NoRet, RetpolineType 275 276else 277 278 .err @catstr(<unknown expression type >, %(.type(Callee))) 279 280endif 281 282 endm 283 284; 285; CAPJMP - Perform an IceCAP instrumented tail jump. 286; 287; Instrumenation is disabled on non-IceCAP builds. 288; 289; Arguments: 290; 291; Callee - A function label, a memory address, or a register. 292; 293; Return value: 294; 295; Never returns. 296; 297 298CAPJMP macro Callee, RetpolineType 299 300; 301; Begin jump instrumentation 302; 303 304ifdef _CAPKERN 305 306; 307; The documentation surrounding the .type operator is very poor. 308; See above for syntax explanation. 309; 310 311if (.type(Callee)) eq 000h ; direct via local label 312 313 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 314 315elseif (.type(Callee)) eq 022h ; register-direct jump 316 317 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 318 319elseif (.type(Callee)) eq 025h ; direct via extern proc 320 321 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 322 323elseif (.type(Callee)) eq 030h ; register-indirect 324 325 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 326 327elseif (.type(Callee)) eq 062h ; indirect via offset from register 328 329 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 330 331elseif (.type(Callee)) eq 0A5h ; direct via extern proc 332 333 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 334 335elseif (.type(Callee)) eq 0AAh ; indirect via extern qword 336 337 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 338 339else 340 341 .err @catstr(<unknown expression type >, %(.type(Callee))) 342 343endif 344 345endif ; _CAPKERN 346 347; 348; End jump instrumentation. Begin common code. 349; 350 351 RETPOLINEDIRECTIVE <RetpolineType> 352 353 jmp Callee 354 355 endm 356 357; 358; CAPRETPOLJMP - Perform an IceCAP instrumented tail jump using retpoline. 359; 360; Instrumentation is disabled on non-IceCAP builds. 361; 362; Arguments: 363; 364; Callee - A function label, a memory address or a register. 365; 366; Return value: 367; 368; Never returns. 369; 370 371CAPRETPOLJMP macro Callee, Alignment 372 373 LOCAL Jump 374 375; 376; Begin jump instrumentation 377; 378 379ifdef _CAPKERN 380 381; 382; The documentation surrounding the .type operator is very poor. 383; See above for syntax explanation. 384; 385 386if (.type(Callee)) eq 000h ; direct via local label 387 388 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 389 390elseif (.type(Callee)) eq 022h ; register-direct jump 391 392 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 393 394elseif (.type(Callee)) eq 025h ; direct via extern proc 395 396 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 397 398elseif (.type(Callee)) eq 030h ; register-indirect 399 400 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 401 402elseif (.type(Callee)) eq 062h ; indirect via offset from register 403 404 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 405 406elseif (.type(Callee)) eq 0A5h ; direct via extern proc 407 408 call __CAP_Start_DirectJmp_Profiling_ASM ; record profiling information 409 410elseif (.type(Callee)) eq 0AAh ; indirect via extern qword 411 412 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 413 414else 415 416 .err @catstr(<unknown expression type >, %(.type(Callee))) 417 418endif 419 420endif ; _CAPKERN 421 422; 423; End jump instrumentation. Begin common code. 424; 425 426 call Jump 427 int 3 428 429ifnb <Alignment> 430 ALIGN Alignment 431else 432 ALIGN 16 433endif 434 435Jump: 436 mov [rsp], Callee 437 ret 438 439 endm 440 441; 442; CAPEPILOGJMP - Logs a tail jump from an epilog. 443; 444; Instrumenation is disabled on non-IceCAP builds. 445; 446; Arguments: 447; 448; Callee - A function label, a memory address, or a register. 449; 450; Return value: 451; 452; None 453; 454 455CAPEPILOGJMP macro Callee 456 457 LOCAL Exit 458 459ifdef _CAPKERN 460 461 jmp Exit 462Exit: 463 CAPJMP Callee 464 465else 466 467 jmp Callee 468 469endif ; _CAPKERN 470 471 endm 472 473; 474; CAPREX_JMP_REG - Perform an IceCAP instrumented indirect tail jump. 475; Use this when a function does not return to the caller 476; and when a rex_jmp_reg would normally be specified. 477; 478; Instrumentation is disabled on non-IceCAP builds. 479; 480; Arguments: 481; 482; Callee is a register or memory location. 483; 484; Return value: 485; 486; None 487; 488 489CAPREX_JMP_REG macro Callee, RetpolineType 490 491ifdef _CAPKERN 492 493 call __CAP_Start_IndirectJmp_Profiling_ASM ; record profiling information 494 495endif ; _CAPKERN 496 497 RETPOLINEDIRECTIVE <RetpolineType> 498 rex_jmp_reg Callee ; make the jump 499 endm 500 501; 502; Define macro to clear legacy floating exceptions. 503; 504 505clfpex macro 506 507 db 0dbh, 0e2h 508 509 endm 510 511; 512; Define macro to perform an enlightened yield. 513; 514; Arguments: 515; 516; None. 517; 518; N.B. This macro is restricted to only freely using the register specified by 519; the 'Register' parameter and rcx. 'Register' should be nonvolatile. 520; 521 522EnlightenedYield macro Register 523 524 local skip 525 526; 527;; 528 529skip: Yield 530 531 endm 532 533; 534; Define macro to acquire spin lock. 535; 536; Arguments: 537; 538; None. 539; 540; N.B. This macro is restricted to only freely using the register specified by 541; the 'Register' parameter and rcx. 'Register' should be nonvolatile. 542; 543; N.B. If 'Register' is specified, 'Address' must be nonvolatile or global. 544; 545 546AcquireSpinLock macro Address, Register 547 548 local exit, spin 549 550ifndef NT_UP 551 552 lock bts qword ptr Address, 0 ; attempt to acquire spin lock 553 jnc short exit ; if nc, spin lock acquired 554 555ifndef XBOX_SYSTEMOS 556 557ifnb <Register> 558 559 xor Register, Register ; initialize spin count 560 561endif 562 563endif 564 565spin: EnlightenedYield <Register> ; yield execution 566 test qword ptr Address, 1 ; check if lock currently owned 567 jnz short spin ; if nz, spin lock owned 568 lock bts qword ptr Address, 0 ; attempt to acquire spin lock 569 jc short spin ; if c, spin lock owned 570 571exit: ; continue 572 573endif 574 575 endm 576 577; 578; Define macro to acquire spin lock and mask interrupts. 579; 580; Arguments: 581; 582; None. 583; 584; Note: 585; 586; rsp is assumed to point to pushed EFLAGS 587; 588; N.B. This macro uses no registers. 589; 590 591AcquireSpinLockDisable macro Address 592 593 local exit, spin, spin1 594 595 cli ; disable interrupts 596 597ifndef NT_UP 598 599 lock bts qword ptr Address, 0 ; attempt to acquire spin lock 600 jnc short exit ; if nc, spin lock acquired 601spin: test dword ptr [rsp], EFLAGS_IF_MASK ; test if interrupts enabled 602 jz short spin1 ; if z, interrupts disabled 603 sti ; enable interrupts 604 605spin1: Yield ; yield execution 606 607 test qword ptr Address, 1 ; check if lock currently owned 608 jnz short spin1 ; if nz, spin lock owned 609 cli ; lock is (was) clear, disable ints 610 lock bts qword ptr Address, 0 ; attempt to acquire spin lock 611 jc short spin ; if c, spin lock owned 612exit: ; continue 613 614endif 615 616 endm 617 618; 619; Define macro to release spin lock. 620; 621; Arguments: 622; 623; None. 624; 625; N.B. This macro uses no registers. 626; 627 628ReleaseSpinLock macro Address 629 630ifndef NT_UP 631 632 lock and qword ptr Address, 0 ; release spin lock 633 634endif 635 636 endm 637 638; 639; Define macro to release spin lock and restore the interrupt flag. 640; 641; Arguments: 642; 643; None. 644; 645; Note: 646; 647; rsp is assumed to point to pushd EFLAGS 648; 649; N.B. This macro uses no registers. 650; 651 652ReleaseSpinLockEnable macro Address 653 654 local exit 655 656ifndef NT_UP 657 658 lock and qword ptr Address, 0 ; release spin lock 659 660endif 661 662 test dword ptr [rsp], EFLAGS_IF_MASK ; test if interrupts enabled 663 jz short exit ; if z, interrupts not enabled 664 sti ; enable interrupts 665exit: ; continue 666 667 endm 668 669; 670; Define macro to try to acquire spin lock. 671; 672; Arguments: 673; 674; None. 675; 676; N.B. This macro uses no registers. 677; 678 679TryToAcquireSpinLock macro Address 680 681ifndef NT_UP 682 683 lock bts qword ptr Address, 0 ; attempt to acquire spin lock 684 685endif 686 687 endm 688 689; 690; Define macro to perform the equivalent of reading cr8. 691; 692; Arguments: 693; 694; None 695; 696; The equivalent of the contents of cr8 is returned in rax 697; 698; N.B. This macro is restricted to using only rax. 699; 700 701ReadCr8 macro 702 703 mov rax, cr8 ; read IRQL 704 705 endm 706 707; 708; Define macro to perform the equivalent of writing cr8. 709; 710; Arguments: 711; 712; rcx - The desired value of cr8. 713; 714 715WriteCr8 macro 716 717 mov cr8, rcx ; write IRQL 718 719 endm 720 721; 722; Define macro to get current IRQL. 723; 724; Arguments: 725; 726; None. 727; 728; The previous IRQL is returned in rax. 729; 730 731CurrentIrql macro 732 733 ReadCr8 ; get current IRQL 734 735 endm 736 737; 738; Define macro to lower IRQL. 739; 740; Arguments: 741; 742; rcx - Supplies the new IRQL. 743; 744; N.B. The register rax is destroyed. 745; 746; N.B. This macro is restricted to using only rcx and rdx. 747; 748 749LowerIrql macro 750 751 local exit 752 753if DBG 754 755 mov rdx, rax ; preserve rax 756 ReadCr8 ; get current IRQL 757 cmp eax, ecx ; check new IRQL 758 jge short exit ; if ge, new IRQL okay 759 int 3 ; break into debugger 760exit: mov rax, rdx 761 762endif 763 764 WriteCr8 ; set new IRQL 765 766 endm 767 768; 769; Define macro to raise IRQL. 770; 771; Arguments: 772; 773; rcx - Supplies the new IRQL. 774; 775; The previous IRQL is returned in rax. 776; 777; N.B. This macro is restricted to using only rax and rcx. 778; 779 780RaiseIrql macro 781 782 local exit 783 784 ReadCr8 ; get current IRQL 785 786if DBG 787 788 cmp eax, ecx ; check new IRQL 789 jle short exit ; if le, new IRQL okay 790 int 3 ; break into debugger 791 792endif 793 794exit: WriteCr8 ; set new IRQL 795 796 endm 797 798; 799; Define macro to set IRQL. 800; 801; Arguments: 802; 803; rcx - Supplies the new IRQL. 804; 805; N.B. This macro is restricted to using only rcx. 806; 807 808SetIrql macro 809 810 WriteCr8 ; set new IRQL 811 812 endm 813 814; 815; Define macro to swap IRQL. 816; 817; Arguments: 818; 819; rcx - Supplies the new IRQL. 820; 821; The previous IRQL is returned in rax. 822; 823; N.B. This macro is restricted to using only rax and rcx. 824; 825 826SwapIrql macro 827 828 ReadCr8 ; get current IRQL 829 WriteCr8 ; set new IRQL 830 831 endm 832 833; 834; 835 836; 837; Define restore exception state macro. 838; 839; This macro restores the nonvolatile state. 840; 841; Arguments: 842; 843; Flag - If blank, then nonvolatile floating and integer registers are 844; restored. If nonblank and identical to "Rbp", then rbp is restored 845; in addition to the nonvolatile floating and integer registers. If 846; nonblank and identical to "NoFp", then only the nonvolatile integer 847; registers are restored. 848; 849; Implicit arguments: 850; 851; rsp - Supplies the address of the exception frame. 852; 853 854RESTORE_EXCEPTION_STATE macro Flag 855 856 lea rcx, 100h[rsp] ; set frame display pointer 857 858ifdif <Flag>, <NoFp> 859 860 movaps xmm6, ExXmm6[rsp] ; restore nonvolatile xmm registers 861 movaps xmm7, ExXmm7[rsp] ; 862 movaps xmm8, ExXmm8[rsp] ; 863 movaps xmm9, ExXmm9[rsp] ; 864 movaps xmm10, ExXmm10[rsp] ; 865 movaps xmm11, (ExXmm11 - 100h)[rcx] ; 866 movaps xmm12, (ExXmm12 - 100h)[rcx] ; 867 movaps xmm13, (ExXmm13 - 100h)[rcx] ; 868 movaps xmm14, (ExXmm14 - 100h)[rcx] ; 869 movaps xmm15, (ExXmm15 - 100h)[rcx] ; 870 871endif 872 873 mov rbx, (ExRbx - 100h)[rcx] ; restore nonvolatile integer registers 874 mov rdi, (ExRdi - 100h)[rcx] ; 875 mov rsi, (ExRsi - 100h)[rcx] ; 876 mov r12, (ExR12 - 100h)[rcx] ; 877 mov r13, (ExR13 - 100h)[rcx] ; 878 mov r14, (ExR14 - 100h)[rcx] ; 879 mov r15, (ExR15 - 100h)[rcx] ; 880 881ifdif <Flag>, <NoPop> 882 883ifidn <Flag>, <Rbp> 884 885 mov rbp, (ExRbp - 100h)[rcx] ; restore nonvolatile integer register 886 887endif 888 889 add rsp, KEXCEPTION_FRAME_LENGTH - (1 * 8) ; deallocate frame 890 891ifdif <Flag>, <Rbp> 892 893 BEGIN_EPILOGUE 894 895endif 896 897endif 898 899 endm 900 901; 902; Define generate exception frame macro. 903; 904; This macro allocates an exception frame and saves the nonvolatile state. 905; 906; Arguments: 907; 908; Flag - If blank, then nonvolatile floating and integer registers are 909; saved. If nonblank and identical to "Rbp", then rbp is saved in 910; addition to the nonvolatile floating and integer registers. If 911; nonblank and identical to "NoFp", then only the nonvolatile integer 912; registers are saved. If nonblank and identical to "NoPop", then 913; allocate an exception record in addition to an exception frame. If 914; nonblank and identical to "NoFrame", then rbp is saved in addition to 915; the other registers but is not established as a frame pointer. 916; 917; Implicit arguments: 918; 919; The top of the stack is assumed to contain a return address. 920; 921 922GENERATE_EXCEPTION_FRAME macro Flag 923 924 925ifidn <Flag>, <NoPop> 926 927 alloc_stack (EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH - (1 * 8)) ; allocate frame 928 929else 930 931 alloc_stack (KEXCEPTION_FRAME_LENGTH - (1 * 8)) ; allocate frame 932 933endif 934 935 lea rax, 100h[rsp] ; set frame display pointer 936 937ifdif <Flag>, <NoFp> 938 939 save_xmm128 xmm6, ExXmm6 ; save xmm nonvolatile registers 940 save_xmm128 xmm7, ExXmm7 ; 941 save_xmm128 xmm8, ExXmm8 ; 942 save_xmm128 xmm9, ExXmm9 ; 943 save_xmm128 xmm10, ExXmm10 ; 944 945 movaps (ExXmm11 - 100h)[rax], xmm11 ; 946 .savexmm128 xmm11, ExXmm11 ; 947 948 movaps (ExXmm12 - 100h)[rax], xmm12 ; 949 .savexmm128 xmm12, ExXmm12 ; 950 951 movaps (ExXmm13 - 100h)[rax], xmm13 ; 952 .savexmm128 xmm13, ExXmm13 ; 953 954 movaps (ExXmm14 - 100h)[rax], xmm14 ; 955 .savexmm128 xmm14, ExXmm14 ; 956 957 movaps (ExXmm15 - 100h)[rax], xmm15 ; 958 .savexmm128 xmm15, ExXmm15 ; 959 960endif 961 962ifidn <Flag>, <Rbp> 963 964 mov (ExRbp - 100h)[rax], rbp ; save nonvolatile integer register 965 .savereg rbp, ExRbp ; 966 set_frame rbp, 0 ; set frame pointer 967 968endif 969 970ifidn <Flag>, <NoFrame> 971 972 mov (ExRbp - 100h)[rax], rbp ; save nonvolatile integer register 973 .savereg rbp, ExRbp ; 974 975endif 976 977 mov (ExRbx - 100h)[rax], rbx ; 978 .savereg rbx, ExRbx ; 979 980 mov (ExRdi - 100h)[rax], rdi ; 981 .savereg rdi, ExRdi ; 982 983 mov (ExRsi - 100h)[rax], rsi ; 984 .savereg rsi, ExRsi ; 985 986 mov (ExR12 - 100h)[rax], r12 ; 987 .savereg r12, ExR12 ; 988 989 mov (ExR13 - 100h)[rax], r13 ; 990 .savereg r13, ExR13 ; 991 992 mov (ExR14 - 100h)[rax], r14 ; 993 .savereg r14, ExR14 ; 994 995 mov (ExR15 - 100h)[rax], r15 ; 996 .savereg r15, ExR15 ; 997 998 END_PROLOGUE 999 1000 endm 1001 1002; 1003