code *cdsetjmp(elem *e,regm_t *pretregs) { code cs; code *c; regm_t retregs; unsigned stackpushsave; unsigned flag; c = NULL; stackpushsave = stackpush; #if SCPP if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp)) { /* If in C++ try block If the frame that is calling setjmp has a try,catch block then the call to setjmp3 is as follows: __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata); __cpp_longjmp_unwind is a routine in the RTL. This is a stdcall routine that will deal with unwinding for CPP Frames. trylevel is the value that gets incremented at each catch, constructor invocation. funcdata is the same value that you put into EAX prior to cppframehandler getting called. */ symbol *s; s = except_gensym(); if (!s) goto L1; c = gencs(c,0x68,0,FLextern,s); // PUSH &scope_table stackpush += 4; genadjesp(c,4); c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4); // PUSH trylevel stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = rtlsym[RTLSYM_CPP_LONGJMP]; cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_cpp_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 3; } else #endif if (funcsym_p->Sfunc->Fflags3 & Fnteh) { /* If in NT SEH try block If the frame that is calling setjmp has a try, except block then the call to setjmp3 is as follows: __setjmp3(environment,2,__seh_longjmp_unwind,trylevel); __seth_longjmp_unwind is supplied by the RTL and is a stdcall function. It is the name that MSOFT uses, we should probably use the same one. trylevel is the value that you increment at each try and decrement at the close of the try. This corresponds to the index field of the ehrec. */ int sindex_off; sindex_off = 20; // offset of __context.sindex cs.Iop = 0xFF; cs.Irm = modregrm(2,6,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLbprel; cs.IEVsym1 = nteh_contextsym(); cs.IEVoffset1 = sindex_off; c = gen(c,&cs); // PUSH scope_index stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = rtlsym[RTLSYM_LONGJMP]; cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_seh_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 2; } else { /* If the frame calling setjmp has neither a try..except, nor a try..catch, then call setjmp3 as follows: _setjmp3(environment,0) */ L1: flag = 0; } cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = flag; c = gen(c,&cs); // PUSH flag stackpush += 4; genadjesp(c,4); c = cat(c,params(e->E1,REGSIZE)); c = cat(c,getregs(~rtlsym[RTLSYM_SETJMP3]->Sregsaved & (ALLREGS | mES))); gencs(c,0xE8,0,FLfunc,rtlsym[RTLSYM_SETJMP3]); // CALL __setjmp3 c = genc2(c,0x81,modregrm(3,0,SP),stackpush - stackpushsave); // ADD ESP,8 genadjesp(c,-(stackpush - stackpushsave)); stackpush = stackpushsave; retregs = regmask(e->Ety, TYnfunc); return cat(c,fixresult(e,retregs,pretregs)); }
code *nteh_monitor_prolog(Symbol *shandle) { /* * PUSH handle * PUSH offset _d_monitor_handler * PUSH FS:__except_list * MOV FS:__except_list,ESP * CALL _d_monitor_prolog */ code *c1 = NULL; code *c; code cs; Symbol *s; regm_t desregs; assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's if (shandle->Sclass == SCfastpar) { assert(shandle->Spreg != DX); c = gen1(NULL,0x50 + shandle->Spreg); // PUSH shandle } else { // PUSH shandle #if 0 c = genc1(NULL,0xFF,modregrm(2,6,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); c->Isib = modregrm(0,4,SP); #else useregs(mCX); c = genc1(NULL,0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); c->Isib = modregrm(0,4,SP); gen1(c,0x50 + CX); // PUSH ECX #endif } s = rtlsym[RTLSYM_MONITOR_HANDLER]; c = gencs(c,0x68,0,FLextern,s); // PUSH offset _d_monitor_handler makeitextern(s); #if 0 cs.Iop = 0xFF; cs.Irm = modregrm(0,6,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; cs.IEVoffset1 = 0; gen(c,&cs); // PUSH FS:__except_list #else useregs(mDX); cs.Iop = 0x8B; cs.Irm = modregrm(0,DX,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; cs.IEVoffset1 = 0; c1 = gen(c1,&cs); // MOV EDX,FS:__except_list gen1(c,0x50 + DX); // PUSH EDX #endif s = rtlsym[RTLSYM_MONITOR_PROLOG]; desregs = ~s->Sregsaved & ALLREGS; c = cat(c,getregs(desregs)); c = gencs(c,0xE8,0,FLfunc,s); // CALL _d_monitor_prolog cs.Iop = 0x89; NEWREG(cs.Irm,SP); gen(c,&cs); // MOV FS:__except_list,ESP return cat(c1,c); }
code *xmmeq(elem *e, unsigned op, elem *e1, elem *e2,regm_t *pretregs) { tym_t tymll; unsigned reg; int i; code *cl,*cr,*c,cs; elem *e11; bool regvar; /* TRUE means evaluate into register variable */ regm_t varregm; unsigned varreg; targ_int postinc; //printf("xmmeq(e1 = %p, e2 = %p, *pretregs = %s)\n", e1, e2, regm_str(*pretregs)); int e2oper = e2->Eoper; tym_t tyml = tybasic(e1->Ety); /* type of lvalue */ regm_t retregs = *pretregs; if (!(retregs & XMMREGS)) retregs = XMMREGS; // pick any XMM reg cs.Iop = (op == OPeq) ? xmmstore(tyml) : op; regvar = FALSE; varregm = 0; if (config.flags4 & CFG4optimized) { // Be careful of cases like (x = x+x+x). We cannot evaluate in // x if x is in a register. if (isregvar(e1,&varregm,&varreg) && // if lvalue is register variable doinreg(e1->EV.sp.Vsym,e2) // and we can compute directly into it ) { regvar = TRUE; retregs = varregm; reg = varreg; /* evaluate directly in target register */ } } if (*pretregs & mPSW && !EOP(e1)) // if evaluating e1 couldn't change flags { // Be careful that this lines up with jmpopcode() retregs |= mPSW; *pretregs &= ~mPSW; } cr = scodelem(e2,&retregs,0,TRUE); // get rvalue // Look for special case of (*p++ = ...), where p is a register variable if (e1->Eoper == OPind && ((e11 = e1->E1)->Eoper == OPpostinc || e11->Eoper == OPpostdec) && e11->E1->Eoper == OPvar && e11->E1->EV.sp.Vsym->Sfl == FLreg ) { postinc = e11->E2->EV.Vint; if (e11->Eoper == OPpostdec) postinc = -postinc; cl = getlvalue(&cs,e11,RMstore | retregs); freenode(e11->E2); } else { postinc = 0; cl = getlvalue(&cs,e1,RMstore | retregs); // get lvalue (cl == CNIL if regvar) } c = getregs_imm(varregm); reg = findreg(retregs & XMMREGS); cs.Irm |= modregrm(0,(reg - XMM0) & 7,0); if ((reg - XMM0) & 8) cs.Irex |= REX_R; // Do not generate mov from register onto itself if (!(regvar && reg == XMM0 + ((cs.Irm & 7) | (cs.Irex & REX_B ? 8 : 0)))) c = gen(c,&cs); // MOV EA+offset,reg if (e1->Ecount || // if lvalue is a CSE or regvar) // rvalue can't be a CSE { c = cat(c,getregs_imm(retregs)); // necessary if both lvalue and // rvalue are CSEs (since a reg // can hold only one e at a time) cssave(e1,retregs,EOP(e1)); // if lvalue is a CSE } c = cat4(cr,cl,c,fixresult(e,retregs,pretregs)); Lp: if (postinc) { int reg = findreg(idxregm(&cs)); if (*pretregs & mPSW) { // Use LEA to avoid touching the flags unsigned rm = cs.Irm & 7; if (cs.Irex & REX_B) rm |= 8; c = genc1(c,0x8D,buildModregrm(2,reg,rm),FLconst,postinc); if (tysize(e11->E1->Ety) == 8) code_orrex(c, REX_W); } else if (I64) { c = genc2(c,0x81,modregrmx(3,0,reg),postinc); if (tysize(e11->E1->Ety) == 8) code_orrex(c, REX_W); } else { if (postinc == 1) c = gen1(c,0x40 + reg); // INC reg else if (postinc == -(targ_int)1) c = gen1(c,0x48 + reg); // DEC reg else { c = genc2(c,0x81,modregrm(3,0,reg),postinc); } } } freenode(e1); return c; }