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