Files
ldc/backend/nteh.c
Alexey Prokhin caad8cde58 Squashed 'dmd2/' content from commit 10017d5
git-subtree-dir: dmd2
git-subtree-split: 10017d50eaaff4ecdc37a0153b6c37ea0b004c81
2012-04-05 11:10:48 +04:00

916 lines
23 KiB
C

// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
// Support for NT exception handling
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "el.h"
#include "code.h"
#include "oper.h"
#include "global.h"
#include "type.h"
#include "dt.h"
#if SCPP
#include "scope.h"
#endif
#include "exh.h"
#if !SPP && NTEXCEPTIONS
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
static symbol *s_table;
static symbol *s_context;
static char s_name_context_tag[] = "__nt_context";
static char s_name_context[] = "__context";
static char s_name_ecode[] = "__ecode";
static char text_nt[] =
"struct __nt_context {"
"int esp; int info; int prev; int handler; int stable; int sindex; int ebp;"
"};\n";
// member stable is not used for MARS or C++
int nteh_EBPoffset_sindex() { return -4; }
int nteh_EBPoffset_prev() { return -nteh_contextsym_size() + 8; }
int nteh_EBPoffset_info() { return -nteh_contextsym_size() + 4; }
int nteh_EBPoffset_esp() { return -nteh_contextsym_size() + 0; }
int nteh_offset_sindex() { return MARS ? 16 : 20; }
int nteh_offset_sindex_seh() { return 20; }
int nteh_offset_info() { return 4; }
/***********************************
*/
unsigned char *nteh_context_string()
{
if (config.flags2 & CFG2seh)
return (unsigned char *)text_nt;
else
return NULL;
}
/*******************************
* Get symbol for scope table for current function.
* Returns:
* symbol of table
*/
STATIC symbol *nteh_scopetable()
{ symbol *s;
type *t;
if (!s_table)
{
t = type_alloc(TYint);
s = symbol_generate(SCstatic,t);
s->Sseg = UNKNOWN;
symbol_keep(s);
s_table = s;
}
return s_table;
}
/*************************************
*/
void nteh_filltables()
{
#if MARS
symbol *s = s_table;
symbol_debug(s);
except_fillInEHTable(s);
#endif
}
/****************************
* Generate and output scope table.
* Not called for NTEH C++ exceptions
*/
void nteh_gentables()
{
symbol *s = s_table;
symbol_debug(s);
#if MARS
//except_fillInEHTable(s);
#else
/* NTEH table for C.
* The table consists of triples:
* parent index
* filter address
* handler address
*/
unsigned fsize = 4; // target size of function pointer
dt_t **pdt = &s->Sdt;
int sz = 0; // size so far
for (block *b = startblock; b; b = b->Bnext)
{
if (b->BC == BC_try)
{ dt_t *dt;
block *bhandler;
pdt = dtdword(pdt,b->Blast_index); // parent index
// If try-finally
if (list_nitems(b->Bsucc) == 2)
{
pdt = dtdword(pdt,0); // filter address
bhandler = list_block(list_next(b->Bsucc));
assert(bhandler->BC == BC_finally);
// To successor of BC_finally block
bhandler = list_block(bhandler->Bsucc);
}
else // try-except
{
bhandler = list_block(list_next(b->Bsucc));
assert(bhandler->BC == BC_filter);
pdt = dtcoff(pdt,bhandler->Boffset); // filter address
bhandler = list_block(list_next(list_next(b->Bsucc)));
assert(bhandler->BC == BC_except);
}
pdt = dtcoff(pdt,bhandler->Boffset); // handler address
sz += 4 + fsize * 2;
}
}
assert(sz != 0);
#endif
outdata(s); // output the scope table
#if MARS
nteh_framehandler(s);
#endif
s_table = NULL;
}
/**************************
* Declare frame variables.
*/
void nteh_declarvars(Blockx *bx)
{ symbol *s;
//printf("nteh_declarvars()\n");
#if MARS
if (!(bx->funcsym->Sfunc->Fflags3 & Fnteh)) // if haven't already done it
{ bx->funcsym->Sfunc->Fflags3 |= Fnteh;
s = symbol_name(s_name_context,SCbprel,tsint);
s->Soffset = -5 * 4; // -6 * 4 for C __try, __except, __finally
s->Sflags |= SFLfree | SFLnodebug;
type_setty(&s->Stype,mTYvolatile | TYint);
symbol_add(s);
bx->context = s;
}
#else
if (!(funcsym_p->Sfunc->Fflags3 & Fnteh)) // if haven't already done it
{ funcsym_p->Sfunc->Fflags3 |= Fnteh;
if (!s_context)
s_context = scope_search(s_name_context_tag,CPP ? SCTglobal : SCTglobaltag);
symbol_debug(s_context);
s = symbol_name(s_name_context,SCbprel,s_context->Stype);
s->Soffset = -6 * 4; // -5 * 4 for C++
s->Sflags |= SFLfree;
symbol_add(s);
type_setty(&s->Stype,mTYvolatile | TYstruct);
s = symbol_name(s_name_ecode,SCauto,type_alloc(mTYvolatile | TYint));
s->Sflags |= SFLfree;
symbol_add(s);
}
#endif
}
/**************************************
* Generate elem that sets the context index into the scope table.
*/
#if MARS
elem *nteh_setScopeTableIndex(Blockx *blx, int scope_index)
{
elem *e;
Symbol *s;
s = blx->context;
symbol_debug(s);
e = el_var(s);
e->EV.sp.Voffset = nteh_offset_sindex();
return el_bin(OPeq, TYint, e, el_long(TYint, scope_index));
}
#endif
/**********************************
* Return pointer to context symbol.
*/
symbol *nteh_contextsym()
{ SYMIDX si;
symbol *sp;
for (si = 0; 1; si++)
{ assert(si < globsym.top);
sp = globsym.tab[si];
symbol_debug(sp);
if (strcmp(sp->Sident,s_name_context) == 0)
return sp;
}
}
/**********************************
* Return size of context symbol on stack.
*/
unsigned nteh_contextsym_size()
{ int sz;
if (usednteh & NTEH_try)
{
#if MARS
sz = 5 * 4;
#elif SCPP
sz = 6 * 4;
#else
assert(0);
#endif
assert(usedalloca != 1);
}
else if (usednteh & NTEHcpp)
{ sz = 5 * 4; // C++ context record
assert(usedalloca != 1);
}
else if (usednteh & NTEHpassthru)
{ sz = 1 * 4;
}
else
sz = 0; // no context record
return sz;
}
/**********************************
* Return pointer to ecode symbol.
*/
symbol *nteh_ecodesym()
{ SYMIDX si;
symbol *sp;
for (si = 0; 1; si++)
{ assert(si < globsym.top);
sp = globsym.tab[si];
symbol_debug(sp);
if (strcmp(sp->Sident,s_name_ecode) == 0)
return sp;
}
}
/*********************************
* Mark EH variables as used so that they don't get optimized away.
*/
void nteh_usevars()
{
#if SCPP
// Turn off SFLdead and SFLunambig in Sflags
nteh_contextsym()->Sflags &= ~(SFLdead | SFLunambig);
nteh_contextsym()->Sflags |= SFLread;
nteh_ecodesym()->Sflags &= ~(SFLdead | SFLunambig);
nteh_ecodesym()->Sflags |= SFLread;
#else
// Turn off SFLdead and SFLunambig in Sflags
nteh_contextsym()->Sflags &= ~SFLdead;
nteh_contextsym()->Sflags |= SFLread;
#endif
}
/*********************************
* Generate NT exception handling function prolog.
*/
code *nteh_prolog()
{
code cs;
code *c1;
code *c;
if (usednteh & NTEHpassthru)
{
/* An sindex value of -2 is a magic value that tells the
* stack unwinder to skip this frame.
*/
assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64));
cs.Iop = 0x68;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL2 = FLconst;
cs.IEV2.Vint = -2;
return gen(CNIL,&cs); // PUSH -2
}
/* Generate instance of struct __nt_context on stack frame:
[ ] // previous ebp already there
push -1 // sindex
mov EDX,FS:__except_list
push offset FLAT:scope_table // stable (not for MARS or C++)
push offset FLAT:__except_handler3 // handler
push EDX // prev
mov FS:__except_list,ESP
sub ESP,8 // info, esp for __except support
*/
// useregs(mAX); // What is this for?
cs.Iop = 0x68;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL2 = FLconst;
cs.IEV2.Vint = -1;
c1 = gen(CNIL,&cs); // PUSH -1
if (usednteh & NTEHcpp || MARS)
{
// PUSH &framehandler
cs.IFL2 = FLframehandler;
#if MARS
nteh_scopetable();
#endif
}
else
{
// Do stable
cs.Iflags |= CFoff;
cs.IFL2 = FLextern;
cs.IEVsym2 = nteh_scopetable();
cs.IEVoffset2 = 0;
c1 = gen(c1,&cs); // PUSH &scope_table
cs.IFL2 = FLextern;
cs.IEVsym2 = rtlsym[RTLSYM_EXCEPT_HANDLER3];
makeitextern(rtlsym[RTLSYM_EXCEPT_HANDLER3]);
}
c = gen(NULL,&cs); // PUSH &__except_handler3
if (config.exe == EX_NT)
{
makeitextern(rtlsym[RTLSYM_EXCEPT_LIST]);
#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;
gen(c1,&cs); // MOV EDX,FS:__except_list
gen1(c,0x50 + DX); // PUSH EDX
#endif
cs.Iop = 0x89;
NEWREG(cs.Irm,SP);
gen(c,&cs); // MOV FS:__except_list,ESP
}
c = genc2(c,0x81,modregrm(3,5,SP),8); // SUB ESP,8
return cat(c1,c);
}
/*********************************
* Generate NT exception handling function epilog.
*/
code *nteh_epilog()
{
if (!(config.flags2 & CFG2seh))
return NULL;
/* Generate:
mov ECX,__context[EBP].prev
mov FS:__except_list,ECX
*/
code cs;
code *c;
unsigned reg;
#if MARS
reg = CX;
#else
reg = (tybasic(funcsym_p->Stype->Tnext->Tty) == TYvoid) ? AX : CX;
#endif
useregs(mask[reg]);
cs.Iop = 0x8B;
cs.Irm = modregrm(2,reg,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.prev
cs.IEV1.Vint = nteh_EBPoffset_prev();
c = gen(CNIL,&cs);
cs.Iop = 0x89;
cs.Irm = modregrm(0,reg,BPRM);
cs.Iflags |= CFfs;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
return gen(c,&cs);
}
/**************************
* Set/Reset ESP from context.
*/
code *nteh_setsp(int op)
{ code cs;
cs.Iop = op;
cs.Irm = modregrm(2,SP,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.esp
cs.IEV1.Vint = nteh_EBPoffset_esp();
return gen(CNIL,&cs); // MOV ESP,__context[EBP].esp
}
/****************************
* Put out prolog for BC_filter block.
*/
code *nteh_filter(block *b)
{ code *c;
code cs;
assert(b->BC == BC_filter);
c = CNIL;
if (b->Bflags & BFLehcode) // if referenced __ecode
{
/* Generate:
mov EAX,__context[EBP].info
mov EAX,[EAX]
mov EAX,[EAX]
mov __ecode[EBP],EAX
*/
c = getregs(mAX);
cs.Iop = 0x8B;
cs.Irm = modregrm(2,AX,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.info
cs.IEV1.Vint = nteh_EBPoffset_info();
c = gen(c,&cs); // MOV EAX,__context[EBP].info
cs.Irm = modregrm(0,AX,0);
gen(c,&cs); // MOV EAX,[EAX]
gen(c,&cs); // MOV EAX,[EAX]
cs.Iop = 0x89;
cs.Irm = modregrm(2,AX,BPRM);
cs.IFL1 = FLauto;
cs.IEVsym1 = nteh_ecodesym();
cs.IEVoffset1 = 0;
gen(c,&cs); // MOV __ecode[EBP],EAX
}
return c;
}
/*******************************
* Generate C++ or D frame handler.
*/
void nteh_framehandler(symbol *scopetable)
{ code *c;
// Generate:
// MOV EAX,&scope_table
// JMP __cpp_framehandler
if (scopetable)
{
symbol_debug(scopetable);
c = gencs(NULL,0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table
gencs(c,0xE9,0,FLfunc,rtlsym[RTLSYM_CPP_HANDLER]); // JMP __cpp_framehandler
pinholeopt(c,NULL);
codout(c);
code_free(c);
}
}
/*********************************
* Generate code to set scope index.
*/
code *nteh_gensindex(int sindex)
{ code *c;
if (!(config.flags2 & CFG2seh))
return NULL;
// Generate:
// MOV -4[EBP],sindex
c = genc(NULL,0xC7,modregrm(1,0,BP),FLconst,(targ_uns)nteh_EBPoffset_sindex(),FLconst,sindex); // 7 bytes long
c->Iflags |= CFvolatile;
#ifdef DEBUG
//assert(GENSINDEXSIZE == calccodsize(c));
#endif
return c;
}
/*********************************
* Generate code for setjmp().
*/
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));
}
/****************************************
* Call _local_unwind(), which means call the __finally blocks until
* index is reached.
*/
code *nteh_unwind(regm_t retregs,unsigned index)
{ code *c;
code cs;
code *cs1;
code *cs2;
regm_t desregs;
int reg;
int local_unwind;
// Shouldn't this always be CX?
#if SCPP
reg = AX;
#else
reg = CX;
#endif
#if MARS
local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
cs.Iop = 0x8D;
cs.Irm = modregrm(2,reg,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.prev
cs.IEV1.Vint = nteh_EBPoffset_prev();
c = gen(c,&cs); // LEA ECX,contextsym
genc2(c,0x68,0,index); // PUSH index
gen1(c,0x50 + reg); // PUSH ECX
#if MARS
//gencs(c,0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table
gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),12); // ADD ESP,12
#else
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8
#endif
c = cat4(cs1,c,cs2,NULL);
return c;
}
/****************************************
* Call _local_unwind(), which means call the __finally blocks until
* index is reached.
*/
#if 0 // Replaced with inline calls to __finally blocks
code *linux_unwind(regm_t retregs,unsigned index)
{ code *c;
code *cs1;
code *cs2;
int i;
regm_t desregs;
int reg;
int local_unwind;
// Shouldn't this always be CX?
#if SCPP
reg = AX;
#else
reg = CX;
#endif
#if MARS
local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
c = genc2(c,0x68,0,index); // PUSH index
#if MARS
// gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),4); // ADD ESP,12
#else
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8
#endif
c = cat4(cs1,c,cs2,NULL);
return c;
}
#endif
/*************************************************
* Set monitor, hook monitor exception handler.
*/
#if MARS
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);
}
#endif
/*************************************************
* Release monitor, unhook monitor exception handler.
* Input:
* retregs registers to not destroy
*/
#if MARS
code *nteh_monitor_epilog(regm_t retregs)
{
/*
* CALL _d_monitor_epilog
* POP FS:__except_list
*/
code cs;
code *c;
code *cs1;
code *cs2;
code *cpop;
regm_t desregs;
Symbol *s;
assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's
s = rtlsym[RTLSYM_MONITOR_EPILOG];
//desregs = ~s->Sregsaved & ALLREGS;
desregs = 0;
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
c = gencs(c,0xE8,0,FLfunc,s); // CALL __d_monitor_epilog
cs.Iop = 0x8F;
cs.Irm = modregrm(0,0,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
cpop = gen(NULL,&cs); // POP FS:__except_list
c = cat4(cs1,c,cs2,cpop);
return c;
}
#endif
#endif