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