1 /** 2 * Support for NT exception handling 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 1994-1998 by Symantec 8 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/nteh.d, backend/nteh.d) 12 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/nteh.d 13 */ 14 15 module dmd.backend.nteh; 16 17 import core.stdc.stdio; 18 import core.stdc.string; 19 20 import dmd.backend.cc; 21 import dmd.backend.cdef; 22 import dmd.backend.code; 23 import dmd.backend.code_x86; 24 import dmd.backend.codebuilder : CodeBuilder; 25 import dmd.backend.dt; 26 import dmd.backend.el; 27 import dmd.backend.global; 28 import dmd.backend.oper; 29 import dmd.backend.rtlsym; 30 import dmd.backend.symtab; 31 import dmd.backend.ty; 32 import dmd.backend.type; 33 34 version (SCPP) 35 { 36 import scopeh; 37 } 38 else version (HTOD) 39 { 40 import scopeh; 41 } 42 43 static if (NTEXCEPTIONS) 44 { 45 46 extern (C++): 47 48 nothrow: 49 @safe: 50 51 int REGSIZE(); 52 void except_fillInEHTable(Symbol *s); 53 54 private __gshared 55 { 56 Symbol *s_table; 57 Symbol *s_context; 58 const(char)* s_name_context_tag = "__nt_context"; 59 const(char)* s_name_context = "__context"; 60 const(char)* s_name_ecode = "__ecode"; 61 62 const(char)* text_nt = 63 "struct __nt_context {" ~ 64 "int esp; int info; int prev; int handler; int stable; int sindex; int ebp;" ~ 65 "};\n"; 66 } 67 68 // member stable is not used for MARS or C++ 69 70 int nteh_EBPoffset_sindex() { return -4; } 71 int nteh_EBPoffset_prev() { return -nteh_contextsym_size() + 8; } 72 int nteh_EBPoffset_info() { return -nteh_contextsym_size() + 4; } 73 int nteh_EBPoffset_esp() { return -nteh_contextsym_size() + 0; } 74 75 int nteh_offset_sindex() { version (MARS) { return 16; } else { return 20; } } 76 int nteh_offset_sindex_seh() { return 20; } 77 int nteh_offset_info() { return 4; } 78 79 /*********************************** 80 */ 81 82 @trusted 83 ubyte *nteh_context_string() 84 { 85 if (config.exe == EX_WIN32) 86 return cast(ubyte *)text_nt; 87 else 88 return null; 89 } 90 91 /******************************* 92 * Get symbol for scope table for current function. 93 * Returns: 94 * symbol of table 95 */ 96 97 @trusted 98 private Symbol *nteh_scopetable() 99 { 100 Symbol *s; 101 type *t; 102 103 if (!s_table) 104 { 105 t = type_alloc(TYint); 106 s = symbol_generate(SC.static_,t); 107 s.Sseg = UNKNOWN; 108 symbol_keep(s); 109 s_table = s; 110 } 111 return s_table; 112 } 113 114 /************************************* 115 */ 116 117 @trusted 118 void nteh_filltables() 119 { 120 version (MARS) 121 { 122 Symbol *s = s_table; 123 symbol_debug(s); 124 except_fillInEHTable(s); 125 } 126 } 127 128 /**************************** 129 * Generate and output scope table. 130 * Not called for NTEH C++ exceptions 131 */ 132 133 @trusted 134 void nteh_gentables(Symbol *sfunc) 135 { 136 Symbol *s = s_table; 137 symbol_debug(s); 138 version (MARS) 139 { 140 //except_fillInEHTable(s); 141 } 142 else 143 { 144 /* NTEH table for C. 145 * The table consists of triples: 146 * parent index 147 * filter address 148 * handler address 149 */ 150 uint fsize = 4; // target size of function pointer 151 auto dtb = DtBuilder(0); 152 int sz = 0; // size so far 153 154 foreach (b; BlockRange(startblock)) 155 { 156 if (b.BC == BC_try) 157 { 158 block *bhandler; 159 160 dtb.dword(b.Blast_index); // parent index 161 162 // If try-finally 163 if (b.numSucc() == 2) 164 { 165 dtb.dword(0); // filter address 166 bhandler = b.nthSucc(1); 167 assert(bhandler.BC == BC_finally); 168 // To successor of BC_finally block 169 bhandler = bhandler.nthSucc(0); 170 } 171 else // try-except 172 { 173 bhandler = b.nthSucc(1); 174 assert(bhandler.BC == BC_filter); 175 dtb.coff(bhandler.Boffset); // filter address 176 bhandler = b.nthSucc(2); 177 assert(bhandler.BC == BC_except); 178 } 179 dtb.coff(bhandler.Boffset); // handler address 180 sz += 4 + fsize * 2; 181 } 182 } 183 assert(sz != 0); 184 s.Sdt = dtb.finish(); 185 } 186 187 outdata(s); // output the scope table 188 version (MARS) 189 { 190 nteh_framehandler(sfunc, s); 191 } 192 s_table = null; 193 } 194 195 /************************** 196 * Declare frame variables. 197 */ 198 199 @trusted 200 void nteh_declarvars(Blockx *bx) 201 { 202 Symbol *s; 203 204 //printf("nteh_declarvars()\n"); 205 version (MARS) 206 { 207 if (!(bx.funcsym.Sfunc.Fflags3 & Fnteh)) // if haven't already done it 208 { bx.funcsym.Sfunc.Fflags3 |= Fnteh; 209 s = symbol_name(s_name_context[0 .. strlen(s_name_context)],SC.bprel,tstypes[TYint]); 210 s.Soffset = -5 * 4; // -6 * 4 for C __try, __except, __finally 211 s.Sflags |= SFLfree | SFLnodebug; 212 type_setty(&s.Stype,mTYvolatile | TYint); 213 symbol_add(s); 214 bx.context = s; 215 } 216 } 217 else 218 { 219 if (!(funcsym_p.Sfunc.Fflags3 & Fnteh)) // if haven't already done it 220 { funcsym_p.Sfunc.Fflags3 |= Fnteh; 221 if (!s_context) 222 s_context = scope_search(s_name_context_tag, CPP ? SCTglobal : SCTglobaltag); 223 symbol_debug(s_context); 224 225 s = symbol_name(s_name_context[0 .. strlen(s_name_context)],SC.bprel,s_context.Stype); 226 s.Soffset = -6 * 4; // -5 * 4 for C++ 227 s.Sflags |= SFLfree; 228 symbol_add(s); 229 type_setty(&s.Stype,mTYvolatile | TYstruct); 230 231 s = symbol_name(s_name_ecode[0 .. strlen(s_name_context)],SC.auto_,type_alloc(mTYvolatile | TYint)); 232 s.Sflags |= SFLfree; 233 symbol_add(s); 234 } 235 } 236 } 237 238 /************************************** 239 * Generate elem that sets the context index into the scope table. 240 */ 241 242 version (MARS) 243 { 244 elem *nteh_setScopeTableIndex(Blockx *blx, int scope_index) 245 { 246 elem *e; 247 Symbol *s; 248 249 s = blx.context; 250 symbol_debug(s); 251 e = el_var(s); 252 e.EV.Voffset = nteh_offset_sindex(); 253 return el_bin(OPeq, TYint, e, el_long(TYint, scope_index)); 254 } 255 } 256 257 258 /********************************** 259 * Return pointer to context symbol. 260 */ 261 262 @trusted 263 Symbol *nteh_contextsym() 264 { 265 for (SYMIDX si = 0; 1; si++) 266 { assert(si < globsym.length); 267 Symbol* sp = globsym[si]; 268 symbol_debug(sp); 269 if (strcmp(sp.Sident.ptr,s_name_context) == 0) 270 return sp; 271 } 272 } 273 274 /********************************** 275 * Return size of context symbol on stack. 276 */ 277 @trusted 278 uint nteh_contextsym_size() 279 { 280 int sz; 281 282 if (usednteh & NTEH_try) 283 { 284 version (MARS) 285 { 286 sz = 5 * 4; 287 } 288 else version (SCPP) 289 { 290 sz = 6 * 4; 291 } 292 else version (HTOD) 293 { 294 sz = 6 * 4; 295 } 296 else 297 static assert(0); 298 } 299 else if (usednteh & NTEHcpp) 300 { 301 sz = 5 * 4; // C++ context record 302 } 303 else if (usednteh & NTEHpassthru) 304 { 305 sz = 1 * 4; 306 } 307 else 308 sz = 0; // no context record 309 return sz; 310 } 311 312 /********************************** 313 * Return pointer to ecode symbol. 314 */ 315 316 @trusted 317 Symbol *nteh_ecodesym() 318 { 319 SYMIDX si; 320 Symbol *sp; 321 322 for (si = 0; 1; si++) 323 { assert(si < globsym.length); 324 sp = globsym[si]; 325 symbol_debug(sp); 326 if (strcmp(sp.Sident.ptr, s_name_ecode) == 0) 327 return sp; 328 } 329 } 330 331 /********************************* 332 * Mark EH variables as used so that they don't get optimized away. 333 */ 334 335 void nteh_usevars() 336 { 337 version (SCPP) 338 { 339 // Turn off SFLdead and SFLunambig in Sflags 340 nteh_contextsym().Sflags &= ~(SFLdead | SFLunambig); 341 nteh_contextsym().Sflags |= SFLread; 342 nteh_ecodesym().Sflags &= ~(SFLdead | SFLunambig); 343 nteh_ecodesym().Sflags |= SFLread; 344 } 345 else 346 { 347 // Turn off SFLdead and SFLunambig in Sflags 348 nteh_contextsym().Sflags &= ~SFLdead; 349 nteh_contextsym().Sflags |= SFLread; 350 } 351 } 352 353 /********************************* 354 * Generate NT exception handling function prolog. 355 */ 356 357 @trusted 358 void nteh_prolog(ref CodeBuilder cdb) 359 { 360 code cs; 361 362 if (usednteh & NTEHpassthru) 363 { 364 /* An sindex value of -2 is a magic value that tells the 365 * stack unwinder to skip this frame. 366 */ 367 assert(config.exe & EX_posix); 368 cs.Iop = 0x68; 369 cs.Iflags = 0; 370 cs.Irex = 0; 371 cs.IFL2 = FLconst; 372 cs.IEV2.Vint = -2; 373 cdb.gen(&cs); // PUSH -2 374 return; 375 } 376 377 /* Generate instance of struct __nt_context on stack frame: 378 [ ] // previous ebp already there 379 push -1 // sindex 380 mov EDX,FS:__except_list 381 push offset FLAT:scope_table // stable (not for MARS or C++) 382 push offset FLAT:__except_handler3 // handler 383 push EDX // prev 384 mov FS:__except_list,ESP 385 sub ESP,8 // info, esp for __except support 386 */ 387 388 // useregs(mAX); // What is this for? 389 390 cs.Iop = 0x68; 391 cs.Iflags = 0; 392 cs.Irex = 0; 393 cs.IFL2 = FLconst; 394 cs.IEV2.Vint = -1; 395 cdb.gen(&cs); // PUSH -1 396 397 version (MARS) 398 { 399 // PUSH &framehandler 400 cs.IFL2 = FLframehandler; 401 nteh_scopetable(); 402 } 403 else 404 { 405 if (usednteh & NTEHcpp) 406 { 407 // PUSH &framehandler 408 cs.IFL2 = FLframehandler; 409 } 410 else 411 { 412 // Do stable 413 cs.Iflags |= CFoff; 414 cs.IFL2 = FLextern; 415 cs.IEV2.Vsym = nteh_scopetable(); 416 cs.IEV2.Voffset = 0; 417 cdb.gen(&cs); // PUSH &scope_table 418 419 cs.IFL2 = FLextern; 420 cs.IEV2.Vsym = getRtlsym(RTLSYM.EXCEPT_HANDLER3); 421 makeitextern(getRtlsym(RTLSYM.EXCEPT_HANDLER3)); 422 } 423 } 424 425 CodeBuilder cdb2; 426 cdb2.ctor(); 427 cdb2.gen(&cs); // PUSH &__except_handler3 428 429 if (config.exe == EX_WIN32) 430 { 431 makeitextern(getRtlsym(RTLSYM.EXCEPT_LIST)); 432 static if (0) 433 { 434 cs.Iop = 0xFF; 435 cs.Irm = modregrm(0,6,BPRM); 436 cs.Iflags = CFfs; 437 cs.Irex = 0; 438 cs.IFL1 = FLextern; 439 cs.IEV1.Vsym = getRtlsym(RTLSYM.EXCEPT_LIST); 440 cs.IEV1.Voffset = 0; 441 cdb2.gen(&cs); // PUSH FS:__except_list 442 } 443 else 444 { 445 useregs(mDX); 446 cs.Iop = 0x8B; 447 cs.Irm = modregrm(0,DX,BPRM); 448 cs.Iflags = CFfs; 449 cs.Irex = 0; 450 cs.IFL1 = FLextern; 451 cs.IEV1.Vsym = getRtlsym(RTLSYM.EXCEPT_LIST); 452 cs.IEV1.Voffset = 0; 453 cdb.gen(&cs); // MOV EDX,FS:__except_list 454 455 cdb2.gen1(0x50 + DX); // PUSH EDX 456 } 457 cs.Iop = 0x89; 458 NEWREG(cs.Irm,SP); 459 cdb2.gen(&cs); // MOV FS:__except_list,ESP 460 } 461 462 cdb.append(cdb2); 463 cod3_stackadj(cdb, 8); 464 } 465 466 /********************************* 467 * Generate NT exception handling function epilog. 468 */ 469 470 @trusted 471 void nteh_epilog(ref CodeBuilder cdb) 472 { 473 if (config.exe != EX_WIN32) 474 return; 475 476 /* Generate: 477 mov ECX,__context[EBP].prev 478 mov FS:__except_list,ECX 479 */ 480 code cs; 481 reg_t reg; 482 483 version (MARS) 484 reg = CX; 485 else 486 reg = (tybasic(funcsym_p.Stype.Tnext.Tty) == TYvoid) ? AX : CX; 487 488 useregs(1 << reg); 489 490 cs.Iop = 0x8B; 491 cs.Irm = modregrm(2,reg,BPRM); 492 cs.Iflags = 0; 493 cs.Irex = 0; 494 cs.IFL1 = FLconst; 495 // EBP offset of __context.prev 496 cs.IEV1.Vint = nteh_EBPoffset_prev(); 497 cdb.gen(&cs); 498 499 cs.Iop = 0x89; 500 cs.Irm = modregrm(0,reg,BPRM); 501 cs.Iflags |= CFfs; 502 cs.IFL1 = FLextern; 503 cs.IEV1.Vsym = getRtlsym(RTLSYM.EXCEPT_LIST); 504 cs.IEV1.Voffset = 0; 505 cdb.gen(&cs); 506 } 507 508 /************************** 509 * Set/Reset ESP from context. 510 */ 511 512 @trusted 513 void nteh_setsp(ref CodeBuilder cdb, opcode_t op) 514 { 515 code cs; 516 cs.Iop = op; 517 cs.Irm = modregrm(2,SP,BPRM); 518 cs.Iflags = 0; 519 cs.Irex = 0; 520 cs.IFL1 = FLconst; 521 // EBP offset of __context.esp 522 cs.IEV1.Vint = nteh_EBPoffset_esp(); 523 cdb.gen(&cs); // MOV ESP,__context[EBP].esp 524 } 525 526 /**************************** 527 * Put out prolog for BC_filter block. 528 */ 529 530 @trusted 531 void nteh_filter(ref CodeBuilder cdb, block *b) 532 { 533 code cs; 534 535 assert(b.BC == BC_filter); 536 if (b.Bflags & BFLehcode) // if referenced __ecode 537 { 538 /* Generate: 539 mov EAX,__context[EBP].info 540 mov EAX,[EAX] 541 mov EAX,[EAX] 542 mov __ecode[EBP],EAX 543 */ 544 545 getregs(cdb,mAX); 546 547 cs.Iop = 0x8B; 548 cs.Irm = modregrm(2,AX,BPRM); 549 cs.Iflags = 0; 550 cs.Irex = 0; 551 cs.IFL1 = FLconst; 552 // EBP offset of __context.info 553 cs.IEV1.Vint = nteh_EBPoffset_info(); 554 cdb.gen(&cs); // MOV EAX,__context[EBP].info 555 556 cs.Irm = modregrm(0,AX,0); 557 cdb.gen(&cs); // MOV EAX,[EAX] 558 cdb.gen(&cs); // MOV EAX,[EAX] 559 560 cs.Iop = 0x89; 561 cs.Irm = modregrm(2,AX,BPRM); 562 cs.IFL1 = FLauto; 563 cs.IEV1.Vsym = nteh_ecodesym(); 564 cs.IEV1.Voffset = 0; 565 cdb.gen(&cs); // MOV __ecode[EBP],EAX 566 } 567 } 568 569 /******************************* 570 * Generate C++ or D frame handler. 571 */ 572 573 void nteh_framehandler(Symbol *sfunc, Symbol *scopetable) 574 { 575 // Generate: 576 // MOV EAX,&scope_table 577 // JMP __cpp_framehandler 578 579 if (scopetable) 580 { 581 symbol_debug(scopetable); 582 CodeBuilder cdb; 583 cdb.ctor(); 584 cdb.gencs(0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table 585 586 version (MARS) 587 cdb.gencs(0xE9,0,FLfunc,getRtlsym(RTLSYM.D_HANDLER)); // JMP _d_framehandler 588 else 589 cdb.gencs(0xE9,0,FLfunc,getRtlsym(RTLSYM.CPP_HANDLER)); // JMP __cpp_framehandler 590 591 code *c = cdb.finish(); 592 pinholeopt(c,null); 593 codout(sfunc.Sseg,c,null); 594 code_free(c); 595 } 596 } 597 598 /********************************* 599 * Generate code to set scope index. 600 */ 601 602 code *nteh_patchindex(code* c, int sindex) 603 { 604 c.IEV2.Vsize_t = sindex; 605 return c; 606 } 607 608 @trusted 609 void nteh_gensindex(ref CodeBuilder cdb, int sindex) 610 { 611 if (!(config.ehmethod == EHmethod.EH_WIN32 || config.ehmethod == EHmethod.EH_SEH) || funcsym_p.Sfunc.Fflags3 & Feh_none) 612 return; 613 // Generate: 614 // MOV -4[EBP],sindex 615 616 cdb.genc(0xC7,modregrm(1,0,BP),FLconst,cast(targ_uns)nteh_EBPoffset_sindex(),FLconst,sindex); // 7 bytes long 617 cdb.last().Iflags |= CFvolatile; 618 619 //assert(GENSINDEXSIZE == calccodsize(c)); 620 } 621 622 /********************************* 623 * Generate code for setjmp(). 624 */ 625 626 @trusted 627 void cdsetjmp(ref CodeBuilder cdb, elem *e,regm_t *pretregs) 628 { 629 code cs; 630 regm_t retregs; 631 uint stackpushsave; 632 uint flag; 633 634 stackpushsave = stackpush; 635 version (SCPP) 636 { 637 if (CPP && (funcsym_p.Sfunc.Fflags3 & Fcppeh || usednteh & NTEHcpp)) 638 { 639 /* If in C++ try block 640 If the frame that is calling setjmp has a try,catch block then 641 the call to setjmp3 is as follows: 642 __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata); 643 644 __cpp_longjmp_unwind is a routine in the RTL. This is a 645 stdcall routine that will deal with unwinding for CPP Frames. 646 trylevel is the value that gets incremented at each catch, 647 constructor invocation. 648 funcdata is the same value that you put into EAX prior to 649 cppframehandler getting called. 650 */ 651 Symbol *s; 652 653 s = except_gensym(); 654 if (!s) 655 goto L1; 656 657 cdb.gencs(0x68,0,FLextern,s); // PUSH &scope_table 658 stackpush += 4; 659 cdb.genadjesp(4); 660 661 cdb.genc1(0xFF,modregrm(1,6,BP),FLconst,cast(targ_uns)-4); 662 // PUSH trylevel 663 stackpush += 4; 664 cdb.genadjesp(4); 665 666 cs.Iop = 0x68; 667 cs.Iflags = CFoff; 668 cs.Irex = 0; 669 cs.IFL2 = FLextern; 670 cs.IEV2.Vsym = getRtlsym(RTLSYM.CPP_LONGJMP); 671 cs.IEV2.Voffset = 0; 672 cdb.gen(&cs); // PUSH &_cpp_longjmp_unwind 673 stackpush += 4; 674 cdb.genadjesp(4); 675 676 flag = 3; 677 goto L2; 678 } 679 } 680 if (funcsym_p.Sfunc.Fflags3 & Fnteh) 681 { 682 /* If in NT SEH try block 683 If the frame that is calling setjmp has a try, except block 684 then the call to setjmp3 is as follows: 685 __setjmp3(environment,2,__seh_longjmp_unwind,trylevel); 686 __seth_longjmp_unwind is supplied by the RTL and is a stdcall 687 function. It is the name that MSOFT uses, we should 688 probably use the same one. 689 trylevel is the value that you increment at each try and 690 decrement at the close of the try. This corresponds to the 691 index field of the ehrec. 692 */ 693 int sindex_off; 694 695 sindex_off = 20; // offset of __context.sindex 696 cs.Iop = 0xFF; 697 cs.Irm = modregrm(2,6,BPRM); 698 cs.Iflags = 0; 699 cs.Irex = 0; 700 cs.IFL1 = FLbprel; 701 cs.IEV1.Vsym = nteh_contextsym(); 702 cs.IEV1.Voffset = sindex_off; 703 cdb.gen(&cs); // PUSH scope_index 704 stackpush += 4; 705 cdb.genadjesp(4); 706 707 cs.Iop = 0x68; 708 cs.Iflags = CFoff; 709 cs.Irex = 0; 710 cs.IFL2 = FLextern; 711 cs.IEV2.Vsym = getRtlsym(RTLSYM.LONGJMP); 712 cs.IEV2.Voffset = 0; 713 cdb.gen(&cs); // PUSH &_seh_longjmp_unwind 714 stackpush += 4; 715 cdb.genadjesp(4); 716 717 flag = 2; 718 } 719 else 720 { 721 /* If the frame calling setjmp has neither a try..except, nor a 722 try..catch, then call setjmp3 as follows: 723 _setjmp3(environment,0) 724 */ 725 L1: 726 flag = 0; 727 } 728 L2: 729 cs.Iop = 0x68; 730 cs.Iflags = 0; 731 cs.Irex = 0; 732 cs.IFL2 = FLconst; 733 cs.IEV2.Vint = flag; 734 cdb.gen(&cs); // PUSH flag 735 stackpush += 4; 736 cdb.genadjesp(4); 737 738 pushParams(cdb,e.EV.E1,REGSIZE, TYnfunc); 739 740 getregs(cdb,~getRtlsym(RTLSYM.SETJMP3).Sregsaved & (ALLREGS | mES)); 741 cdb.gencs(0xE8,0,FLfunc,getRtlsym(RTLSYM.SETJMP3)); // CALL __setjmp3 742 743 cod3_stackadj(cdb, -(stackpush - stackpushsave)); 744 cdb.genadjesp(-(stackpush - stackpushsave)); 745 746 stackpush = stackpushsave; 747 retregs = regmask(e.Ety, TYnfunc); 748 fixresult(cdb,e,retregs,pretregs); 749 } 750 751 /**************************************** 752 * Call _local_unwind(), which means call the __finally blocks until 753 * stop_index is reached. 754 * Params: 755 * cdb = append generated code to 756 * saveregs = registers to save across the generated code 757 * stop_index = index to stop at 758 */ 759 760 @trusted 761 void nteh_unwind(ref CodeBuilder cdb,regm_t saveregs,uint stop_index) 762 { 763 // Shouldn't this always be CX? 764 version (SCPP) 765 const reg_t reg = AX; 766 else 767 const reg_t reg = CX; 768 769 version (MARS) 770 // https://github.com/dlang/dmd/blob/cdfadf8a18f474e6a1b8352af2541efe3e3467cc/druntime/src/rt/deh_win32.d#L934 771 const local_unwind = RTLSYM.D_LOCAL_UNWIND2; // __d_local_unwind2() 772 else 773 // dm/src/win32/ehsup.c 774 const local_unwind = RTLSYM.LOCAL_UNWIND2; // __local_unwind2() 775 776 const regm_t desregs = (~getRtlsym(local_unwind).Sregsaved & (ALLREGS)) | (1 << reg); 777 CodeBuilder cdbs; 778 cdbs.ctor(); 779 CodeBuilder cdbr; 780 cdbr.ctor(); 781 gensaverestore(saveregs & desregs,cdbs,cdbr); 782 783 CodeBuilder cdbx; 784 cdbx.ctor(); 785 getregs(cdbx,desregs); 786 787 code cs; 788 cs.Iop = LEA; 789 cs.Irm = modregrm(2,reg,BPRM); 790 cs.Iflags = 0; 791 cs.Irex = 0; 792 cs.IFL1 = FLconst; 793 // EBP offset of __context.prev 794 cs.IEV1.Vint = nteh_EBPoffset_prev(); 795 cdbx.gen(&cs); // LEA ECX,contextsym 796 797 int nargs = 0; 798 version (SCPP) 799 { 800 const int take_addr = 1; 801 cdbx.genc2(0x68,0,take_addr); // PUSH take_addr 802 ++nargs; 803 } 804 805 cdbx.genc2(0x68,0,stop_index); // PUSH stop_index 806 cdbx.gen1(0x50 + reg); // PUSH ECX ; DEstablisherFrame 807 nargs += 2; 808 version (MARS) 809 { 810 cdbx.gencs(0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table ; DHandlerTable 811 ++nargs; 812 } 813 814 cdbx.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL _local_unwind() 815 cod3_stackadj(cdbx, -nargs * 4); 816 817 cdb.append(cdbs); 818 cdb.append(cdbx); 819 cdb.append(cdbr); 820 } 821 822 /************************************************* 823 * Set monitor, hook monitor exception handler. 824 */ 825 826 version (MARS) 827 { 828 @trusted 829 void nteh_monitor_prolog(ref CodeBuilder cdb, Symbol *shandle) 830 { 831 /* 832 * PUSH handle 833 * PUSH offset _d_monitor_handler 834 * PUSH FS:__except_list 835 * MOV FS:__except_list,ESP 836 * CALL _d_monitor_prolog 837 */ 838 CodeBuilder cdbx; 839 cdbx.ctor(); 840 841 assert(config.exe == EX_WIN32); // BUG: figure out how to implement for other EX's 842 843 if (shandle.Sclass == SC.fastpar) 844 { assert(shandle.Spreg != DX); 845 assert(shandle.Spreg2 == NOREG); 846 cdbx.gen1(0x50 + shandle.Spreg); // PUSH shandle 847 } 848 else 849 { 850 // PUSH shandle 851 useregs(mCX); 852 cdbx.genc1(0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle.Soffset + localsize); 853 cdbx.last().Isib = modregrm(0,4,SP); 854 cdbx.gen1(0x50 + CX); // PUSH ECX 855 } 856 857 Symbol *smh = getRtlsym(RTLSYM.MONITOR_HANDLER); 858 cdbx.gencs(0x68,0,FLextern,smh); // PUSH offset _d_monitor_handler 859 makeitextern(smh); 860 861 code cs; 862 useregs(mDX); 863 cs.Iop = 0x8B; 864 cs.Irm = modregrm(0,DX,BPRM); 865 cs.Iflags = CFfs; 866 cs.Irex = 0; 867 cs.IFL1 = FLextern; 868 cs.IEV1.Vsym = getRtlsym(RTLSYM.EXCEPT_LIST); 869 cs.IEV1.Voffset = 0; 870 cdb.gen(&cs); // MOV EDX,FS:__except_list 871 872 cdbx.gen1(0x50 + DX); // PUSH EDX 873 874 Symbol *s = getRtlsym(RTLSYM.MONITOR_PROLOG); 875 regm_t desregs = ~s.Sregsaved & ALLREGS; 876 getregs(cdbx,desregs); 877 cdbx.gencs(0xE8,0,FLfunc,s); // CALL _d_monitor_prolog 878 879 cs.Iop = 0x89; 880 NEWREG(cs.Irm,SP); 881 cdbx.gen(&cs); // MOV FS:__except_list,ESP 882 883 cdb.append(cdbx); 884 } 885 886 } 887 888 /************************************************* 889 * Release monitor, unhook monitor exception handler. 890 * Input: 891 * retregs registers to not destroy 892 */ 893 894 version (MARS) 895 { 896 897 @trusted 898 void nteh_monitor_epilog(ref CodeBuilder cdb,regm_t retregs) 899 { 900 /* 901 * CALL _d_monitor_epilog 902 * POP FS:__except_list 903 */ 904 905 assert(config.exe == EX_WIN32); // BUG: figure out how to implement for other EX's 906 907 Symbol *s = getRtlsym(RTLSYM.MONITOR_EPILOG); 908 //desregs = ~s.Sregsaved & ALLREGS; 909 regm_t desregs = 0; 910 CodeBuilder cdbs; 911 cdbs.ctor(); 912 CodeBuilder cdbr; 913 cdbr.ctor(); 914 gensaverestore(retregs& desregs,cdbs,cdbr); 915 cdb.append(cdbs); 916 917 getregs(cdb,desregs); 918 cdb.gencs(0xE8,0,FLfunc,s); // CALL __d_monitor_epilog 919 920 cdb.append(cdbr); 921 922 code cs; 923 cs.Iop = 0x8F; 924 cs.Irm = modregrm(0,0,BPRM); 925 cs.Iflags = CFfs; 926 cs.Irex = 0; 927 cs.IFL1 = FLextern; 928 cs.IEV1.Vsym = getRtlsym(RTLSYM.EXCEPT_LIST); 929 cs.IEV1.Voffset = 0; 930 cdb.gen(&cs); // POP FS:__except_list 931 } 932 933 } 934 935 }