// 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; 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 mdToken Token() const { return token_; } }; static RBTREE typeSpecCache; extern FIFO 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() { // First we check for "System.Private.CoreLib" as the base or System assembly // AsmManAssembly* coreLibAsm = m_pManifest->GetAsmRefByAsmName("System.Private.CoreLib"); if(coreLibAsm != NULL) { return GetAsmRef(coreLibAsm->szAlias ? coreLibAsm->szAlias : coreLibAsm->szName); } AsmManAssembly* sysRuntime = m_pManifest->GetAsmRefByAsmName("System.Runtime"); if(sysRuntime != NULL) { return GetAsmRef(sysRuntime->szAlias ? sysRuntime->szAlias : sysRuntime->szName); } AsmManAssembly* mscorlibAsm = m_pManifest->GetAsmRefByAsmName("mscorlib"); if(mscorlibAsm != NULL) { return GetAsmRef(mscorlibAsm->szAlias ? mscorlibAsm->szAlias : mscorlibAsm->szName); } AsmManAssembly* netstandardAsm = m_pManifest->GetAsmRefByAsmName("netstandard"); if (netstandardAsm != NULL) { return GetAsmRef(netstandardAsm->szAlias ? netstandardAsm->szAlias : netstandardAsm->szName); } 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"); } 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