diff options
Diffstat (limited to 'src/ilasm/assembler.cpp')
-rw-r--r-- | src/ilasm/assembler.cpp | 2462 |
1 files changed, 2462 insertions, 0 deletions
diff --git a/src/ilasm/assembler.cpp b/src/ilasm/assembler.cpp new file mode 100644 index 0000000000..690da64890 --- /dev/null +++ b/src/ilasm/assembler.cpp @@ -0,0 +1,2462 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: assembler.cpp +// + +// + +#include "ilasmpch.h" + +#include "assembler.h" +#include "binstr.h" +#include "nvpair.h" + +#define FAIL_UNLESS(x, y) if (!(x)) { report->error y; return; } + +/**************************************************************************/ +void Assembler::StartNameSpace(__in __nullterminated char* name) +{ + m_NSstack.PUSH(m_szNamespace); + m_szNamespace = name; + unsigned L = (unsigned)strlen(m_szFullNS); + unsigned l = (unsigned)strlen(name); + if(L+l+1 >= m_ulFullNSLen) + { + char* pch = new char[((L+l)/MAX_NAMESPACE_LENGTH + 1)*MAX_NAMESPACE_LENGTH]; + if(pch) + { + memcpy(pch,m_szFullNS,L+1); + delete [] m_szFullNS; + m_szFullNS = pch; + m_ulFullNSLen = ((L+l)/MAX_NAMESPACE_LENGTH + 1)*MAX_NAMESPACE_LENGTH; + } + else report->error("Failed to reallocate the NameSpace buffer\n"); + } + if(L) m_szFullNS[L] = NAMESPACE_SEPARATOR_CHAR; + else L = 0xFFFFFFFF; + memcpy(&m_szFullNS[L+1],m_szNamespace, l+1); +} + +/**************************************************************************/ +void Assembler::EndNameSpace() +{ + char *p = &m_szFullNS[strlen(m_szFullNS)-strlen(m_szNamespace)]; + if(p > m_szFullNS) p--; + *p = 0; + delete [] m_szNamespace; + if((m_szNamespace = m_NSstack.POP())==NULL) + { + m_szNamespace = new char[2]; + m_szNamespace[0] = 0; + } +} + +/**************************************************************************/ +void Assembler::ClearImplList(void) +{ + while(m_nImplList) m_crImplList[--m_nImplList] = mdTypeRefNil; +} +/**************************************************************************/ +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:22008) // "Suppress PREfast warnings about integer overflow" +#endif +void Assembler::AddToImplList(mdToken tk) +{ + if(m_nImplList+1 >= m_nImplListSize) + { + mdToken *ptr = new mdToken[m_nImplListSize + MAX_INTERFACES_IMPLEMENTED]; + if(ptr == NULL) + { + report->error("Failed to reallocate Impl List from %d to %d bytes\n", + m_nImplListSize*sizeof(mdToken), + (m_nImplListSize+MAX_INTERFACES_IMPLEMENTED)*sizeof(mdToken)); + return; + } + memcpy(ptr,m_crImplList,m_nImplList*sizeof(mdToken)); + delete m_crImplList; + m_crImplList = ptr; + m_nImplListSize += MAX_INTERFACES_IMPLEMENTED; + } + m_crImplList[m_nImplList++] = tk; + m_crImplList[m_nImplList] = mdTypeRefNil; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +void Assembler::ClearBoundList(void) +{ + m_TyParList = NULL; +} +/**************************************************************************/ +mdToken Assembler::ResolveClassRef(mdToken tkResScope, __in __nullterminated const char *pszFullClassName, Class** ppClass) +{ + Class *pClass = NULL; + mdToken tkRet = mdTokenNil; + mdToken *ptkSpecial = NULL; + + if(pszFullClassName == NULL) return mdTokenNil; +#if (0) + if (m_fInitialisedMetaData == FALSE) + { + if (FAILED(InitMetaData())) // impl. see WRITER.CPP + { + _ASSERTE(0); + if(ppClass) *ppClass = NULL; + return mdTokenNil; + } + } +#endif + + switch(strlen(pszFullClassName)) + { + case 11: + if(strcmp(pszFullClassName,"System.Enum")==0) ptkSpecial = &m_tkSysEnum; + break; + case 13: + if(strcmp(pszFullClassName,"System.Object")==0) ptkSpecial = &m_tkSysObject; + else if(strcmp(pszFullClassName,"System.String")==0) ptkSpecial = &m_tkSysString; + break; + case 16: + if(strcmp(pszFullClassName,"System.ValueType")==0) ptkSpecial = &m_tkSysValue; + break; + } + if(ptkSpecial) // special token + { + if(*ptkSpecial) // already resolved + { + tkRet = *ptkSpecial; + if(ppClass) + { + if(TypeFromToken(tkRet)==mdtTypeDef) + *ppClass = m_lstClass.PEEK(RidFromToken(tkRet)-1); + else *ppClass = NULL; + } + return tkRet; + } + else // needs to be resolved + if(!m_fIsMscorlib) tkResScope = GetBaseAsmRef(); + } + if(tkResScope == 1) + { + if((pClass = FindCreateClass(pszFullClassName)) != NULL) tkRet = pClass->m_cl; + } + else + { + tkRet = MakeTypeRef(tkResScope, pszFullClassName); + pClass = NULL; + } + if(ppClass) *ppClass = pClass; + if(ptkSpecial) *ptkSpecial = tkRet; + return tkRet; +} + +class TypeSpecContainer +{ +private: + // Contain a BinStr + unsigned __int8 *ptr_; + unsigned len_; + // Hash the BinStr, just for speed of lookup + unsigned hash_; + // The value we're looking for + mdToken token_; +public: + // Constructor for a 'lookup' object + TypeSpecContainer(BinStr *typeSpec) : + ptr_(typeSpec->ptr()), + len_(typeSpec->length()), + hash_(typeSpec->length()), + token_(mdTokenNil) + { + for (unsigned i = 0; i < len_; i++) + hash_ = (hash_ * 257) ^ ((i + 1) * (ptr_[i] ^ 0xA5)); + } + // Constructor for a 'permanent' object + // Don't bother re-hashing, since we will always have already constructed the lookup object + TypeSpecContainer(const TypeSpecContainer &t, mdToken tk) : + ptr_(new unsigned __int8[t.len_]), + len_(t.len_), + hash_(t.hash_), + token_(tk) + { + _ASSERT(tk != mdTokenNil); + _ASSERT(t.token_ == mdTokenNil); + memcpy(ptr_, t.ptr_, len_); + } + ~TypeSpecContainer() + { + if (token_ != mdTokenNil) + // delete any memory for a 'permanent' object + delete[] ptr_; + } + // this is the operator for a RBTREE + int ComparedTo(TypeSpecContainer *t) const + { + // If they don't hash the same, just diff the hashes + if (hash_ != t->hash_) + return hash_ - t->hash_; + if (len_ != t->len_) + return len_ - t->len_; + return memcmp(ptr_, t->ptr_, len_); + } + // The only public data we need + const mdToken Token() const { return token_; } +}; + +static RBTREE<TypeSpecContainer> typeSpecCache; + +extern FIFO<char> TyParFixupList; + +/**************************************************************************/ +mdToken Assembler::ResolveTypeSpec(BinStr* typeSpec) +{ + mdToken tk; + + // It is safe to use the cache only if there are no pending fixups + if (TyParFixupList.COUNT() != 0) + { + if (FAILED(m_pEmitter->GetTokenFromTypeSpec(typeSpec->ptr(), typeSpec->length(), &tk))) + return mdTokenNil; + return tk; + } + + TypeSpecContainer tsc(typeSpec); + + // GetTokenFromTypeSpec is a linear search through an unsorted list + // Instead of doing that all the time, look this thing up in a cache + TypeSpecContainer *res = typeSpecCache.FIND(&tsc); + if (res != NULL) + { +#ifdef _DEBUG + // Verify that the cache is in sync with the master copy in metadata + PCOR_SIGNATURE pSig; + ULONG cSig; + m_pImporter->GetTypeSpecFromToken(res->Token(),(PCCOR_SIGNATURE*)&pSig,&cSig); + _ASSERTE(typeSpec->length() == cSig); + _ASSERTE(memcmp(typeSpec->ptr(), pSig, cSig) == 0); +#endif + + return res->Token(); + } + + if (FAILED(m_pEmitter->GetTokenFromTypeSpec(typeSpec->ptr(), typeSpec->length(), &tk))) + return mdTokenNil; + + typeSpecCache.PUSH(new TypeSpecContainer(tsc, tk)); + return tk; +} + +/**************************************************************************/ +mdToken Assembler::GetAsmRef(__in __nullterminated const char* szName) +{ + mdToken tkResScope = 0; + if(strcmp(szName,"*")==0) tkResScope = mdTokenNil; + else + { + tkResScope = m_pManifest->GetAsmRefTokByName(szName); + if(RidFromToken(tkResScope)==0) + { + // emit the AssemblyRef + // if it's not self, try to get attributes with Autodetect + unsigned L = (unsigned)strlen(szName)+1; + char *sz = new char[L]; + if(sz) + { + memcpy(sz,szName,L); + AsmManAssembly *pAsmRef = m_pManifest->m_pCurAsmRef; + m_pManifest->StartAssembly(sz,NULL,0,TRUE); + if(RidFromToken(m_pManifest->GetAsmTokByName(szName))==0) + { + report->warn("Reference to undeclared extern assembly '%s'. Attempting autodetect\n",szName); + m_pManifest->SetAssemblyAutodetect(); + } + m_pManifest->EndAssembly(); + tkResScope = m_pManifest->GetAsmRefTokByName(szName); + m_pManifest->m_pCurAsmRef = pAsmRef; + } + else + report->error("\nOut of memory!\n"); + } + } + return tkResScope; +} + +mdToken Assembler::GetBaseAsmRef() +{ + if(RidFromToken(m_pManifest->GetAsmRefTokByName("System.Runtime")) != 0) + { + return GetAsmRef("System.Runtime"); + } + + return GetAsmRef("mscorlib"); +} + +mdToken Assembler::GetInterfaceImpl(mdToken tsClass, mdToken tsInterface) +{ + mdToken result = mdTokenNil; + HCORENUM iiEnum = 0; + ULONG actualInterfaces; + mdInterfaceImpl impls; + + while (SUCCEEDED(m_pImporter->EnumInterfaceImpls(&iiEnum, tsClass, &impls, 1, &actualInterfaces))) + { + if (actualInterfaces == 1) + { + mdToken classToken, interfaceToken; + if (FAILED(m_pImporter->GetInterfaceImplProps(impls, &classToken, &interfaceToken))) + break; + if (classToken == tsClass && interfaceToken == tsInterface) + { + result = impls; + break; + } + } + } + m_pImporter->CloseEnum(iiEnum); + return result; +} + +/**************************************************************************/ +mdToken Assembler::GetModRef(__in __nullterminated char* szName) +{ + mdToken tkResScope = 0; + if(!strcmp(szName,m_szScopeName)) + tkResScope = 1; // scope is "this module" + else + { + ImportDescriptor* pID; + int i = 0; + tkResScope = mdModuleRefNil; + DWORD L = (DWORD)strlen(szName); + while((pID=m_ImportList.PEEK(i++))) + { + if(pID->dwDllName != L) continue; + if((L > 0) && (strcmp(pID->szDllName,szName)!=0)) continue; + tkResScope = pID->mrDll; + break; + } + if(RidFromToken(tkResScope)==0) + report->error("Undefined module ref '%s'\n",szName); + } + return tkResScope; +} +/**************************************************************************/ +mdToken Assembler::MakeTypeRef(mdToken tkResScope, LPCUTF8 pszFullClassName) +{ + mdToken tkRet = mdTokenNil; + if(pszFullClassName && *pszFullClassName) + { + LPCUTF8 pc; + if((pc = strrchr(pszFullClassName,NESTING_SEP))) // scope: enclosing class + { + LPUTF8 szScopeName; + DWORD L = (DWORD)(pc-pszFullClassName); + if((szScopeName = new char[L+1]) != NULL) + { + memcpy(szScopeName,pszFullClassName,L); + szScopeName[L] = 0; + tkResScope = MakeTypeRef(tkResScope,szScopeName); + delete [] szScopeName; + } + else + report->error("\nOut of memory!\n"); + pc++; + } + else pc = pszFullClassName; + if(*pc) + { + // convert name to widechar + WszMultiByteToWideChar(g_uCodePage,0,pc,-1,wzUniBuf,dwUniBuf); + if(FAILED(m_pEmitter->DefineTypeRefByName(tkResScope, wzUniBuf, &tkRet))) tkRet = mdTokenNil; + } + } + return tkRet; +} +/**************************************************************************/ + +DWORD Assembler::CheckClassFlagsIfNested(Class* pEncloser, DWORD attr) +{ + DWORD wasAttr = attr; + if(pEncloser && (!IsTdNested(attr))) + { + if(OnErrGo) + report->error("Nested class has non-nested visibility (0x%08X)\n",attr); + else + { + attr &= ~tdVisibilityMask; + attr |= (IsTdPublic(wasAttr) ? tdNestedPublic : tdNestedPrivate); + report->warn("Nested class has non-nested visibility (0x%08X), changed to nested (0x%08X)\n",wasAttr,attr); + } + } + else if((pEncloser==NULL) && IsTdNested(attr)) + { + if(OnErrGo) + report->error("Non-nested class has nested visibility (0x%08X)\n",attr); + else + { + attr &= ~tdVisibilityMask; + attr |= (IsTdNestedPublic(wasAttr) ? tdPublic : tdNotPublic); + report->warn("Non-nested class has nested visibility (0x%08X), changed to non-nested (0x%08X)\n",wasAttr,attr); + } + } + return attr; +} + +/**************************************************************************/ + +void Assembler::StartClass(__in __nullterminated char* name, DWORD attr, TyParList *typars) +{ + Class *pEnclosingClass = m_pCurClass; + char *szFQN; + ULONG LL; + + m_TyParList = typars; + + if (m_pCurMethod != NULL) + { + report->error("Class cannot be declared within a method scope\n"); + } + if(pEnclosingClass) + { + LL = pEnclosingClass->m_dwFQN+(ULONG)strlen(name)+2; + if((szFQN = new char[LL])) + sprintf_s(szFQN,LL,"%s%c%s",pEnclosingClass->m_szFQN,NESTING_SEP,name); + else + report->error("\nOut of memory!\n"); + } + else + { + unsigned L = (unsigned)strlen(m_szFullNS); + unsigned LLL = (unsigned)strlen(name); + LL = L + LLL + (L ? 2 : 1); + if((szFQN = new char[LL])) + { + if(L) sprintf_s(szFQN,LL,"%s.%s",m_szFullNS,name); + else memcpy(szFQN,name,LL); + if(LL > MAX_CLASSNAME_LENGTH) + { + report->error("Full class name too long (%d characters, %d allowed).\n",LL-1,MAX_CLASSNAME_LENGTH-1); + } + } + else + report->error("\nOut of memory!\n"); + } + if(szFQN == NULL) return; + + mdToken tkThis; + if(m_fIsMscorlib) + tkThis = ResolveClassRef(1,szFQN,&m_pCurClass); // boils down to FindCreateClass(szFQN) + else + { + m_pCurClass = FindCreateClass(szFQN); + tkThis = m_pCurClass->m_cl; + } + if(m_pCurClass->m_bIsMaster) + { + m_pCurClass->m_Attr = CheckClassFlagsIfNested(pEnclosingClass, attr); + + if (m_TyParList) + { + //m_pCurClass->m_NumTyPars = m_TyParList->ToArray(&m_pCurClass->m_TyParBounds, &m_pCurClass->m_TyParNames, &m_pCurClass->m_TyParAttrs); + m_pCurClass->m_NumTyPars = m_TyParList->ToArray(&(m_pCurClass->m_TyPars)); + delete m_TyParList; + m_TyParList = NULL; + } + else m_pCurClass->m_NumTyPars = 0; + m_pCurClass->m_pEncloser = pEnclosingClass; + } // end if(old class) else + m_tkCurrentCVOwner = 0; + m_CustomDescrListStack.PUSH(m_pCustomDescrList); + m_pCustomDescrList = &(m_pCurClass->m_CustDList); + + m_ClassStack.PUSH(pEnclosingClass); + ClearBoundList(); +} + +/**************************************************************************/ + +void Assembler::AddClass() +{ + mdTypeRef crExtends = mdTypeRefNil; + BOOL bIsEnum = FALSE; + BOOL bIsValueType = FALSE; + + if(m_pCurClass->m_bIsMaster) + { + DWORD attr = m_pCurClass->m_Attr; + if(!IsNilToken(m_crExtends)) + { + // has a superclass + if(IsTdInterface(attr)) report->error("Base class in interface\n"); + bIsValueType = (m_crExtends == m_tkSysValue)&&(m_pCurClass->m_cl != m_tkSysEnum); + bIsEnum = (m_crExtends == m_tkSysEnum); + crExtends = m_crExtends; + } + else + { + bIsEnum = ((attr & 0x40000000) != 0); + bIsValueType = ((attr & 0x80000000) != 0); + } + attr &= 0x3FFFFFFF; + if (m_fAutoInheritFromObject && (crExtends == mdTypeRefNil) && (!IsTdInterface(attr))) + { + mdToken tkMscorlib = m_fIsMscorlib ? 1 : GetBaseAsmRef(); + crExtends = bIsEnum ? + ResolveClassRef(tkMscorlib,"System.Enum",NULL) + :( bIsValueType ? + ResolveClassRef(tkMscorlib,"System.ValueType",NULL) + : ResolveClassRef(tkMscorlib, "System.Object",NULL)); + } + m_pCurClass->m_Attr = attr; + m_pCurClass->m_crExtends = (m_pCurClass->m_cl == m_tkSysObject)? mdTypeRefNil : crExtends; + + if ((m_pCurClass->m_dwNumInterfaces = m_nImplList) != NULL) + { + if(bIsEnum) report->error("Enum implementing interface(s)\n"); + if((m_pCurClass->m_crImplements = new mdTypeRef[m_nImplList+1]) != NULL) + memcpy(m_pCurClass->m_crImplements, m_crImplList, (m_nImplList+1)*sizeof(mdTypeRef)); + else + { + report->error("Failed to allocate Impl List for class '%s'\n", m_pCurClass->m_szFQN); + m_pCurClass->m_dwNumInterfaces = 0; + } + } + else m_pCurClass->m_crImplements = NULL; + if(bIsValueType) + { + if(!IsTdSealed(attr)) + { + if(OnErrGo) report->error("Non-sealed value class\n"); + else + { + report->warn("Non-sealed value class, made sealed\n"); + m_pCurClass->m_Attr |= tdSealed; + } + } + } + m_pCurClass->m_bIsMaster = FALSE; + } // end if(old class) else + ClearImplList(); + m_crExtends = mdTypeRefNil; +} + +/**************************************************************************/ +void Assembler::EndClass() +{ + m_pCurClass = m_ClassStack.POP(); + m_tkCurrentCVOwner = 0; + m_pCustomDescrList = m_CustomDescrListStack.POP(); +} + +/**************************************************************************/ +void Assembler::SetPinvoke(BinStr* DllName, int Ordinal, BinStr* Alias, int Attrs) +{ + if(m_pPInvoke) delete m_pPInvoke; + if(DllName->length()) + { + if((m_pPInvoke = new PInvokeDescriptor)) + { + unsigned l; + ImportDescriptor* pID; + if((pID = EmitImport(DllName))) + { + m_pPInvoke->mrDll = pID->mrDll; + m_pPInvoke->szAlias = NULL; + if(Alias) + { + l = Alias->length(); + if((m_pPInvoke->szAlias = new char[l+1])) + { + memcpy(m_pPInvoke->szAlias,Alias->ptr(),l); + m_pPInvoke->szAlias[l] = 0; + } + else report->error("\nOut of memory!\n"); + } + m_pPInvoke->dwAttrs = (DWORD)Attrs; + } + else + { + delete m_pPInvoke; + m_pPInvoke = NULL; + report->error("PInvoke refers to undefined imported DLL\n"); + } + } + else + report->error("Failed to allocate PInvokeDescriptor\n"); + } + else + { + m_pPInvoke = NULL; // No DLL name, it's "local" (IJW) PInvoke + report->error("Local (embedded native) PInvoke method, the resulting PE file is unusable\n"); + } + if(DllName) delete DllName; + if(Alias) delete Alias; +} + +/**************************************************************************/ +void Assembler::StartMethod(__in __nullterminated char* name, BinStr* sig, CorMethodAttr flags, BinStr* retMarshal, DWORD retAttr, TyParList *typars) +{ + if (m_pCurMethod != NULL) + { + report->error("Cannot declare a method '%s' within another method\n",name); + } + if (!m_fInitialisedMetaData) + { + if (FAILED(InitMetaData())) // impl. see WRITER.CPP + { + _ASSERTE(0); + } + } + size_t namelen = strlen(name); + if(namelen >= MAX_CLASSNAME_LENGTH) + { + char c = name[MAX_CLASSNAME_LENGTH-1]; + name[MAX_CLASSNAME_LENGTH-1] = 0; + report->error("Method '%s...' -- name too long (%d characters).\n",name,namelen); + name[MAX_CLASSNAME_LENGTH-1] = c; + } + if (!(flags & mdStatic)) + *(sig->ptr()) |= IMAGE_CEE_CS_CALLCONV_HASTHIS; + else if(*(sig->ptr()) & (IMAGE_CEE_CS_CALLCONV_HASTHIS | IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)) + { + if(OnErrGo) report->error("Method '%s' -- both static and instance\n", name); + else + { + report->warn("Method '%s' -- both static and instance, set to static\n", name); + *(sig->ptr()) &= ~(IMAGE_CEE_CS_CALLCONV_HASTHIS | IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS); + } + } + + if(!IsMdPrivateScope(flags)) + { + Method* pMethod; + Class* pClass = (m_pCurClass ? m_pCurClass : m_pModuleClass); + DWORD L = (DWORD)strlen(name); + for(int j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++) + { + if( (pMethod->m_dwName == L) && + (!strcmp(pMethod->m_szName,name)) && + (pMethod->m_dwMethodCSig == sig->length()) && + (!memcmp(pMethod->m_pMethodSig,sig->ptr(),sig->length())) + &&(!IsMdPrivateScope(pMethod->m_Attr))) + { + if(m_fTolerateDupMethods) + { + // reset for new body + pMethod->m_lstFixup.RESET(true); + //pMethod->m_lstLabel.RESET(true); + m_lstLabel.RESET(true); + pMethod->m_Locals.RESET(true); + delArgNameList(pMethod->m_firstArgName); + delArgNameList(pMethod->m_firstVarName); + pMethod->m_pCurrScope = &(pMethod->m_MainScope); + pMethod->m_pCurrScope->Reset(); + pMethod->m_firstArgName = getArgNameList(); + pMethod->m_dwNumExceptions = 0; + pMethod->m_dwNumEndfilters = 0; + if(pMethod->m_pRetMarshal) delete pMethod->m_pRetMarshal; + if(pMethod->m_pRetValue) delete pMethod->m_pRetValue; + + pMethod->m_MethodImplDList.RESET(false); // ptrs in m_MethodImplDList are dups of those in Assembler + + pMethod->m_CustomDescrList.RESET(true); + + if(pMethod->m_fEntryPoint) + { + pMethod->m_fEntryPoint = FALSE; + m_fEntryPointPresent = FALSE; + } + + if(pMethod->m_pbsBody) + { + // no need to remove relevant MemberRef Fixups from the Assembler list: + // their m_fNew flag is set to FALSE anyway. + // Just get rid of old method body + delete pMethod->m_pbsBody; + pMethod->m_pbsBody = NULL; + } + + pMethod->m_fNewBody = TRUE; + m_pCurMethod = pMethod; + } + else + report->error("Duplicate method declaration\n"); + break; + } + } + } + if(m_pCurMethod == NULL) + { + if(m_pCurClass) + { // instance method + if(IsMdAbstract(flags) && !IsTdAbstract(m_pCurClass->m_Attr)) + { + report->error("Abstract method '%s' in non-abstract class '%s'\n",name,m_pCurClass->m_szFQN); + } + if(m_pCurClass->m_crExtends == m_tkSysEnum) report->error("Method in enum\n"); + + if(!strcmp(name,COR_CTOR_METHOD_NAME)) + { + flags = (CorMethodAttr)(flags | mdSpecialName); + if(IsTdInterface(m_pCurClass->m_Attr)) report->error("Instance constructor in interface\n"); + + } + if(!IsMdStatic(flags)) + { + if(IsTdInterface(m_pCurClass->m_Attr)) + { + if(!IsMdPublic(flags)) report->error("Non-public instance method in interface\n"); + if((!(IsMdVirtual(flags) && IsMdAbstract(flags)))) + { + if(OnErrGo) report->error("Non-virtual, non-abstract instance method in interface\n"); + else + { + report->warn("Non-virtual, non-abstract instance method in interface, set to such\n"); + flags = (CorMethodAttr)(flags |mdVirtual | mdAbstract); + } + } + + } + } + m_pCurMethod = new Method(this, m_pCurClass, name, sig, flags); + } + else + { + if(IsMdAbstract(flags)) + { + if(OnErrGo) report->error("Global method '%s' can't be abstract\n",name); + else + { + report->warn("Global method '%s' can't be abstract, flag removed\n",name); + flags = (CorMethodAttr)(((int) flags) &~mdAbstract); + } + } + if(!IsMdStatic(flags)) + { + if(OnErrGo) report->error("Non-static global method '%s'\n",name); + else + { + report->warn("Non-static global method '%s', made static\n",name); + flags = (CorMethodAttr)(flags | mdStatic); + *((BYTE*)(sig->ptr())) &= ~(IMAGE_CEE_CS_CALLCONV_HASTHIS | IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS); + } + } + m_pCurMethod = new Method(this, m_pCurClass, name, sig, flags); + if (m_pCurMethod) + { + m_pCurMethod->SetIsGlobalMethod(); + if (m_fInitialisedMetaData == FALSE) InitMetaData(); + } + } + if(m_pCurMethod) + { + if(!OnErrGo) + { + if(m_pCurMethod->m_firstArgName) + { + for(ARG_NAME_LIST *pAN=m_pCurMethod->m_firstArgName; pAN; pAN = pAN->pNext) + { + if(pAN->dwName) + { + int k = m_pCurMethod->findArgNum(pAN->pNext,pAN->szName,pAN->dwName); + if(k >= 0) + report->warn("Duplicate param name '%s' in method '%s'\n",pAN->szName,name); + } + } + } + } + m_pCurMethod->m_pRetMarshal = retMarshal; + m_pCurMethod->m_dwRetAttr = retAttr; + m_tkCurrentCVOwner = 0; + m_CustomDescrListStack.PUSH(m_pCustomDescrList); + m_pCustomDescrList = &(m_pCurMethod->m_CustomDescrList); + m_pCurMethod->m_MainScope.dwStart = m_CurPC; + if (typars) + { + //m_pCurMethod->m_NumTyPars = typars->ToArray(&m_pCurMethod->m_TyParBounds, + //&m_pCurMethod->m_TyParNames, NULL); + m_pCurMethod->m_NumTyPars = typars->ToArray(&(m_pCurMethod->m_TyPars)); + delete typars; + m_TyParList = NULL; + } + else m_pCurMethod->m_NumTyPars = 0; + } + else report->error("Failed to allocate Method class\n"); + } // end if new method +} + +/**************************************************************************/ +void Assembler::EndMethod() +{ + + if(m_pCurMethod->m_pCurrScope != &(m_pCurMethod->m_MainScope)) + { + report->error("Invalid lexical scope structure in method %s\n",m_pCurMethod->m_szName); + } + m_pCurMethod->m_pCurrScope->dwEnd = m_CurPC; + if (DoFixups(m_pCurMethod)) AddMethod(m_pCurMethod); //AddMethod - see ASSEM.CPP + else + { + report->error("Method '%s' compilation failed.\n",m_pCurMethod->m_szName); + } + //m_pCurMethod->m_lstLabel.RESET(true); + m_lstLabel.RESET(true); + m_tkCurrentCVOwner = 0; + m_pCustomDescrList = m_CustomDescrListStack.POP(); + ResetForNextMethod(); // see ASSEM.CPP +} +/**************************************************************************/ +/* rvaLabel is the optional label that indicates this field points at a particular RVA */ +void Assembler::AddField(__inout_z __inout char* name, BinStr* sig, CorFieldAttr flags, __in __nullterminated char* rvaLabel, BinStr* pVal, ULONG ulOffset) +{ + FieldDescriptor* pFD; + ULONG i,n; + mdToken tkParent = mdTokenNil; + Class* pClass; + + if (m_pCurMethod) + report->error("Field cannot be declared within a method\n"); + + if(strlen(name) >= MAX_CLASSNAME_LENGTH) + { + char c = name[MAX_CLASSNAME_LENGTH-1]; + name[MAX_CLASSNAME_LENGTH-1] = 0; + report->error("Field '%s...' -- name too long (%d characters).\n",name,strlen(name)); + name[MAX_CLASSNAME_LENGTH-1] = c; + } + + if(sig && (sig->length() >= 2)) + { + if(sig->ptr()[1] == ELEMENT_TYPE_VOID) + report->error("Illegal use of type 'void'\n"); + } + + if (m_pCurClass) + { + tkParent = m_pCurClass->m_cl; + + if(IsTdInterface(m_pCurClass->m_Attr)) + { + if(!IsFdStatic(flags)) + { + report->warn("Instance field in interface (CLS violation)\n"); + if(!IsFdPublic(flags)) report->error("Non-public instance field in interface\n"); + } + } + } + else + { + if(ulOffset != 0xFFFFFFFF) + { + report->warn("Offset in global field '%s' is ignored\n",name); + ulOffset = 0xFFFFFFFF; + } + if(!IsFdStatic(flags)) + { + if(OnErrGo) report->error("Non-static global field\n"); + else + { + report->warn("Non-static global field, made static\n"); + flags = (CorFieldAttr)(flags | fdStatic); + } + } + } + pClass = (m_pCurClass ? m_pCurClass : m_pModuleClass); + n = pClass->m_FieldDList.COUNT(); + DWORD L = (DWORD)strlen(name); + for(i = 0; i < n; i++) + { + pFD = pClass->m_FieldDList.PEEK(i); + if((pFD->m_tdClass == tkParent)&&(L==pFD->m_dwName)&&(!strcmp(pFD->m_szName,name)) + &&(pFD->m_pbsSig->length() == sig->length()) + &&(memcmp(pFD->m_pbsSig->ptr(),sig->ptr(),sig->length())==0)) + { + report->error("Duplicate field declaration: '%s'\n",name); + break; + } + } + if (rvaLabel && !IsFdStatic(flags)) + report->error("Only static fields can have 'at' clauses\n"); + + if(i >= n) + { + if((pFD = new FieldDescriptor)) + { + pFD->m_tdClass = tkParent; + pFD->m_szName = name; + pFD->m_dwName = L; + pFD->m_fdFieldTok = mdTokenNil; + if((pFD->m_ulOffset = ulOffset) != 0xFFFFFFFF) pClass->m_dwNumFieldsWithOffset++; + pFD->m_rvaLabel = rvaLabel; + pFD->m_pbsSig = sig; + pFD->m_pClass = pClass; + pFD->m_pbsValue = pVal; + pFD->m_pbsMarshal = m_pMarshal; + pFD->m_pPInvoke = m_pPInvoke; + pFD->m_dwAttr = flags; + + m_tkCurrentCVOwner = 0; + m_pCustomDescrList = &(pFD->m_CustomDescrList); + + pClass->m_FieldDList.PUSH(pFD); + pClass->m_fNewMembers = TRUE; + } + else + report->error("Failed to allocate Field Descriptor\n"); + } + else + { + if(pVal) delete pVal; + if(m_pPInvoke) delete m_pPInvoke; + if(m_pMarshal) delete m_pMarshal; + delete name; + } + m_pPInvoke = NULL; + m_pMarshal = NULL; +} + +BOOL Assembler::EmitField(FieldDescriptor* pFD) +{ + WCHAR* wzFieldName=&wzUniBuf[0]; + HRESULT hr; + DWORD cSig; + COR_SIGNATURE* mySig; + mdFieldDef mb; + BYTE ValType = ELEMENT_TYPE_VOID; + void * pValue = NULL; + unsigned lVal = 0; + BOOL ret = TRUE; + + cSig = pFD->m_pbsSig->length(); + mySig = (COR_SIGNATURE*)(pFD->m_pbsSig->ptr()); + + WszMultiByteToWideChar(g_uCodePage,0,pFD->m_szName,-1,wzFieldName,dwUniBuf); //int)cFieldNameLength); + if(IsFdPrivateScope(pFD->m_dwAttr)) + { + WCHAR* p = wcsstr(wzFieldName,W("$PST04")); + if(p) *p = 0; + } + + if(pFD->m_pbsValue && pFD->m_pbsValue->length()) + { + ValType = *(pFD->m_pbsValue->ptr()); + lVal = pFD->m_pbsValue->length() - 1; // 1 is type byte + pValue = (void*)(pFD->m_pbsValue->ptr() + 1); + if(ValType == ELEMENT_TYPE_STRING) + { + //while(lVal % sizeof(WCHAR)) { pFD->m_pbsValue->appendInt8(0); lVal++; } + lVal /= sizeof(WCHAR); + +#if defined(ALIGN_ACCESS) || BIGENDIAN + void* pValueTemp = _alloca(lVal * sizeof(WCHAR)); + memcpy(pValueTemp, pValue, lVal * sizeof(WCHAR)); + pValue = pValueTemp; + + SwapStringLength((WCHAR*)pValue, lVal); +#endif + } + } + + hr = m_pEmitter->DefineField( + pFD->m_tdClass, + wzFieldName, + pFD->m_dwAttr, + mySig, + cSig, + ValType, + pValue, + lVal, + &mb + ); + if (FAILED(hr)) + { + report->error("Failed to define field '%s' (HRESULT=0x%08X)\n",pFD->m_szName,hr); + ret = FALSE; + } + else + { + //-------------------------------------------------------------------------------- + if(IsFdPinvokeImpl(pFD->m_dwAttr)&&(pFD->m_pPInvoke)) + { + if(pFD->m_pPInvoke->szAlias == NULL) pFD->m_pPInvoke->szAlias = pFD->m_szName; + if(FAILED(EmitPinvokeMap(mb,pFD->m_pPInvoke))) + { + report->error("Failed to define PInvoke map of .field '%s'\n",pFD->m_szName); + ret = FALSE; + } + } + //-------------------------------------------------------------------------- + if(pFD->m_pbsMarshal) + { + if(FAILED(hr = m_pEmitter->SetFieldMarshal ( + mb, // [IN] given a fieldDef or paramDef token + (PCCOR_SIGNATURE)(pFD->m_pbsMarshal->ptr()), // [IN] native type specification + pFD->m_pbsMarshal->length()))) // [IN] count of bytes of pvNativeType + { + report->error("Failed to set field marshaling for '%s' (HRESULT=0x%08X)\n",pFD->m_szName,hr); + ret = FALSE; + } + } + //-------------------------------------------------------------------------------- + // Set the the RVA to a dummy value. later it will be fixed + // up to be something correct, but if we don't emit something + // the size of the meta-data will not be correct + if (pFD->m_rvaLabel) + { + m_fHaveFieldsWithRvas = TRUE; + hr = m_pEmitter->SetFieldRVA(mb, 0xCCCCCCCC); + if (FAILED(hr)) + { + report->error("Failed to set RVA for field '%s' (HRESULT=0x%08X)\n",pFD->m_szName,hr); + ret = FALSE; + } + } + //-------------------------------------------------------------------------------- + EmitCustomAttributes(mb, &(pFD->m_CustomDescrList)); + + } + pFD->m_fdFieldTok = mb; + return ret; +} + +/**************************************************************************/ +void Assembler::EmitByte(int val) +{ + char ch = (char)val; + //if((val < -128)||(val > 127)) + // report->warn("Emitting 0x%X as a byte: data truncated to 0x%X\n",(unsigned)val,(BYTE)ch); + EmitBytes((BYTE *)&ch,1); +} + +/**************************************************************************/ +void Assembler::NewSEHDescriptor(void) //sets m_SEHD +{ + m_SEHDstack.PUSH(m_SEHD); + m_SEHD = new SEH_Descriptor; + if(m_SEHD == NULL) report->error("Failed to allocate SEH descriptor\n"); +} +/**************************************************************************/ +void Assembler::SetTryLabels(__in __nullterminated char * szFrom, __in __nullterminated char *szTo) +{ + if(!m_SEHD) return; + Label *pLbl = m_pCurMethod->FindLabel(szFrom); + if(pLbl) + { + m_SEHD->tryFrom = pLbl->m_PC; + if((pLbl = m_pCurMethod->FindLabel(szTo))) m_SEHD->tryTo = pLbl->m_PC; //FindLabel: Method.CPP + else report->error("Undefined 2nd label in 'try <label> to <label>'\n"); + } + else report->error("Undefined 1st label in 'try <label> to <label>'\n"); +} +/**************************************************************************/ +void Assembler::SetFilterLabel(__in __nullterminated char *szFilter) +{ + if(!m_SEHD) return; + Label *pLbl = m_pCurMethod->FindLabel(szFilter); + if(pLbl) m_SEHD->sehFilter = pLbl->m_PC; + else report->error("Undefined label in 'filter <label>'\n"); +} +/**************************************************************************/ +void Assembler::SetCatchClass(mdToken catchClass) +{ + if(!m_SEHD) return; + m_SEHD->cException = catchClass; + +} +/**************************************************************************/ +void Assembler::SetHandlerLabels(__in __nullterminated char *szHandlerFrom, __in __nullterminated char *szHandlerTo) +{ + if(!m_SEHD) return; + Label *pLbl = m_pCurMethod->FindLabel(szHandlerFrom); + if(pLbl) + { + m_SEHD->sehHandler = pLbl->m_PC; + if(szHandlerTo) + { + pLbl = m_pCurMethod->FindLabel(szHandlerTo); + if(pLbl) + { + m_SEHD->sehHandlerTo = pLbl->m_PC; + return; + } + } + else + { + m_SEHD->sehHandlerTo = m_SEHD->sehHandler - 1; + return; + } + } + report->error("Undefined label in 'handler <label> to <label>'\n"); +} +/**************************************************************************/ +void Assembler::EmitTry(void) //enum CorExceptionFlag kind, char* beginLabel, char* endLabel, char* handleLabel, char* filterOrClass) +{ + if(m_SEHD) + { + bool isFilter=(m_SEHD->sehClause == COR_ILEXCEPTION_CLAUSE_FILTER), + isFault=(m_SEHD->sehClause == COR_ILEXCEPTION_CLAUSE_FAULT), + isFinally=(m_SEHD->sehClause == COR_ILEXCEPTION_CLAUSE_FINALLY); + + AddException(m_SEHD->tryFrom, m_SEHD->tryTo, m_SEHD->sehHandler, m_SEHD->sehHandlerTo, + m_SEHD->cException, isFilter, isFault, isFinally); + } + else report->error("Attempt to EmitTry with NULL SEH descriptor\n"); +} +/**************************************************************************/ + +void Assembler::AddException(DWORD pcStart, DWORD pcEnd, DWORD pcHandler, DWORD pcHandlerTo, mdTypeRef crException, BOOL isFilter, BOOL isFault, BOOL isFinally) +{ + if (m_pCurMethod == NULL) + { + report->error("Exceptions can be declared only when in a method scope\n"); + return; + } + + if (m_pCurMethod->m_dwNumExceptions >= m_pCurMethod->m_dwMaxNumExceptions) + { + COR_ILMETHOD_SECT_EH_CLAUSE_FAT *ptr = + new COR_ILMETHOD_SECT_EH_CLAUSE_FAT[m_pCurMethod->m_dwMaxNumExceptions+MAX_EXCEPTIONS]; + if(ptr == NULL) + { + report->error("Failed to reallocate SEH buffer\n"); + return; + } + memcpy(ptr,m_pCurMethod->m_ExceptionList,m_pCurMethod->m_dwNumExceptions*sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT)); + delete [] m_pCurMethod->m_ExceptionList; + m_pCurMethod->m_ExceptionList = ptr; + m_pCurMethod->m_dwMaxNumExceptions += MAX_EXCEPTIONS; + } + + COR_ILMETHOD_SECT_EH_CLAUSE_FAT *clause = &m_pCurMethod->m_ExceptionList[m_pCurMethod->m_dwNumExceptions]; + clause->SetTryOffset(pcStart); + clause->SetTryLength(pcEnd - pcStart); + clause->SetHandlerOffset(pcHandler); + clause->SetHandlerLength(pcHandlerTo - pcHandler); + clause->SetClassToken(crException); + + int flags = COR_ILEXCEPTION_CLAUSE_OFFSETLEN; + if (isFilter) { + flags |= COR_ILEXCEPTION_CLAUSE_FILTER; + } + if (isFault) { + flags |= COR_ILEXCEPTION_CLAUSE_FAULT; + } + if (isFinally) { + flags |= COR_ILEXCEPTION_CLAUSE_FINALLY; + } + clause->SetFlags((CorExceptionFlag)flags); + + m_pCurMethod->m_dwNumExceptions++; +} + +/**************************************************************************/ +void Assembler::EmitMaxStack(unsigned val) +{ + if(val > 0xFFFF) report->warn(".maxstack parameter exceeds 65535, truncated to %d\n",val&0xFFFF); + if (m_pCurMethod) m_pCurMethod->m_MaxStack = val&0xFFFF; + else report->error(".maxstack can be used only within a method scope\n"); +} + +/**************************************************************************/ +void Assembler::EmitLocals(BinStr* sig) +{ + if(sig) + { + if (m_pCurMethod) + { + ARG_NAME_LIST *pAN, *pList= getArgNameList(); + if(pList) + { + VarDescr* pVD; + for(pAN=pList; pAN; pAN = pAN->pNext) + { + if(pAN->dwAttr == 0) pAN->dwAttr = m_pCurMethod->m_Locals.COUNT() +1; + (pAN->dwAttr)--; + if((pVD = m_pCurMethod->m_Locals.PEEK(pAN->dwAttr))) + { + if(pVD->bInScope) + { + report->warn("Local var slot %d is in use\n",pAN->dwAttr); + } + if(pVD->pbsSig && ((pVD->pbsSig->length() != pAN->pSig->length()) || + (memcmp(pVD->pbsSig->ptr(),pAN->pSig->ptr(),pVD->pbsSig->length())))) + { + report->error("Local var slot %d: type conflict\n",pAN->dwAttr); + } + } + else + { // create new entry: + for(unsigned n = m_pCurMethod->m_Locals.COUNT(); n <= pAN->dwAttr; n++) + { + pVD = new VarDescr; + if(pVD != NULL) m_pCurMethod->m_Locals.PUSH(pVD); + else + { + report->error("Out of memory allocating local var descriptor\n"); + delete sig; + return; + } + } + } + pVD->dwSlot = pAN->dwAttr; + pVD->pbsSig = pAN->pSig; + pVD->bInScope = TRUE; + } + if(pVD->pbsSig && (pVD->pbsSig->length() == 1)) + { + if(pVD->pbsSig->ptr()[0] == ELEMENT_TYPE_VOID) + report->error("Illegal local var type: 'void'\n"); + } + m_pCurMethod->m_pCurrScope->pLocals = + m_pCurMethod->catArgNameList(m_pCurMethod->m_pCurrScope->pLocals, pList); + } + } + else report->error(".locals can be used only within a method scope\n"); + delete sig; + } + else report->error("Attempt to EmitLocals with NULL argument\n"); +} + +/**************************************************************************/ +void Assembler::EmitEntryPoint() +{ + if (m_pCurMethod) + { + if(!m_fEntryPointPresent) + { + if(IsMdStatic(m_pCurMethod->m_Attr)) + { + m_pCurMethod->m_fEntryPoint = TRUE; + m_fEntryPointPresent = TRUE; + } + else report->error("Non-static method as entry point\n"); + } + else report->error("Multiple .entrypoint declarations\n"); + } + else report->error(".entrypoint can be used only within a method scope\n"); +} + +/**************************************************************************/ +void Assembler::EmitZeroInit() +{ + if (m_pCurMethod) m_pCurMethod->m_Flags |= CorILMethod_InitLocals; + else report->error(".zeroinit can be used only within a method scope\n"); +} + +/**************************************************************************/ +void Assembler::SetImplAttr(unsigned short attrval) +{ + if (m_pCurMethod) + { + if(IsMiNative(attrval)||IsMiOPTIL(attrval)||IsMiUnmanaged(attrval)) + report->error("Cannot compile native/unmanaged method\n"); + m_pCurMethod->m_wImplAttr = attrval; + } +} + +/**************************************************************************/ +void Assembler::EmitData(__in_opt void *buffer, unsigned len) +{ + if (len != 0) + { + void* ptr; + HRESULT hr = m_pCeeFileGen->GetSectionBlock(m_pCurSection, len, 1, &ptr); + if (FAILED(hr)) + { + report->error("Could not extend data section (out of memory?)"); + exit(1); + } + + if (buffer != NULL) + { + memcpy(ptr, buffer, len); + } + else + { + memset(ptr, 0, len); + } + } +} + +/**************************************************************************/ +void Assembler::EmitDD(__in __nullterminated char *str) +{ + DWORD dwAddr = 0; + GlobalLabel *pLabel = FindGlobalLabel(str); + + ULONG loc; + HRESULT hr = m_pCeeFileGen->GetSectionDataLen(m_pCurSection, &loc); + _ASSERTE(SUCCEEDED(hr)); + + DWORD* ptr; + DWORD sizeofptr = (DWORD)((m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32) ? sizeof(DWORD) : sizeof(__int64)); + hr = m_pCeeFileGen->GetSectionBlock(m_pCurSection, sizeofptr, 1, (void**) &ptr); + if (FAILED(hr)) + { + report->error("Could not extend data section (out of memory?)"); + exit(1); + } + + if (pLabel != 0) { + dwAddr = pLabel->m_GlobalOffset; + if (pLabel->m_Section != m_pGlobalDataSection) { + report->error("For '&label', label must be in data section"); + m_State = STATE_FAIL; + } + } + else + AddDeferredGlobalFixup(str, (BYTE*) ptr); + + hr = m_pCeeFileGen->AddSectionReloc(m_pCurSection, loc, m_pGlobalDataSection, srRelocHighLow); + _ASSERTE(SUCCEEDED(hr)); + if(m_dwCeeFileFlags & ICEE_CREATE_FILE_STRIP_RELOCS) + { + report->error("Base relocations are emitted, while /STRIPRELOC option has been specified"); + } + if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32) + { + m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY; + if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386) + COR_SET_32BIT_REQUIRED(m_dwComImageFlags); + *ptr = dwAddr; + } + else + { + m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY; + *((__int64*)ptr) = (__int64)dwAddr; + } +} + +/**************************************************************************/ +GlobalLabel *Assembler::FindGlobalLabel(LPCUTF8 pszName) +{ + GlobalLabel lSearch(pszName,0,NULL), *pL; + pL = m_lstGlobalLabel.FIND(&lSearch); + lSearch.m_szName = NULL; + return pL; + //return m_lstGlobalLabel.FIND(pszName); +} + +/**************************************************************************/ + +GlobalFixup *Assembler::AddDeferredGlobalFixup(__in __nullterminated char *pszLabel, BYTE* pReference) +{ + GlobalFixup *pNew = new GlobalFixup(pszLabel, (BYTE*) pReference); + if (pNew == NULL) + { + report->error("Failed to allocate global fixup\n"); + m_State = STATE_FAIL; + } + else + m_lstGlobalFixup.PUSH(pNew); + + return pNew; +} + +/**************************************************************************/ +void Assembler::AddDeferredILFixup(ILFixupType Kind) +{ + _ASSERTE(Kind != ilGlobal); + AddDeferredILFixup(Kind, NULL); +} +/**************************************************************************/ + +void Assembler::AddDeferredILFixup(ILFixupType Kind, + GlobalFixup *GFixup) +{ + ILFixup *pNew = new ILFixup(m_CurPC, Kind, GFixup); + + _ASSERTE(m_pCurMethod != NULL); + if (pNew == NULL) + { + report->error("Failed to allocate IL fixup\n"); + m_State = STATE_FAIL; + } + else + m_pCurMethod->m_lstILFixup.PUSH(pNew); +} + +/**************************************************************************/ +void Assembler::EmitDataString(BinStr* str) +{ + if(str) + { + str->appendInt8(0); + DWORD DataLen = str->length(); + char *pb = (char*)(str->ptr()); + WCHAR *UnicodeString = (DataLen >= dwUniBuf) ? new WCHAR[DataLen] : &wzUniBuf[0]; + + if(UnicodeString) + { + WszMultiByteToWideChar(g_uCodePage,0,pb,-1,UnicodeString,DataLen); + EmitData(UnicodeString,DataLen*sizeof(WCHAR)); + if(DataLen >= dwUniBuf) delete [] UnicodeString; + } + else report->error("\nOut of memory!\n"); + delete str; + } +} + + + +/**************************************************************************/ +unsigned Assembler::OpcodeLen(Instr* instr) +{ + return (m_fStdMapping ? OpcodeInfo[instr->opcode].Len : 3); +} +/**************************************************************************/ +void Assembler::EmitOpcode(Instr* instr) +{ + if(m_fGeneratePDB && + ((instr->linenum != m_ulLastDebugLine) + ||(instr->column != m_ulLastDebugColumn) + ||(instr->linenum_end != m_ulLastDebugLineEnd) + ||(instr->column_end != m_ulLastDebugColumnEnd))) + { + if(m_pCurMethod) + { + LinePC *pLPC = new LinePC; + if(pLPC) + { + pLPC->Line = instr->linenum; + pLPC->Column = instr->column; + pLPC->LineEnd = instr->linenum_end; + pLPC->ColumnEnd = instr->column_end; + pLPC->PC = m_CurPC; + pLPC->pWriter = instr->pWriter; + m_pCurMethod->m_LinePCList.PUSH(pLPC); + } + else report->error("\nOut of memory!\n"); + } + m_ulLastDebugLine = instr->linenum; + m_ulLastDebugColumn = instr->column; + m_ulLastDebugLineEnd = instr->linenum_end; + m_ulLastDebugColumnEnd = instr->column_end; + } + if(instr->opcode == CEE_ENDFILTER) + { + if(m_pCurMethod) + { + if(m_pCurMethod->m_dwNumEndfilters >= m_pCurMethod->m_dwMaxNumEndfilters) + { + DWORD *pdw = new DWORD[m_pCurMethod->m_dwMaxNumEndfilters+MAX_EXCEPTIONS]; + if(pdw == NULL) + { + report->error("Failed to reallocate auxiliary SEH buffer\n"); + instr->opcode = -1; + return; + } + memcpy(pdw,m_pCurMethod->m_EndfilterOffsetList,m_pCurMethod->m_dwNumEndfilters*sizeof(DWORD)); + delete m_pCurMethod->m_EndfilterOffsetList; + m_pCurMethod->m_EndfilterOffsetList = pdw; + m_pCurMethod->m_dwMaxNumEndfilters += MAX_EXCEPTIONS; + } + m_pCurMethod->m_EndfilterOffsetList[m_pCurMethod->m_dwNumEndfilters++] = m_CurPC+2; + } + } + if (m_fStdMapping) + { + if (OpcodeInfo[instr->opcode].Len == 2) + EmitByte(OpcodeInfo[instr->opcode].Std1); + EmitByte(OpcodeInfo[instr->opcode].Std2); + } + else + { + unsigned short us = (unsigned short)instr->opcode; + EmitByte(REFPRE); + EmitBytes((BYTE *)&us,2); + } + instr->opcode = -1; +} + +/**************************************************************************/ +//void Assembler::OptimizeInstr(Instr* instr, int var) +//{ + +//} +/**************************************************************************/ +unsigned Assembler::ShortOf(unsigned opcode) +{ + unsigned retcode; + switch(opcode) + { + case CEE_LDARG: retcode=CEE_LDARG_S; break; + case CEE_LDARGA: retcode=CEE_LDARGA_S; break; + case CEE_STARG: retcode=CEE_STARG_S; break; + + case CEE_LDLOC: retcode=CEE_LDLOC_S; break; + case CEE_LDLOCA: retcode=CEE_LDLOCA_S; break; + case CEE_STLOC: retcode=CEE_STLOC_S; break; + + case CEE_BR: retcode=CEE_BR_S; break; + case CEE_BRFALSE: retcode=CEE_BRFALSE_S; break; + case CEE_BRTRUE: retcode=CEE_BRTRUE_S; break; + case CEE_BEQ: retcode=CEE_BEQ_S; break; + case CEE_BGE: retcode=CEE_BGE_S; break; + case CEE_BGT: retcode=CEE_BGT_S; break; + case CEE_BLE: retcode=CEE_BLE_S; break; + case CEE_BLT: retcode=CEE_BLT_S; break; + case CEE_BNE_UN: retcode=CEE_BNE_UN_S; break; + case CEE_BGE_UN: retcode=CEE_BGE_UN_S; break; + case CEE_BGT_UN: retcode=CEE_BGT_UN_S; break; + case CEE_BLE_UN: retcode=CEE_BLE_UN_S; break; + case CEE_BLT_UN: retcode=CEE_BLT_UN_S; break; + case CEE_LEAVE: retcode=CEE_LEAVE_S; break; + + case CEE_LDC_I4: retcode=CEE_LDC_I4_S; break; + case CEE_LDC_R8: retcode=CEE_LDC_R4; break; + + + default: retcode = opcode; break; + } + return retcode; +} + +/**************************************************************************/ +void Assembler::EmitInstrVar(Instr* instr, int var) +{ + unsigned opc = instr->opcode; + if(m_fOptimize) + { + if(var < 4) + { + switch(opc) + { + case CEE_LDARG: + case CEE_LDARG_S: opc = CEE_LDARG_0 + var; break; + + case CEE_LDLOC: + case CEE_LDLOC_S: opc = CEE_LDLOC_0 + var; break; + + case CEE_STLOC: + case CEE_STLOC_S: opc = CEE_STLOC_0 + var; break; + + default: break; + } + if(opc != (unsigned) instr->opcode) + { + instr->opcode = opc; + EmitOpcode(instr); + return; + } + } + if(var <= 0xFF) + { + opc = instr->opcode = ShortOf(opc); + } + } + EmitOpcode(instr); + if (isShort(opc)) + { + EmitByte(var); + } + else + { + short sh = (short)var; + EmitBytes((BYTE *)&sh,2); + } +} + +/**************************************************************************/ +void Assembler::EmitInstrVarByName(Instr* instr, __in __nullterminated char* label) +{ + int idx = -1, nArgVarFlag=0; + switch(instr->opcode) + { + case CEE_LDARGA: + case CEE_LDARGA_S: + case CEE_LDARG: + case CEE_LDARG_S: + case CEE_STARG: + case CEE_STARG_S: + nArgVarFlag++; + case CEE_LDLOCA: + case CEE_LDLOCA_S: + case CEE_LDLOC: + case CEE_LDLOC_S: + case CEE_STLOC: + case CEE_STLOC_S: + + if(m_pCurMethod) + { + DWORD L = (DWORD)strlen(label); + if(nArgVarFlag == 1) + { + idx = m_pCurMethod->findArgNum(m_pCurMethod->m_firstArgName,label,L); + } + else + { + for(Scope* pSC = m_pCurMethod->m_pCurrScope; pSC; pSC=pSC->pSuperScope) + { + idx = m_pCurMethod->findLocSlot(pSC->pLocals,label,L); + if(idx >= 0) break; + } + } + if(idx >= 0) EmitInstrVar(instr, + ((nArgVarFlag==0)||(m_pCurMethod->m_Attr & mdStatic))? idx : idx+1); + else report->error("Undeclared identifier %s\n",label); + } + else + report->error("Instructions can be used only when in a method scope\n"); + break; + default: + report->error("Named argument illegal for this instruction\n"); + } + instr->opcode = -1; // in case we got here with error +} + +/**************************************************************************/ +void Assembler::EmitInstrI(Instr* instr, int val) +{ + int opc = instr->opcode; + if(m_fOptimize) + { + if((val >= -1)&&(val <= 8)) + { + switch(opc) + { + case CEE_LDC_I4: + case CEE_LDC_I4_S: opc = CEE_LDC_I4_M1 + (val+1); break; + + default: break; + } + if(opc != instr->opcode) + { + instr->opcode = opc; + EmitOpcode(instr); + return; + } + } + if((-128 <= val)&&(val <= 127)) + { + opc = instr->opcode = ShortOf(opc); + } + } + EmitOpcode(instr); + if (isShort(opc)) + { + EmitByte(val); + } + else + { + int i = val; + EmitBytes((BYTE *)&i,sizeof(int)); + } +} + +/**************************************************************************/ +void Assembler::EmitInstrI8(Instr* instr, __int64* val) +{ + EmitOpcode(instr); + EmitBytes((BYTE *)val, sizeof(__int64)); + delete val; +} + +/**************************************************************************/ +void Assembler::EmitInstrR(Instr* instr, double* pval) +{ + unsigned opc = instr->opcode; + EmitOpcode(instr); + if (isShort(opc)) + { + float val = (float)*pval; + EmitBytes((BYTE *)&val, sizeof(float)); + } + else + EmitBytes((BYTE *)pval, sizeof(double)); +} + +/**************************************************************************/ +void Assembler::EmitInstrBrTarget(Instr* instr, __in __nullterminated char* label) +{ + Label * pLabel = m_pCurMethod->FindLabel(label); + int offset=0; + if (pLabel == NULL) // branching forward -- no optimization + { + int pcrelsize = 1+(isShort(instr->opcode) ? 1 : 4); //size of the instruction plus argument + AddDeferredFixup(label, m_pCurOutputPos+1, + (m_CurPC + pcrelsize), pcrelsize-1); + } + else + { + offset = pLabel->m_PC - m_CurPC; + if(m_fOptimize) + { + if((-128 <= offset-5)&&(offset-2 <= 127)) //need to take into account the argument size (worst cases) + { + instr->opcode = ShortOf(instr->opcode); + } + } + if(isShort(instr->opcode)) + { + offset -= 2; + if((-128 > offset)||(offset > 127)) + report->error("Offset too large for short branching instruction, truncated\n"); + } + else + offset -= 5; + delete [] label; + } + int opc = instr->opcode; + EmitOpcode(instr); + if(isShort(opc)) EmitByte(offset); + else EmitBytes((BYTE *)&offset,4); +} +/**************************************************************************/ +void Assembler::AddDeferredFixup(__in __nullterminated char *pszLabel, BYTE *pBytes, DWORD RelativeToPC, BYTE FixupSize) +{ + Fixup *pNew = new Fixup(pszLabel, pBytes, RelativeToPC, FixupSize); + + if (pNew == NULL) + { + report->error("Failed to allocate deferred fixup\n"); + m_State = STATE_FAIL; + } + else + m_pCurMethod->m_lstFixup.PUSH(pNew); +} +/**************************************************************************/ +void Assembler::EmitInstrBrOffset(Instr* instr, int offset) +{ + unsigned opc=instr->opcode; + if(m_fOptimize) + { + if((-128 >= offset)&&(offset <= 127)) + { + opc = instr->opcode = ShortOf(opc); + } + } + EmitOpcode(instr); + if(isShort(opc)) EmitByte(offset); + else + { + int i = offset; + EmitBytes((BYTE *)&i,4); + } +} + +/**************************************************************************/ +mdToken Assembler::MakeMemberRef(mdToken cr, __in __nullterminated char* pszMemberName, BinStr* sig) +{ + DWORD cSig = sig->length(); + COR_SIGNATURE* mySig = (COR_SIGNATURE *)(sig->ptr()); + mdToken mr = mdMemberRefNil; + Class* pClass = NULL; + if(cr == 0x00000001) cr = mdTokenNil; // Module -> nil for globals + if(TypeFromToken(cr) == mdtTypeDef) pClass = m_lstClass.PEEK(RidFromToken(cr)-1); + if((TypeFromToken(cr) == mdtTypeDef)||(cr == mdTokenNil)) + { + MemberRefDescriptor* pMRD = new MemberRefDescriptor; + if(pMRD) + { + pMRD->m_tdClass = cr; + pMRD->m_pClass = pClass; + pMRD->m_szName = pszMemberName; + pMRD->m_dwName = (DWORD)strlen(pszMemberName); + pMRD->m_pSigBinStr = sig; + pMRD->m_tkResolved = 0; + if(*(sig->ptr())== IMAGE_CEE_CS_CALLCONV_FIELD) + { + m_LocalFieldRefDList.PUSH(pMRD); + mr = 0x98000000 | m_LocalFieldRefDList.COUNT(); + } + else + { + m_LocalMethodRefDList.PUSH(pMRD); + mr = 0x99000000 | m_LocalMethodRefDList.COUNT(); + } + } + else + { + report->error("Failed to allocate MemberRef Descriptor\n"); + return 0; + } + } + else + { + WszMultiByteToWideChar(g_uCodePage,0,pszMemberName,-1,wzUniBuf,dwUniBuf); + + if(cr == mdTokenNil) cr = mdTypeRefNil; + if(TypeFromToken(cr) == mdtAssemblyRef) + { + report->error("Cross-assembly global references are not supported ('%s')\n", pszMemberName); + mr = 0; + } + else + { + HRESULT hr = m_pEmitter->DefineMemberRef(cr, wzUniBuf, mySig, cSig, &mr); + if(FAILED(hr)) + { + report->error("Unable to define member reference '%s'\n", pszMemberName); + mr = 0; + } + } + //if(m_fOBJ) m_pCurMethod->m_TRDList.PUSH(new TokenRelocDescr(m_CurPC,mr)); + delete pszMemberName; + delete sig; + } + return mr; +} +/**************************************************************************/ +void Assembler::SetMemberRefFixup(mdToken tk, unsigned opcode_len) +{ + if(opcode_len) + { + switch(TypeFromToken(tk)) + { + case 0x98000000: + case 0x99000000: + case 0x9A000000: + if(m_pCurMethod != NULL) + m_pCurMethod->m_LocalMemberRefFixupList.PUSH( + new LocalMemberRefFixup(tk,(size_t)(m_CurPC + opcode_len))); + break; + } + } +} + +/**************************************************************************/ +mdToken Assembler::MakeMethodSpec(mdToken tkParent, BinStr* sig) +{ + DWORD cSig = sig->length(); + COR_SIGNATURE* mySig = (COR_SIGNATURE *)(sig->ptr()); + mdMethodSpec mi = mdMethodSpecNil; + if(TypeFromToken(tkParent) == 0x99000000) // Local MemberRef: postpone until resolved + { + MemberRefDescriptor* pMRD = new MemberRefDescriptor; + if(pMRD) + { + memset(pMRD,0,sizeof(MemberRefDescriptor)); + pMRD->m_tdClass = tkParent; + pMRD->m_pSigBinStr = sig; + m_MethodSpecList.PUSH(pMRD); + mi = 0x9A000000 | m_MethodSpecList.COUNT(); + } + else + { + report->error("Failed to allocate MemberRef Descriptor\n"); + return 0; + } + } + else + { + HRESULT hr = m_pEmitter->DefineMethodSpec(tkParent, mySig, cSig, &mi); + if(FAILED(hr)) + { + report->error("Unable to define method instantiation"); + return 0; + } + } + return mi; +} + +/**************************************************************************/ +void Assembler::EndEvent(void) +{ + Class* pClass = (m_pCurClass ? m_pCurClass : m_pModuleClass); + if(m_pCurEvent->m_tkAddOn == 0) + report->error("Event %s of class %s has no Add method. Event not emitted.", + m_pCurEvent->m_szName,pClass->m_szFQN); + else if(m_pCurEvent->m_tkRemoveOn == 0) + report->error("Event %s of class %s has no Remove method. Event not emitted.", + m_pCurEvent->m_szName,pClass->m_szFQN); + else + { + pClass->m_EventDList.PUSH(m_pCurEvent); + pClass->m_fNewMembers = TRUE; + } + m_pCurEvent = NULL; + m_tkCurrentCVOwner = 0; + m_pCustomDescrList = m_CustomDescrListStack.POP(); +} + +void Assembler::ResetEvent(__inout_z __inout char* szName, mdToken typeSpec, DWORD dwAttr) +{ + if(strlen(szName) >= MAX_CLASSNAME_LENGTH) + { + char c = szName[MAX_CLASSNAME_LENGTH-1]; + szName[MAX_CLASSNAME_LENGTH-1] = 0; + report->error("Event '%s...' -- name too long (%d characters).\n",szName,strlen(szName)); + szName[MAX_CLASSNAME_LENGTH-1] = c; + } + if((m_pCurEvent = new EventDescriptor)) + { + memset(m_pCurEvent,0,sizeof(EventDescriptor)); + m_pCurEvent->m_tdClass = m_pCurClass->m_cl; + m_pCurEvent->m_szName = szName; + m_pCurEvent->m_dwAttr = dwAttr; + m_pCurEvent->m_tkEventType = typeSpec; + m_pCurEvent->m_fNew = TRUE; + m_tkCurrentCVOwner = 0; + m_CustomDescrListStack.PUSH(m_pCustomDescrList); + m_pCustomDescrList = &(m_pCurEvent->m_CustomDescrList); + } + else report->error("Failed to allocate Event Descriptor\n"); +} + +void Assembler::SetEventMethod(int MethodCode, mdToken tk) +{ + switch(MethodCode) + { + case 0: + m_pCurEvent->m_tkAddOn = tk; + break; + case 1: + m_pCurEvent->m_tkRemoveOn = tk; + break; + case 2: + m_pCurEvent->m_tkFire = tk; + break; + case 3: + m_pCurEvent->m_tklOthers.PUSH((mdToken*)(UINT_PTR)tk); + break; + } +} +/**************************************************************************/ + +void Assembler::EndProp(void) +{ + Class* pClass = (m_pCurClass ? m_pCurClass : m_pModuleClass); + pClass->m_PropDList.PUSH(m_pCurProp); + pClass->m_fNewMembers = TRUE; + m_pCurProp = NULL; + m_tkCurrentCVOwner = 0; + m_pCustomDescrList = m_CustomDescrListStack.POP(); +} + +void Assembler::ResetProp(__inout_z __inout char * szName, BinStr* bsType, DWORD dwAttr, BinStr* pValue) +{ + DWORD cSig = bsType->length(); + COR_SIGNATURE* mySig = (COR_SIGNATURE *)(bsType->ptr()); + + if(strlen(szName) >= MAX_CLASSNAME_LENGTH) + { + char c = szName[MAX_CLASSNAME_LENGTH-1]; + szName[MAX_CLASSNAME_LENGTH-1] = 0; + report->error("Property '%s...' -- name too long (%d characters).\n",szName,strlen(szName)); + szName[MAX_CLASSNAME_LENGTH-1] = c; + } + m_pCurProp = new PropDescriptor; + if(m_pCurProp == NULL) + { + report->error("Failed to allocate Property Descriptor\n"); + return; + } + memset(m_pCurProp,0,sizeof(PropDescriptor)); + m_pCurProp->m_tdClass = m_pCurClass->m_cl; + m_pCurProp->m_szName = szName; + m_pCurProp->m_dwAttr = dwAttr; + m_pCurProp->m_fNew = TRUE; + + m_pCurProp->m_pSig = new COR_SIGNATURE[cSig]; + if(m_pCurProp->m_pSig == NULL) + { + report->error("\nOut of memory!\n"); + return; + } + memcpy(m_pCurProp->m_pSig,mySig,cSig); + m_pCurProp->m_dwCSig = cSig; + + if(pValue && pValue->length()) + { + BYTE* pch = pValue->ptr(); + m_pCurProp->m_dwCPlusTypeFlag = (DWORD)(*pch); + m_pCurProp->m_cbValue = pValue->length() - 1; + m_pCurProp->m_pValue = (PVOID)(pch+1); + if(m_pCurProp->m_dwCPlusTypeFlag == ELEMENT_TYPE_STRING) m_pCurProp->m_cbValue /= sizeof(WCHAR); + m_pCurProp->m_dwAttr |= prHasDefault; + } + else + { + m_pCurProp->m_dwCPlusTypeFlag = ELEMENT_TYPE_VOID; + m_pCurProp->m_pValue = NULL; + m_pCurProp->m_cbValue = 0; + } + m_tkCurrentCVOwner = 0; + m_CustomDescrListStack.PUSH(m_pCustomDescrList); + m_pCustomDescrList = &(m_pCurProp->m_CustomDescrList); +} + +void Assembler::SetPropMethod(int MethodCode, mdToken tk) +{ + switch(MethodCode) + { + case 0: + m_pCurProp->m_tkSet = tk; + break; + case 1: + m_pCurProp->m_tkGet = tk; + break; + case 2: + m_pCurProp->m_tklOthers.PUSH((mdToken*)(UINT_PTR)tk); + break; + } +} + +/**************************************************************************/ +void Assembler::EmitInstrStringLiteral(Instr* instr, BinStr* literal, BOOL ConvertToUnicode, BOOL Swap /*=FALSE*/) +{ + DWORD DataLen = literal->length(),L; + unsigned __int8 *pb = literal->ptr(); + HRESULT hr = S_OK; + mdToken tk; + WCHAR *UnicodeString; + if(DataLen == 0) + { + //report->warn("Zero length string emitted\n"); + ConvertToUnicode = FALSE; + } + if(ConvertToUnicode) + { + UnicodeString = (DataLen >= dwUniBuf) ? new WCHAR[DataLen+1] : &wzUniBuf[0]; + literal->appendInt8(0); + pb = literal->ptr(); + // convert string to Unicode + L = UnicodeString ? WszMultiByteToWideChar(g_uCodePage,0,(char*)pb,-1,UnicodeString,DataLen+1) : 0; + if(L == 0) + { + const char* sz=NULL; + DWORD dw; + switch(dw=GetLastError()) + { + case ERROR_INSUFFICIENT_BUFFER: sz = "ERROR_INSUFFICIENT_BUFFER"; break; + case ERROR_INVALID_FLAGS: sz = "ERROR_INVALID_FLAGS"; break; + case ERROR_INVALID_PARAMETER: sz = "ERROR_INVALID_PARAMETER"; break; + case ERROR_NO_UNICODE_TRANSLATION: sz = "ERROR_NO_UNICODE_TRANSLATION"; break; + } + if(sz) report->error("Failed to convert string '%s' to Unicode: %s\n",(char*)pb,sz); + else report->error("Failed to convert string '%s' to Unicode: error 0x%08X\n",(char*)pb,dw); + delete instr; + goto OuttaHere; + } + L--; + } + else + { + if(DataLen & 1) + { + literal->appendInt8(0); + pb = literal->ptr(); + DataLen++; + } + UnicodeString = (WCHAR*)pb; + L = DataLen/sizeof(WCHAR); + +#if BIGENDIAN + if (Swap) + SwapStringLength(UnicodeString, L); +#endif + } + // Add the string data to the metadata, which will fold dupes. + hr = m_pEmitter->DefineUserString( + UnicodeString, + L, + &tk + ); + if (FAILED(hr)) + { + report->error("Failed to add user string using DefineUserString, hr=0x%08x, data: '%S'\n", + hr, UnicodeString); + delete instr; + } + else + { + EmitOpcode(instr); + if(m_fOBJ) m_pCurMethod->m_TRDList.PUSH(new TokenRelocDescr(m_CurPC,tk)); + + EmitBytes((BYTE *)&tk,sizeof(mdToken)); + } +OuttaHere: + delete literal; + if(((void*)UnicodeString != (void*)pb)&&(DataLen >= dwUniBuf)) delete [] UnicodeString; + instr->opcode = -1; // in case we got here with error +} + +/**************************************************************************/ +void Assembler::EmitInstrSig(Instr* instr, BinStr* sig) +{ + mdSignature MetadataToken; + DWORD cSig = sig->length(); + COR_SIGNATURE* mySig = (COR_SIGNATURE *)(sig->ptr()); + + if (FAILED(m_pEmitter->GetTokenFromSig(mySig, cSig, &MetadataToken))) + { + report->error("Unable to convert signature to metadata token.\n"); + delete instr; + } + else + { + EmitOpcode(instr); + if(m_fOBJ) m_pCurMethod->m_TRDList.PUSH(new TokenRelocDescr(m_CurPC,MetadataToken)); + EmitBytes((BYTE *)&MetadataToken, sizeof(mdSignature)); + } + delete sig; + instr->opcode = -1; // in case we got here with error +} + +/**************************************************************************/ +void Assembler::EmitInstrSwitch(Instr* instr, Labels* targets) +{ + Labels *pLbls; + int NumLabels; + Label *pLabel; + UINT offset; + + EmitOpcode(instr); + + // count # labels + for(pLbls = targets, NumLabels = 0; pLbls; pLbls = pLbls->Next, NumLabels++); + + EmitBytes((BYTE *)&NumLabels,sizeof(int)); + DWORD PC_nextInstr = m_CurPC + 4*NumLabels; + for(pLbls = targets; pLbls; pLbls = pLbls->Next) + { + if(pLbls->isLabel) + { + if((pLabel = m_pCurMethod->FindLabel(pLbls->Label))) + { + offset = pLabel->m_PC - PC_nextInstr; + if (m_fDisplayTraceOutput) report->msg("%d\n", offset); + } + else + { + // defer until we find the label + AddDeferredFixup(pLbls->Label, m_pCurOutputPos, PC_nextInstr, 4 /* pcrelsize */ ); + offset = 0; + pLbls->Label = NULL; + if (m_fDisplayTraceOutput) report->msg("forward label %s\n", pLbls->Label); + } + } + else + { + offset = (UINT)(UINT_PTR)pLbls->Label; + if (m_fDisplayTraceOutput) report->msg("%d\n", offset); + } + EmitBytes((BYTE *)&offset, sizeof(UINT)); + } + delete targets; +} + +/**************************************************************************/ +void Assembler::EmitLabel(__in __nullterminated char* label) +{ + _ASSERTE(m_pCurMethod); + AddLabel(m_CurPC, label); +} +/**************************************************************************/ +void Assembler::EmitDataLabel(__in __nullterminated char* label) +{ + AddGlobalLabel(label, m_pCurSection); +} + +/**************************************************************************/ +void Assembler::EmitBytes(BYTE *p, unsigned len) +{ + if(m_pCurOutputPos + len >= m_pEndOutputPos) + { + size_t buflen = m_pEndOutputPos - m_pOutputBuffer; + size_t newlen = buflen+(len/OUTPUT_BUFFER_INCREMENT + 1)*OUTPUT_BUFFER_INCREMENT; + BYTE *pb = new BYTE[newlen]; + if(pb == NULL) + { + report->error("Failed to extend output buffer from %d to %d bytes. Aborting\n", + buflen, newlen); + exit(1); + } + size_t delta = pb - m_pOutputBuffer; + int i; + Fixup* pSearch; + GlobalFixup *pGSearch; + for (i=0; (pSearch = m_pCurMethod->m_lstFixup.PEEK(i)); i++) pSearch->m_pBytes += delta; + for (i=0; (pGSearch = m_lstGlobalFixup.PEEK(i)); i++) //need to move only those pointing to output buffer + { + if((pGSearch->m_pReference >= m_pOutputBuffer)&&(pGSearch->m_pReference <= m_pEndOutputPos)) + pGSearch->m_pReference += delta; + } + + + memcpy(pb,m_pOutputBuffer,m_CurPC); + delete m_pOutputBuffer; + m_pOutputBuffer = pb; + m_pCurOutputPos = &m_pOutputBuffer[m_CurPC]; + m_pEndOutputPos = &m_pOutputBuffer[newlen]; + + } + + switch (len) + { + case 1: + *m_pCurOutputPos = *p; + break; + case 2: + SET_UNALIGNED_VAL16(m_pCurOutputPos, GET_UNALIGNED_16(p)); + break; + case 4: + SET_UNALIGNED_VAL32(m_pCurOutputPos, GET_UNALIGNED_32(p)); + break; + case 8: + SET_UNALIGNED_VAL64(m_pCurOutputPos, GET_UNALIGNED_64(p)); + break; + default: + _ASSERTE(!"NYI"); + break; + } + + m_pCurOutputPos += len; + m_CurPC += len; +} +/**************************************************************************/ +BinStr* Assembler::EncodeSecAttr(__in __nullterminated char* szReflName, BinStr* pbsSecAttrBlob, unsigned nProps) +{ + unsigned cnt; +#if (0) + // Emit MemberRef for .ctor + mdToken tkMscorlib = m_fIsMscorlib ? 1 : GetAsmRef("mscorlib"); + char buffer[64]; + BinStr *pbsSig = new BinStr(); + + strcpy(buffer,"System.Security.Permissions.SecurityAction"); + mdToken tkSecAction = ResolveClassRef(tkMscorlib,buffer, NULL); + + pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_HASTHIS); + pbsSig->appendInt8(1); //corEmitInt(pbsSig,1); + pbsSig->appendInt8(ELEMENT_TYPE_VOID); + pbsSig->appendInt8(ELEMENT_TYPE_VALUETYPE); + cnt = CorSigCompressToken(tkSecAction, pbsSig->getBuff(5)); + pbsSig->remove(5 - cnt); + + char* szName = new char[16]; + strcpy(szName,".ctor"); + MakeMemberRef(tkSecAttr,szName,pbsSig); +#endif + + // build the blob As BinStr + unsigned L = (unsigned) strlen(szReflName); + BYTE* pb = NULL; + BinStr* pbsRet = new BinStr(); + // encode the Reflection name length + cnt = CorSigCompressData(L, pbsRet->getBuff(5)); + pbsRet->remove(5 - cnt); + //put the name in + if((pb = pbsRet->getBuff(L)) != NULL) + memcpy(pb,szReflName,L); + // find out the size of compressed nProps + cnt = CorSigCompressData(nProps, pbsRet->getBuff(5)); + pbsRet->remove(5); + // encode blob size + unsigned nSize = cnt + pbsSecAttrBlob->length(); + cnt = CorSigCompressData(nSize, pbsRet->getBuff(5)); + pbsRet->remove(5 - cnt); + // actually encode nProps + cnt = CorSigCompressData(nProps, pbsRet->getBuff(5)); + pbsRet->remove(5 - cnt); + // append the props/values blob + pbsRet->append(pbsSecAttrBlob); + delete pbsSecAttrBlob; + return pbsRet; +} +/**************************************************************************/ +void Assembler::EmitSecurityInfo(mdToken token, + PermissionDecl* pPermissions, + PermissionSetDecl* pPermissionSets) +{ + PermissionDecl *pPerm, *pPermNext; + PermissionSetDecl *pPset, *pPsetNext; + unsigned uCount = 0; + COR_SECATTR *pAttrs; + unsigned i; + unsigned uLength; + mdTypeRef tkTypeRef; + BinStr *pSig; + char *szMemberName; + DWORD dwErrorIndex = 0; + + if (pPermissions) { + + for (pPerm = pPermissions; pPerm; pPerm = pPerm->m_Next) + uCount++; + + _ASSERTE(uCount > 0); + // uCount is expected to be positive all the time. The if statement is here to please prefast. + if (uCount > 0) + { + if((pAttrs = new COR_SECATTR[uCount])==NULL) + { + report->error("\nOut of memory!\n"); + return; + } + + mdToken tkMscorlib = m_fIsMscorlib ? 1 : GetAsmRef("mscorlib"); + tkTypeRef = ResolveClassRef(tkMscorlib,"System.Security.Permissions.SecurityAction", NULL); + for (pPerm = pPermissions, i = 0; pPerm; pPerm = pPermNext, i++) { + pPermNext = pPerm->m_Next; + + pSig = new BinStr(); + pSig->appendInt8(IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS); + pSig->appendInt8(1); + pSig->appendInt8(ELEMENT_TYPE_VOID); + pSig->appendInt8(ELEMENT_TYPE_VALUETYPE); + uLength = CorSigCompressToken(tkTypeRef, pSig->getBuff(5)); + pSig->remove(5 - uLength); + + uLength = (unsigned)strlen(COR_CTOR_METHOD_NAME) + 1; + if((szMemberName = new char[uLength])) + { + memcpy(szMemberName, COR_CTOR_METHOD_NAME, uLength); + pAttrs[i].tkCtor = MakeMemberRef(pPerm->m_TypeSpec, szMemberName, pSig); + pAttrs[i].pCustomAttribute = (const void *)pPerm->m_Blob; + pAttrs[i].cbCustomAttribute = pPerm->m_BlobLength; + } + else report->error("\nOut of memory!\n"); + } + + if (FAILED(m_pEmitter->DefineSecurityAttributeSet(token, + pAttrs, + uCount, + &dwErrorIndex))) + { + _ASSERT(uCount >= dwErrorIndex); + if (dwErrorIndex == uCount) + { + report->error("Failed to define security attribute set for 0x%08X\n", token); + } + else + { + report->error("Failed to define security attribute set for 0x%08X\n (error in permission %u)\n", + token, uCount - dwErrorIndex); + } + } + delete [] pAttrs; + for (pPerm = pPermissions, i = 0; pPerm; pPerm = pPermNext, i++) { + pPermNext = pPerm->m_Next; + delete pPerm; + } + } + } + + for (pPset = pPermissionSets; pPset; pPset = pPsetNext) { + pPsetNext = pPset->m_Next; + if(FAILED(m_pEmitter->DefinePermissionSet(token, + pPset->m_Action, + pPset->m_Value->ptr(), + pPset->m_Value->length(), + NULL))) + report->error("Failed to define security permission set for 0x%08X\n", token); + delete pPset; + } +} + +void Assembler::AddMethodImpl(mdToken tkImplementedTypeSpec, __in __nullterminated char* szImplementedName, BinStr* pImplementedSig, + mdToken tkImplementingTypeSpec, __in_opt __nullterminated char* szImplementingName, BinStr* pImplementingSig) +{ + if(m_pCurClass) + { + MethodImplDescriptor* pMID = new MethodImplDescriptor; + pMID->m_fNew = TRUE; + if(pMID == NULL) + { + report->error("Failed to allocate MethodImpl Descriptor\n"); + return; + } + pMID->m_tkDefiningClass = m_pCurClass->m_cl; + if(szImplementingName) //called from class scope, overriding method specified + { + pMID->m_tkImplementedMethod = MakeMemberRef(tkImplementedTypeSpec,szImplementedName,pImplementedSig); + pMID->m_tkImplementingMethod = MakeMemberRef(tkImplementingTypeSpec,szImplementingName,pImplementingSig); + } + else //called from method scope, use current method as overriding + { + if(m_pCurMethod) + { + if (pImplementedSig == NULL) + { + pImplementedSig = new BinStr(); + memcpy(pImplementedSig->getBuff(m_pCurMethod->m_dwMethodCSig), m_pCurMethod->m_pMethodSig,m_pCurMethod->m_dwMethodCSig); + } + pMID->m_tkImplementedMethod = MakeMemberRef(tkImplementedTypeSpec,szImplementedName,pImplementedSig); + pMID->m_tkImplementingMethod = 0; + + m_pCurMethod->m_MethodImplDList.PUSH(pMID); // copy goes to method's own list (ptr only) + } + else + { + report->error("No overriding method specified"); + delete pMID; + return; + } + } + m_MethodImplDList.PUSH(pMID); + } + else + report->error(".override directive outside class scope"); +} +// source file name paraphernalia +void Assembler::SetSourceFileName(__in __nullterminated char* szName) +{ + if(szName) + { + if(*szName) + { + if(strcmp(m_szSourceFileName,szName)) + { + strcpy_s(m_szSourceFileName,MAX_FILENAME_LENGTH*3+1,szName); + WszMultiByteToWideChar(g_uCodePage,0,szName,-1,m_wzSourceFileName,MAX_FILENAME_LENGTH); + } + if(m_fGeneratePDB) + { + DocWriter* pDW; + unsigned i=0; + while((pDW = m_DocWriterList.PEEK(i++)) != NULL) + { + if(!strcmp(szName,pDW->Name)) break; + } + if(pDW) + { + m_pSymDocument = pDW->pWriter; + delete [] szName; + } + else if(m_pSymWriter) + { + HRESULT hr; + WszMultiByteToWideChar(g_uCodePage,0,szName,-1,wzUniBuf,dwUniBuf); + if(FAILED(hr=m_pSymWriter->DefineDocument(wzUniBuf,&m_guidLang, + &m_guidLangVendor,&m_guidDoc,&m_pSymDocument))) + { + m_pSymDocument = NULL; + report->error("Failed to define a document writer"); + } + if((pDW = new DocWriter()) != NULL) + { + pDW->Name = szName; + pDW->pWriter = m_pSymDocument; + m_DocWriterList.PUSH(pDW); + } + else + { + report->error("Out of memory"); + delete [] szName; + } + } + else delete [] szName; + } + else delete [] szName; + } + else delete [] szName; + } +} +void Assembler::SetSourceFileName(BinStr* pbsName) +{ + ULONG L; + if(pbsName && (L = (ULONG)(pbsName->length()))) + { + pbsName->appendInt8(0); + char* sz = new char[L+1]; + memcpy(sz,pbsName->ptr(),L+1); + SetSourceFileName(sz); + delete pbsName; + } +} |