diff options
Diffstat (limited to 'src/ilasm/assem.cpp')
-rw-r--r-- | src/ilasm/assem.cpp | 1654 |
1 files changed, 1654 insertions, 0 deletions
diff --git a/src/ilasm/assem.cpp b/src/ilasm/assem.cpp new file mode 100644 index 0000000000..8c56bdc047 --- /dev/null +++ b/src/ilasm/assem.cpp @@ -0,0 +1,1654 @@ +// 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: assem.cpp +// + +// +// COM+ IL assembler +// +#include "ilasmpch.h" + +#define INITGUID + +#define DECLARE_DATA + +#include "assembler.h" +#ifdef FEATURE_CORECLR +#ifdef FEATURE_PAL +#include "coreclrloader.h" +CoreCLRLoader *g_loader; +#endif // FEATURE_PAL +MetaDataGetDispenserFunc metaDataGetDispenser; +#else +#include "MscorpeSxS.h" +#endif // FEATURE_CORECLR + +void indexKeywords(Indx* indx); // defined in asmparse.y + +unsigned int g_uCodePage = CP_ACP; +unsigned int g_uConsoleCP = CP_ACP; + +char g_szSourceFileName[MAX_FILENAME_LENGTH*3]; + +WCHAR wzUniBuf[dwUniBuf]; // Unicode conversion global buffer + +Assembler::Assembler() +{ + m_pDisp = NULL; + m_pEmitter = NULL; + m_pImporter = NULL; + + m_fCPlusPlus = FALSE; + m_fWindowsCE = FALSE; + char* pszFQN = new char[16]; + strcpy_s(pszFQN,16,"<Module>"); + m_pModuleClass = new Class(pszFQN); + m_lstClass.PUSH(m_pModuleClass); + m_hshClass.PUSH(m_pModuleClass); + m_pModuleClass->m_cl = mdTokenNil; + m_pModuleClass->m_bIsMaster = FALSE; + + m_fStdMapping = FALSE; + m_fDisplayTraceOutput= FALSE; + m_fENCMode = FALSE; + m_fTolerateDupMethods = FALSE; + + m_pCurOutputPos = NULL; + + m_CurPC = 0; // PC offset in method + m_pCurMethod = NULL; + m_pCurClass = NULL; + m_pCurEvent = NULL; + m_pCurProp = NULL; + + m_wzMetadataVersion = NULL; + m_wMSVmajor = 0xFFFF; + m_wMSVminor = 0xFFFF; + + m_wSSVersionMajor = 4; + m_wSSVersionMinor = 0; + m_fAppContainer = FALSE; + m_fHighEntropyVA = FALSE; + + m_pCeeFileGen = NULL; + m_pCeeFile = 0; + + m_pManifest = NULL; + + m_pCustomDescrList = NULL; + + m_pGlobalDataSection = NULL; + m_pILSection = NULL; + m_pTLSSection = NULL; + + m_fDidCoInitialise = FALSE; + + m_fDLL = FALSE; + m_fEntryPointPresent = FALSE; + m_fHaveFieldsWithRvas = FALSE; + m_fFoldCode = FALSE; + m_dwMethodsFolded = 0; + + m_szScopeName[0] = 0; + m_crExtends = mdTypeDefNil; + + m_nImplList = 0; + m_TyParList = NULL; + + m_SEHD = NULL; + m_firstArgName = NULL; + m_lastArgName = NULL; + m_szNamespace = new char[2]; + m_szNamespace[0] = 0; + m_NSstack.PUSH(m_szNamespace); + + m_szFullNS = new char[MAX_NAMESPACE_LENGTH]; + memset(m_szFullNS,0,MAX_NAMESPACE_LENGTH); + m_ulFullNSLen = MAX_NAMESPACE_LENGTH; + + m_State = STATE_OK; + m_fInitialisedMetaData = FALSE; + m_fAutoInheritFromObject = TRUE; + + m_ulLastDebugLine = 0xFFFFFFFF; + m_ulLastDebugColumn = 0xFFFFFFFF; + m_ulLastDebugLineEnd = 0xFFFFFFFF; + m_ulLastDebugColumnEnd = 0xFFFFFFFF; + m_pSymWriter = NULL; + m_pSymDocument = NULL; + m_dwIncludeDebugInfo = 0; + m_fGeneratePDB = FALSE; + m_fIsMscorlib = FALSE; + m_fOptimize = FALSE; + m_tkSysObject = 0; + m_tkSysString = 0; + m_tkSysValue = 0; + m_tkSysEnum = 0; + + m_pVTable = NULL; + m_pMarshal = NULL; + m_pPInvoke = NULL; + + m_fReportProgress = TRUE; + m_tkCurrentCVOwner = 1; // module + m_pOutputBuffer = NULL; + + m_dwSubsystem = (DWORD)-1; + m_dwComImageFlags = COMIMAGE_FLAGS_ILONLY; + m_dwFileAlignment = 0; + m_stBaseAddress = 0; + m_stSizeOfStackReserve = 0; + m_dwCeeFileFlags = ICEE_CREATE_FILE_PURE_IL; + + g_szSourceFileName[0] = 0; + + m_guidLang = CorSym_LanguageType_ILAssembly; + m_guidLangVendor = CorSym_LanguageVendor_Microsoft; + m_guidDoc = CorSym_DocumentType_Text; + for(int i=0; i<INSTR_POOL_SIZE; i++) m_Instr[i].opcode = -1; + m_wzResourceFile = NULL; + m_wzKeySourceName = NULL; + OnErrGo = false; + bClock = NULL; + + m_pbsMD = NULL; + + m_pOutputBuffer = new BYTE[OUTPUT_BUFFER_SIZE]; + + m_pCurOutputPos = m_pOutputBuffer; + m_pEndOutputPos = m_pOutputBuffer + OUTPUT_BUFFER_SIZE; + + m_crImplList = new mdTypeRef[MAX_INTERFACES_IMPLEMENTED]; + m_nImplListSize = MAX_INTERFACES_IMPLEMENTED; + + m_pManifest = new AsmMan((void*)this); + + dummyClass = new Class(NULL); + indexKeywords(&indxKeywords); +} + + +Assembler::~Assembler() +{ + if(m_pbsMD) delete m_pbsMD; + + if(m_pMarshal) delete m_pMarshal; + if(m_pManifest) delete m_pManifest; + if(m_pPInvoke) delete m_pPInvoke; + + if(m_pVTable) delete m_pVTable; + + m_lstGlobalLabel.RESET(true); + m_lstGlobalFixup.RESET(true); + m_hshClass.RESET(false); + m_lstClass.RESET(true); + while((m_ClassStack.POP())); + while(m_CustomDescrListStack.POP()); + m_pCurClass = NULL; + dummyClass->m_szFQN = NULL; + delete dummyClass; + + if (m_pOutputBuffer) delete [] m_pOutputBuffer; + if (m_crImplList) delete [] m_crImplList; + if (m_TyParList) delete m_TyParList; + + if (m_pCeeFileGen != NULL) { + if (m_pCeeFile) + m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile); +#ifdef FEATURE_CORECLR + DestroyICeeFileGen(&m_pCeeFileGen); +#else + MscorpeSxS::DestroyICeeFileGen(&m_pCeeFileGen); +#endif + m_pCeeFileGen = NULL; + } + + while((m_szNamespace = m_NSstack.POP())) ; + delete [] m_szFullNS; + + m_DocWriterList.RESET(true); + + m_MethodBodyList.RESET(true); + + m_TypeDefDList.RESET(true); + + if (m_pSymWriter != NULL) + { + m_pSymWriter->Close(); + m_pSymWriter->Release(); + m_pSymWriter = NULL; + } + if (m_pImporter != NULL) + { + m_pImporter->Release(); + m_pImporter = NULL; + } + if (m_pEmitter != NULL) + { + m_pEmitter->Release(); + m_pEmitter = NULL; + } + + if (m_pDisp != NULL) + { + m_pDisp->Release(); + m_pDisp = NULL; + } + +#ifdef FEATURE_CORECLR +#ifdef FEATURE_PAL + if (g_loader != NULL) + { + g_loader->Finish(); + } +#endif +#else + if (m_fDidCoInitialise) + CoUninitialize(); +#endif // FEATURE_CORECLR + +} + + +BOOL Assembler::Init() +{ +#ifdef FEATURE_CORECLR +#ifdef FEATURE_PAL + g_loader = CoreCLRLoader::Create(g_pszExeFile); + if (g_loader == NULL) + { + return FALSE; + } + metaDataGetDispenser = (MetaDataGetDispenserFunc)g_loader->LoadFunction("MetaDataGetDispenser"); +#else + metaDataGetDispenser = (MetaDataGetDispenserFunc)MetaDataGetDispenser; +#endif // FEATURE_PAL +#else + if(!m_fDidCoInitialise) + { + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + return FALSE; + m_fDidCoInitialise = TRUE; + } +#endif // FEATURE_CORECLR + if (m_pCeeFileGen != NULL) { + if (m_pCeeFile) + m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile); +#ifdef FEATURE_CORECLR + DestroyICeeFileGen(&m_pCeeFileGen); +#else + MscorpeSxS::DestroyICeeFileGen(&m_pCeeFileGen); +#endif + m_pCeeFileGen = NULL; + } +#ifdef FEATURE_CORECLR + if (FAILED(CreateICeeFileGen(&m_pCeeFileGen))) return FALSE; +#else + if (FAILED(MscorpeSxS::CreateICeeFileGen(&m_pCeeFileGen))) return FALSE; +#endif + if (FAILED(m_pCeeFileGen->CreateCeeFileEx(&m_pCeeFile,(ULONG)m_dwCeeFileFlags))) return FALSE; + + if (FAILED(m_pCeeFileGen->GetSectionCreate(m_pCeeFile, ".il", sdReadOnly, &m_pILSection))) return FALSE; + if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".sdata", sdReadWrite, &m_pGlobalDataSection))) return FALSE; + if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".tls", sdReadWrite, &m_pTLSSection))) return FALSE; + + return TRUE; +} + +void Assembler::SetDLL(BOOL IsDll) +{ + HRESULT OK; + OK = m_pCeeFileGen->SetDllSwitch(m_pCeeFile, IsDll); + _ASSERTE(SUCCEEDED(OK)); + + m_fDLL = IsDll; +} + +void Assembler::SetOBJ(BOOL IsObj) +{ + HRESULT OK; + OK = m_pCeeFileGen->SetObjSwitch(m_pCeeFile, IsObj); + _ASSERTE(SUCCEEDED(OK)); + + m_fOBJ = IsObj; +} + + +void Assembler::ResetArgNameList() +{ + if(m_firstArgName) delArgNameList(m_firstArgName); + m_firstArgName = NULL; + m_lastArgName = NULL; +} + +void Assembler::ResetForNextMethod() +{ + + ResetArgNameList(); + + m_CurPC = 0; + m_pCurOutputPos = m_pOutputBuffer; + m_State = STATE_OK; + m_pCurMethod = NULL; +} + +void Assembler::ResetLineNumbers() +{ + // reset line number information + m_ulLastDebugLine = 0xFFFFFFFF; + m_ulLastDebugColumn = 0xFFFFFFFF; + m_ulLastDebugLineEnd = 0xFFFFFFFF; + m_ulLastDebugColumnEnd = 0xFFFFFFFF; +} + +BOOL Assembler::AddMethod(Method *pMethod) +{ + BOOL fIsInterface=FALSE, fIsImport=FALSE; + ULONG PEFileOffset=0; + + _ASSERTE(m_pCeeFileGen != NULL); + if (pMethod == NULL) + { + report->error("pMethod == NULL"); + return FALSE; + } + if(pMethod->m_pClass != NULL) + { + fIsInterface = IsTdInterface(pMethod->m_pClass->m_Attr); + fIsImport = IsTdImport(pMethod->m_pClass->m_Attr); + } + if(m_CurPC) + { + char sz[1024]; + sz[0] = 0; + if(fIsInterface && (!IsMdStatic(pMethod->m_Attr))) strcat_s(sz,1024," non-static declared in interface"); + if(fIsImport) strcat_s(sz,1024," imported"); + if(IsMdAbstract(pMethod->m_Attr)) strcat_s(sz,1024," abstract"); + if(IsMdPinvokeImpl(pMethod->m_Attr)) strcat_s(sz,1024," pinvoke"); + if(!IsMiIL(pMethod->m_wImplAttr)) strcat_s(sz,1024," non-IL"); + if(IsMiRuntime(pMethod->m_wImplAttr)) strcat_s(sz,1024," runtime-supplied"); + if(IsMiInternalCall(pMethod->m_wImplAttr)) strcat_s(sz,1024," an internal call"); + if(strlen(sz)) + { + report->error("Method cannot have body if it is%s\n",sz); + } + } + else // method has no body + { + if(fIsImport || IsMdAbstract(pMethod->m_Attr) || IsMdPinvokeImpl(pMethod->m_Attr) + || IsMiRuntime(pMethod->m_wImplAttr) || IsMiInternalCall(pMethod->m_wImplAttr)) return TRUE; + if(OnErrGo) + { + report->error("Method has no body\n"); + return TRUE; + } + else + { + report->warn("Method has no body, 'ret' emitted\n"); + Instr* pIns = GetInstr(); + if(pIns) + { + memset(pIns,0,sizeof(Instr)); + pIns->opcode = CEE_RET; + EmitOpcode(pIns); + } + } + } + + if(pMethod->m_Locals.COUNT()) pMethod->m_LocalsSig=0x11000001; // placeholder, the real token 2b defined in EmitMethod + + COR_ILMETHOD_FAT fatHeader; + fatHeader.SetFlags(pMethod->m_Flags); + fatHeader.SetMaxStack(pMethod->m_MaxStack); + fatHeader.SetLocalVarSigTok(pMethod->m_LocalsSig); + fatHeader.SetCodeSize(m_CurPC); + bool moreSections = (pMethod->m_dwNumExceptions != 0); + + // if max stack is specified <8, force fat header, otherwise (with tiny header) it will default to 8 + if((fatHeader.GetMaxStack() < 8)&&(fatHeader.GetLocalVarSigTok()==0)&&(fatHeader.GetCodeSize()<64)&&(!moreSections)) + fatHeader.SetFlags(fatHeader.GetFlags() | CorILMethod_InitLocals); //forces fat header but does nothing else, since LocalVarSigTok==0 + + unsigned codeSize = m_CurPC; + unsigned codeSizeAligned = codeSize; + if (moreSections) + codeSizeAligned = (codeSizeAligned + 3) & ~3; // to insure EH section aligned + + unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, moreSections); + unsigned ehSize = COR_ILMETHOD_SECT_EH::Size(pMethod->m_dwNumExceptions, pMethod->m_ExceptionList); + unsigned totalSize = headerSize + codeSizeAligned + ehSize; + + BYTE* outBuff; + BYTE* endbuf; + BinStr* pbsBody; + if((pbsBody = new BinStr())==NULL) return FALSE; + if((outBuff = pbsBody->getBuff(totalSize))==NULL) return FALSE; + endbuf = &outBuff[totalSize]; + + // Emit the header + outBuff += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, outBuff); + + pMethod->m_pCode = outBuff; + pMethod->m_headerOffset= PEFileOffset; + pMethod->m_methodOffset= PEFileOffset + headerSize; + pMethod->m_CodeSize = codeSize; + + // Emit the code + if (codeSizeAligned) + { + memset(outBuff,0,codeSizeAligned); + memcpy(outBuff, m_pOutputBuffer, codeSize); + outBuff += codeSizeAligned; + } + + if(pMethod->m_dwNumExceptions) + { + // Validate the eh + COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pEx; + DWORD TryEnd,HandlerEnd, dwEx, dwEf; + for(dwEx = 0, pEx = pMethod->m_ExceptionList; dwEx < pMethod->m_dwNumExceptions; dwEx++, pEx++) + { + if(pEx->GetTryOffset() > m_CurPC) // i.e., pMethod->m_CodeSize + { + report->error("Invalid SEH clause #%d: Try block starts beyond code size\n",dwEx+1); + } + TryEnd = pEx->GetTryOffset()+pEx->GetTryLength(); + if(TryEnd > m_CurPC) + { + report->error("Invalid SEH clause #%d: Try block ends beyond code size\n",dwEx+1); + } + if(pEx->GetHandlerOffset() > m_CurPC) + { + report->error("Invalid SEH clause #%d: Handler block starts beyond code size\n",dwEx+1); + } + HandlerEnd = pEx->GetHandlerOffset()+pEx->GetHandlerLength(); + if(HandlerEnd > m_CurPC) + { + report->error("Invalid SEH clause #%d: Handler block ends beyond code size\n",dwEx+1); + } + if(pEx->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) + { + if(!((pEx->GetFilterOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd))) + { + report->error("Invalid SEH clause #%d: Try and Filter/Handler blocks overlap\n",dwEx+1); + } + for(dwEf = 0; dwEf < pMethod->m_dwNumEndfilters; dwEf++) + { + if(pMethod->m_EndfilterOffsetList[dwEf] == pEx->GetHandlerOffset()) break; + } + if(dwEf >= pMethod->m_dwNumEndfilters) + { + report->error("Invalid SEH clause #%d: Filter block separated from Handler, or not ending with endfilter\n",dwEx+1); + } + } + else + if(!((pEx->GetHandlerOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd))) + { + report->error("Invalid SEH clause #%d: Try and Handler blocks overlap\n",dwEx+1); + } + + } + // Emit the eh + outBuff += COR_ILMETHOD_SECT_EH::Emit(ehSize, pMethod->m_dwNumExceptions, + pMethod->m_ExceptionList, false, outBuff); + } + _ASSERTE(outBuff == endbuf); + + pMethod->m_pbsBody = pbsBody; + + LocalMemberRefFixup* pMRF; + while((pMRF = pMethod->m_LocalMemberRefFixupList.POP())) + { + pMRF->offset += (size_t)(pMethod->m_pCode); + m_LocalMemberRefFixupList.PUSH(pMRF); // transfer MRF to assembler's list + } + + if(m_fReportProgress) + { + if (pMethod->IsGlobalMethod()) + report->msg("Assembled global method %s\n", pMethod->m_szName); + else report->msg("Assembled method %s::%s\n", pMethod->m_pClass->m_szFQN, + pMethod->m_szName); + } + return TRUE; +} + + +BOOL Assembler::EmitMethodBody(Method* pMethod, BinStr* pbsOut) +{ + if(pMethod) + { + BinStr* pbsBody = pMethod->m_pbsBody; + unsigned totalSize; + if(pbsBody && (totalSize = pbsBody->length())) + { + unsigned headerSize = pMethod->m_methodOffset-pMethod->m_headerOffset; + MethodBody* pMB = NULL; + // ----------emit locals signature------------------- + unsigned uLocals; + if((uLocals = pMethod->m_Locals.COUNT())) + { + VarDescr* pVD; + BinStr* pbsSig = new BinStr(); + unsigned cnt; + HRESULT hr; + DWORD cSig; + const COR_SIGNATURE* mySig; + + pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); + cnt = CorSigCompressData(uLocals,pbsSig->getBuff(5)); + pbsSig->remove(5-cnt); + for(cnt = 0; (pVD = pMethod->m_Locals.PEEK(cnt)); cnt++) + { + if(pVD->pbsSig) pbsSig->append(pVD->pbsSig); + else + { + report->error("Undefined type of local var slot %d in method %s\n",cnt,pMethod->m_szName); + pbsSig->appendInt8(ELEMENT_TYPE_I4); + } + } + + cSig = pbsSig->length(); + mySig = (const COR_SIGNATURE *)(pbsSig->ptr()); + + if (cSig > 1) // non-empty signature + { + hr = m_pEmitter->GetTokenFromSig(mySig, cSig, &pMethod->m_LocalsSig); + _ASSERTE(SUCCEEDED(hr)); + } + delete pbsSig; + COR_ILMETHOD_FAT* pFH; // Fat header guaranteed, because there are local vars + pFH = (COR_ILMETHOD_FAT*)(pMethod->m_pbsBody->ptr()); + pFH->SetLocalVarSigTok(pMethod->m_LocalsSig); + } + //-------------------------------------------------------------------------------- + if(m_fGeneratePDB && (m_pSymWriter != NULL)) + { + m_pSymWriter->OpenMethod(pMethod->m_Tok); + ULONG N = pMethod->m_LinePCList.COUNT(); + if(pMethod->m_fEntryPoint) m_pSymWriter->SetUserEntryPoint(pMethod->m_Tok); + if(N) + { + LinePC *pLPC; + ULONG32 *offsets=new ULONG32[N], *lines = new ULONG32[N], *columns = new ULONG32[N]; + ULONG32 *endlines=new ULONG32[N], *endcolumns=new ULONG32[N]; + if(offsets && lines && columns && endlines && endcolumns) + { + DocWriter* pDW; + unsigned j=0; + while((pDW = m_DocWriterList.PEEK(j++))) + { + if((m_pSymDocument = pDW->pWriter)) + { + int i, n; + for(i=0, n=0; (pLPC = pMethod->m_LinePCList.PEEK(i)); i++) + { + if(pLPC->pWriter == m_pSymDocument) + { + offsets[n] = pLPC->PC; + lines[n] = pLPC->Line; + columns[n] = pLPC->Column; + endlines[n] = pLPC->LineEnd; + endcolumns[n] = pLPC->ColumnEnd; + n++; + } + } + if(n) m_pSymWriter->DefineSequencePoints(m_pSymDocument,n, + offsets,lines,columns,endlines,endcolumns); + } // end if(pSymDocument) + } // end while(pDW = next doc.writer) + pMethod->m_LinePCList.RESET(true); + } + else report->error("\nOutOfMemory!\n"); + delete [] offsets; + delete [] lines; + delete [] columns; + delete [] endlines; + delete [] endcolumns; + }//enf if(N) + HRESULT hrr; + if(pMethod->m_ulLines[1]) + hrr = m_pSymWriter->SetMethodSourceRange(m_pSymDocument,pMethod->m_ulLines[0], pMethod->m_ulColumns[0], + m_pSymDocument,pMethod->m_ulLines[1], pMethod->m_ulColumns[1]); + EmitScope(&(pMethod->m_MainScope)); // recursively emits all nested scopes + + m_pSymWriter->CloseMethod(); + } // end if(fIncludeDebugInfo) + //----------------------------------------------------- + + if(m_fFoldCode) + { + for(int k=0; (pMB = m_MethodBodyList.PEEK(k)) != NULL; k++) + { + if((pMB->pbsBody->length() == totalSize) + && (memcmp(pMB->pbsBody->ptr(), pbsBody->ptr(),totalSize)==0)) + break; + } + if(pMB) + { + pMethod->m_headerOffset= pMB->RVA; + pMethod->m_methodOffset= pMB->RVA + headerSize; + pMethod->m_pCode = pMB->pCode; + delete pbsBody; + pMethod->m_pbsBody = NULL; + m_dwMethodsFolded++; + } + } + if(pMB == NULL) + { + BYTE* outBuff; + unsigned align = (headerSize == 1)? 1 : 4; + ULONG PEFileOffset, methodRVA; + if(m_fENCMode) + { + if(pbsOut) + { + PEFileOffset = pbsOut->length(); + align--; + while(PEFileOffset & align) + { + pbsOut->appendInt8(0); + PEFileOffset++; + } + pbsOut->append(pbsBody); + outBuff = (BYTE*)(pbsOut->ptr()) + (pbsOut->length() - pbsBody->length()); + } + else return FALSE; + + } + else + { + if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize, + align, (void **) &outBuff))) return FALSE; + memcpy(outBuff,pbsBody->ptr(),totalSize); + // The offset where we start, (not where the alignment bytes start! + if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) + return FALSE; + PEFileOffset -= totalSize; + } + + pMethod->m_pCode = outBuff + headerSize; + pMethod->m_headerOffset= PEFileOffset; + pMethod->m_methodOffset= PEFileOffset + headerSize; + DoDeferredILFixups(pMethod); + + if(m_fENCMode) methodRVA = PEFileOffset; + else m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA); + + pMethod->m_headerOffset= methodRVA; + pMethod->m_methodOffset= methodRVA + headerSize; + if(m_fFoldCode) + { + if((pMB = new MethodBody)==NULL) return FALSE; + pMB->pbsBody = pbsBody; + pMB->RVA = methodRVA; + pMB->pCode = pMethod->m_pCode; + m_MethodBodyList.PUSH(pMB); + } + //else + // delete pbsBody; + //pMethod->m_pbsBody = NULL; + } + m_pEmitter->SetRVA(pMethod->m_Tok,pMethod->m_headerOffset); + } + return TRUE; + } + else return FALSE; +} + +ImportDescriptor* Assembler::EmitImport(BinStr* DllName) +{ + int i = 0, l = 0; + ImportDescriptor* pID; + char* sz=NULL; + + if(DllName) l = DllName->length(); // No zero terminator here! + if(l) + { + sz = (char*)DllName->ptr(); + while((pID=m_ImportList.PEEK(i++))) + { + if((pID->dwDllName== (DWORD) l)&& !memcmp(pID->szDllName,sz,l)) return pID; + } + } + else + { + while((pID=m_ImportList.PEEK(i++))) + { + if(pID->dwDllName==0) return pID; + } + } + if((pID = new ImportDescriptor(sz,l))) + { + m_ImportList.PUSH(pID); + pID->mrDll = TokenFromRid(m_ImportList.COUNT(),mdtModuleRef); + return pID; + } + else report->error("Failed to allocate import descriptor\n"); + return NULL; +} + +void Assembler::EmitImports() +{ + WCHAR* wzDllName=&wzUniBuf[0]; + ImportDescriptor* pID; + int i; + mdToken tk; + for(i=0; (pID = m_ImportList.PEEK(i)); i++) + { + WszMultiByteToWideChar(g_uCodePage,0,pID->szDllName,-1,wzDllName,dwUniBuf-1); + if(FAILED(m_pEmitter->DefineModuleRef( // S_OK or error. + wzDllName, // [IN] DLL name + &tk))) // [OUT] returned + report->error("Failed to define module ref '%s'\n",pID->szDllName); + else + _ASSERTE(tk == pID->mrDll); + } +} + +HRESULT Assembler::EmitPinvokeMap(mdToken tk, PInvokeDescriptor* pDescr) +{ + WCHAR* wzAlias=&wzUniBuf[0]; + + if(pDescr->szAlias) WszMultiByteToWideChar(g_uCodePage,0,pDescr->szAlias,-1,wzAlias,dwUniBuf-1); + + return m_pEmitter->DefinePinvokeMap( // Return code. + tk, // [IN] FieldDef, MethodDef or MethodImpl. + pDescr->dwAttrs, // [IN] Flags used for mapping. + (LPCWSTR)wzAlias, // [IN] Import name. + pDescr->mrDll); // [IN] ModuleRef token for the target DLL. +} + +void Assembler::EmitScope(Scope* pSCroot) +{ + static ULONG32 scopeID; + static ARG_NAME_LIST *pVarList; + int i; + WCHAR* wzVarName=&wzUniBuf[0]; + char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1]; + Scope* pSC = pSCroot; + if(pSC && m_pSymWriter) + { + if(SUCCEEDED(m_pSymWriter->OpenScope(pSC->dwStart,&scopeID))) + { + if(pSC->pLocals) + { + for(pVarList = pSC->pLocals; pVarList; pVarList = pVarList->pNext) + { + if(pVarList->pSig) + { + if((pVarList->szName)&&(*(pVarList->szName))) strcpy_s(szPhonyName,dwUniBuf >> 1,pVarList->szName); + else sprintf_s(szPhonyName,(dwUniBuf >> 1),"V_%d",pVarList->dwAttr); + + WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzVarName,dwUniBuf >> 1); + + m_pSymWriter->DefineLocalVariable(wzVarName,0,pVarList->pSig->length(), + (BYTE*)pVarList->pSig->ptr(),ADDR_IL_OFFSET,pVarList->dwAttr,0,0,0,0); + } + else + { + report->error("Local Var '%s' has no signature\n",pVarList->szName); + } + } + } + for(i = 0; (pSC = pSCroot->SubScope.PEEK(i)); i++) EmitScope(pSC); + m_pSymWriter->CloseScope(pSCroot->dwEnd); + } + } +} + +BOOL Assembler::EmitMethod(Method *pMethod) +{ +// Emit the metadata for a method definition + BOOL fSuccess = FALSE; + WCHAR* wzMemberName=&wzUniBuf[0]; + BOOL fIsInterface; + DWORD cSig; + ULONG methodRVA = 0; + mdMethodDef MethodToken; + mdTypeDef ClassToken = mdTypeDefNil; + char *pszMethodName; + COR_SIGNATURE *mySig; + + _ASSERTE((m_pCeeFileGen != NULL) && (pMethod != NULL)); + fIsInterface = ((pMethod->m_pClass != NULL) && IsTdInterface(pMethod->m_pClass->m_Attr)); + + + pszMethodName = pMethod->m_szName; + mySig = pMethod->m_pMethodSig; + cSig = pMethod->m_dwMethodCSig; + + // If this is an instance method, make certain the signature says so + + if (!(pMethod->m_Attr & mdStatic)) + *mySig |= IMAGE_CEE_CS_CALLCONV_HASTHIS; + + ClassToken = (pMethod->IsGlobalMethod())? mdTokenNil + : pMethod->m_pClass->m_cl; + // Convert name to UNICODE + WszMultiByteToWideChar(g_uCodePage,0,pszMethodName,-1,wzMemberName,dwUniBuf-1); + + if(IsMdPrivateScope(pMethod->m_Attr)) + { + WCHAR* p = wcsstr(wzMemberName,W("$PST06")); + if(p) *p = 0; + } + + if (FAILED(m_pEmitter->DefineMethod(ClassToken, // parent class + wzMemberName, // member name + pMethod->m_Attr & ~mdReservedMask, // member attributes + mySig, // member signature + cSig, + methodRVA, // RVA + pMethod->m_wImplAttr, // implflags + &MethodToken))) + { + report->error("Failed to define method '%s'\n",pszMethodName); + goto exit; + } + pMethod->m_Tok = MethodToken; + //-------------------------------------------------------------------------------- + // the only way to set mdRequireSecObject: + if(pMethod->m_Attr & mdRequireSecObject) + { + mdToken tkPseudoClass; + if(FAILED(m_pEmitter->DefineTypeRefByName(1, COR_REQUIRES_SECOBJ_ATTRIBUTE, &tkPseudoClass))) + report->error("Unable to define type reference '%s'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI); + else + { + mdToken tkPseudoCtor; + BYTE bSig[3] = {IMAGE_CEE_CS_CALLCONV_HASTHIS,0,ELEMENT_TYPE_VOID}; + if(FAILED(m_pEmitter->DefineMemberRef(tkPseudoClass, W(".ctor"), (PCCOR_SIGNATURE)bSig, 3, &tkPseudoCtor))) + report->error("Unable to define member reference '%s::.ctor'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI); + else DefineCV(new CustomDescr(MethodToken,tkPseudoCtor,NULL)); + } + } + + if (pMethod->m_NumTyPars) + { + ULONG i; + mdToken* ptk; + mdToken tk; + for(i = 0; i < pMethod->m_NumTyPars; i++) + { + //ptk = (pMethod->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pMethod->m_TyParBounds[i]->ptr()); + //if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,0,pMethod->m_TyParNames[i],0,ptk,&tk))) + ptk = (pMethod->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pMethod->m_TyPars[i].Bounds()->ptr()); + if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,pMethod->m_TyPars[i].Attrs(),pMethod->m_TyPars[i].Name(),0,ptk,&tk))) + report->error("Unable to define generic param'\n"); + else + EmitCustomAttributes(tk, pMethod->m_TyPars[i].CAList()); + } + } + //-------------------------------------------------------------------------------- + EmitSecurityInfo(MethodToken, + pMethod->m_pPermissions, + pMethod->m_pPermissionSets); + //-------------------------------------------------------------------------------- + if (pMethod->m_fEntryPoint) + { + if(fIsInterface) report->error("Entrypoint in Interface: Method '%s'\n",pszMethodName); + + if (FAILED(m_pCeeFileGen->SetEntryPoint(m_pCeeFile, MethodToken))) + { + report->error("Failed to set entry point for method '%s'\n",pszMethodName); + goto exit; + } + + } + //-------------------------------------------------------------------------------- + if(IsMdPinvokeImpl(pMethod->m_Attr)) + { + if(pMethod->m_pPInvoke) + { + HRESULT hr; + if(pMethod->m_pPInvoke->szAlias == NULL) pMethod->m_pPInvoke->szAlias = pszMethodName; + hr = EmitPinvokeMap(MethodToken,pMethod->m_pPInvoke); + if(pMethod->m_pPInvoke->szAlias == pszMethodName) pMethod->m_pPInvoke->szAlias = NULL; + + if(FAILED(hr)) + { + report->error("Failed to set PInvoke map for method '%s'\n",pszMethodName); + goto exit; + } + } + } + + { // add parameters to metadata + void const *pValue=NULL; + ULONG cbValue; + DWORD dwCPlusTypeFlag=0; + mdParamDef pdef; + WCHAR* wzParName=&wzUniBuf[0]; + char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1]; + if(pMethod->m_dwRetAttr || pMethod->m_pRetMarshal || pMethod->m_RetCustDList.COUNT()) + { + if(pMethod->m_pRetValue) + { + dwCPlusTypeFlag= (DWORD)*(pMethod->m_pRetValue->ptr()); + pValue = (void const *)(pMethod->m_pRetValue->ptr()+1); + cbValue = pMethod->m_pRetValue->length()-1; + if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR); + } + else + { + pValue = NULL; + cbValue = (ULONG)-1; + dwCPlusTypeFlag=0; + } + m_pEmitter->DefineParam(MethodToken,0,NULL,pMethod->m_dwRetAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef); + + if(pMethod->m_pRetMarshal) + { + if(FAILED(m_pEmitter->SetFieldMarshal ( + pdef, // [IN] given a fieldDef or paramDef token + (PCCOR_SIGNATURE)(pMethod->m_pRetMarshal->ptr()), // [IN] native type specification + pMethod->m_pRetMarshal->length()))) // [IN] count of bytes of pvNativeType + report->error("Failed to set param marshaling for return\n"); + + } + EmitCustomAttributes(pdef, &(pMethod->m_RetCustDList)); + } + for(ARG_NAME_LIST *pAN=pMethod->m_firstArgName; pAN; pAN = pAN->pNext) + { + if(pAN->nNum >= 65535) + { + report->error("Method '%s': Param.sequence number (%d) exceeds 65535, unable to define parameter\n",pszMethodName,pAN->nNum+1); + continue; + } + if(pAN->dwName) strcpy_s(szPhonyName,dwUniBuf >> 1,pAN->szName); + else sprintf_s(szPhonyName,(dwUniBuf >> 1),"A_%d",pAN->nNum); + + WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzParName,dwUniBuf >> 1); + + if(pAN->pValue) + { + dwCPlusTypeFlag= (DWORD)*(pAN->pValue->ptr()); + pValue = (void const *)(pAN->pValue->ptr()+1); + cbValue = pAN->pValue->length()-1; + if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR); + } + else + { + pValue = NULL; + cbValue = (ULONG)-1; + dwCPlusTypeFlag=0; + } + m_pEmitter->DefineParam(MethodToken,pAN->nNum+1,wzParName,pAN->dwAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef); + if(pAN->pMarshal) + { + if(FAILED(m_pEmitter->SetFieldMarshal ( + pdef, // [IN] given a fieldDef or paramDef token + (PCCOR_SIGNATURE)(pAN->pMarshal->ptr()), // [IN] native type specification + pAN->pMarshal->length()))) // [IN] count of bytes of pvNativeType + report->error("Failed to set param marshaling for '%s'\n",pAN->szName); + } + EmitCustomAttributes(pdef, &(pAN->CustDList)); + } + } + fSuccess = TRUE; + //-------------------------------------------------------------------------------- + // Update method implementations for this method + { + MethodImplDescriptor* pMID; + int i; + for(i=0;(pMID = pMethod->m_MethodImplDList.PEEK(i));i++) + { + pMID->m_tkImplementingMethod = MethodToken; + // don't delete it here, it's still in the general list + } + } + //-------------------------------------------------------------------------------- + EmitCustomAttributes(MethodToken, &(pMethod->m_CustomDescrList)); +exit: + if (fSuccess == FALSE) m_State = STATE_FAIL; + return fSuccess; +} + +BOOL Assembler::EmitMethodImpls() +{ + MethodImplDescriptor* pMID; + BOOL ret = TRUE; + int i; + for(i=0; (pMID = m_MethodImplDList.PEEK(i)); i++) + { + if(m_fENCMode && (!pMID->m_fNew)) continue; + pMID->m_tkImplementingMethod = ResolveLocalMemberRef(pMID->m_tkImplementingMethod); + pMID->m_tkImplementedMethod = ResolveLocalMemberRef(pMID->m_tkImplementedMethod); + if(FAILED(m_pEmitter->DefineMethodImpl( pMID->m_tkDefiningClass, + pMID->m_tkImplementingMethod, + pMID->m_tkImplementedMethod))) + { + report->error("Failed to define Method Implementation"); + ret = FALSE; + } + pMID->m_fNew = FALSE; + }// end while + return ret; +} + +mdToken Assembler::ResolveLocalMemberRef(mdToken tok) +{ + if(TypeFromToken(tok) == 0x99000000) + { + tok = RidFromToken(tok); + if(tok) tok = m_LocalMethodRefDList.PEEK(tok-1)->m_tkResolved; + } + else if(TypeFromToken(tok) == 0x98000000) + { + tok = RidFromToken(tok); + if(tok) tok = m_LocalFieldRefDList.PEEK(tok-1)->m_tkResolved; + } + return tok; +} + +BOOL Assembler::EmitEvent(EventDescriptor* pED) +{ + mdMethodDef mdAddOn=mdMethodDefNil, + mdRemoveOn=mdMethodDefNil, + mdFire=mdMethodDefNil, + *mdOthers; + int nOthers; + WCHAR* wzMemberName=&wzUniBuf[0]; + + if(!pED) return FALSE; + + WszMultiByteToWideChar(g_uCodePage,0,pED->m_szName,-1,wzMemberName,dwUniBuf-1); + + mdAddOn = ResolveLocalMemberRef(pED->m_tkAddOn); + if(TypeFromToken(mdAddOn) != mdtMethodDef) + { + report->error("Invalid Add method of event '%s'\n",pED->m_szName); + return FALSE; + } + mdRemoveOn = ResolveLocalMemberRef(pED->m_tkRemoveOn); + if(TypeFromToken(mdRemoveOn) != mdtMethodDef) + { + report->error("Invalid Remove method of event '%s'\n",pED->m_szName); + return FALSE; + } + mdFire = ResolveLocalMemberRef(pED->m_tkFire); + if((RidFromToken(mdFire)!=0)&&(TypeFromToken(mdFire) != mdtMethodDef)) + { + report->error("Invalid Fire method of event '%s'\n",pED->m_szName); + return FALSE; + } + + nOthers = pED->m_tklOthers.COUNT(); + mdOthers = new mdMethodDef[nOthers+1]; + if(mdOthers == NULL) + { + report->error("Failed to allocate Others array for event descriptor\n"); + nOthers = 0; + } + for(int j=0; j < nOthers; j++) + { + mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pED->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken' + } + mdOthers[nOthers] = mdMethodDefNil; // like null-terminator + + if(FAILED(m_pEmitter->DefineEvent( pED->m_tdClass, + wzMemberName, + pED->m_dwAttr, + pED->m_tkEventType, + mdAddOn, + mdRemoveOn, + mdFire, + mdOthers, + &(pED->m_edEventTok)))) + { + report->error("Failed to define event '%s'.\n",pED->m_szName); + delete [] mdOthers; + return FALSE; + } + EmitCustomAttributes(pED->m_edEventTok, &(pED->m_CustomDescrList)); + return TRUE; +} + +BOOL Assembler::EmitProp(PropDescriptor* pPD) +{ + mdMethodDef mdSet, mdGet, *mdOthers; + int nOthers; + WCHAR* wzMemberName=&wzUniBuf[0]; + + if(!pPD) return FALSE; + + WszMultiByteToWideChar(g_uCodePage,0,pPD->m_szName,-1,wzMemberName,dwUniBuf-1); + + mdSet = ResolveLocalMemberRef(pPD->m_tkSet); + if((RidFromToken(mdSet)!=0)&&(TypeFromToken(mdSet) != mdtMethodDef)) + { + report->error("Invalid Set method of property '%s'\n",pPD->m_szName); + return FALSE; + } + mdGet = ResolveLocalMemberRef(pPD->m_tkGet); + if((RidFromToken(mdGet)!=0)&&(TypeFromToken(mdGet) != mdtMethodDef)) + { + report->error("Invalid Get method of property '%s'\n",pPD->m_szName); + return FALSE; + } + + nOthers = pPD->m_tklOthers.COUNT(); + mdOthers = new mdMethodDef[nOthers+1]; + if(mdOthers == NULL) + { + report->error("Failed to allocate Others array for prop descriptor\n"); + nOthers = 0; + } + for(int j=0; j < nOthers; j++) + { + mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pPD->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken' + + if((RidFromToken(mdOthers[j])!=0)&&(TypeFromToken(mdOthers[j]) != mdtMethodDef)) + { + report->error("Invalid Other method of property '%s'\n",pPD->m_szName); + delete [] mdOthers; + return FALSE; + } + + } + mdOthers[nOthers] = mdMethodDefNil; // like null-terminator + + if(FAILED(m_pEmitter->DefineProperty( pPD->m_tdClass, + wzMemberName, + pPD->m_dwAttr, + pPD->m_pSig, + pPD->m_dwCSig, + pPD->m_dwCPlusTypeFlag, + pPD->m_pValue, + pPD->m_cbValue, + mdSet, + mdGet, + mdOthers, + &(pPD->m_pdPropTok)))) + { + report->error("Failed to define property '%s'.\n",pPD->m_szName); + delete [] mdOthers; + return FALSE; + } + EmitCustomAttributes(pPD->m_pdPropTok, &(pPD->m_CustomDescrList)); + return TRUE; +} + +Class *Assembler::FindCreateClass(__in __nullterminated const char *pszFQN) +{ + Class *pSearch = NULL; + + if(pszFQN) + { + dummyClass->m_szFQN = pszFQN; + dummyClass->m_Hash = hash((BYTE*)pszFQN, (unsigned)strlen(pszFQN), 10); + pSearch = m_hshClass.FIND(dummyClass); + dummyClass->m_szFQN = NULL; + dummyClass->m_Hash = 0; + + if(!pSearch) + { + char* pch; + DWORD dwFQN = (DWORD)strlen(pszFQN); + + Class *pEncloser = NULL; + char* pszNewFQN = new char[dwFQN+1]; + strcpy_s(pszNewFQN,dwFQN+1,pszFQN); + if((pch = strrchr(pszNewFQN, NESTING_SEP)) != NULL) + { + *pch = 0; + pEncloser = FindCreateClass(pszNewFQN); + *pch = NESTING_SEP; + } + pSearch = new Class(pszNewFQN); + if (pSearch == NULL) + report->error("Failed to create class '%s'\n",pszNewFQN); + else + { + pSearch->m_pEncloser = pEncloser; + m_lstClass.PUSH(pSearch); + pSearch->m_cl = mdtTypeDef | m_lstClass.COUNT(); + m_hshClass.PUSH(pSearch); + } + } + } + + return pSearch; +} + + +BOOL Assembler::EmitClass(Class *pClass) +{ + LPCUTF8 szFullName; + WCHAR* wzFullName=&wzUniBuf[0]; + HRESULT hr = E_FAIL; + GUID guid; + size_t L; + mdToken tok; + + if(pClass == NULL) return FALSE; + + hr = CoCreateGuid(&guid); + if (FAILED(hr)) + { + printf("Unable to create GUID\n"); + m_State = STATE_FAIL; + return FALSE; + } + + if(pClass->m_pEncloser) + szFullName = strrchr(pClass->m_szFQN,NESTING_SEP) + 1; + else + szFullName = pClass->m_szFQN; + + WszMultiByteToWideChar(g_uCodePage,0,szFullName,-1,wzFullName,dwUniBuf); + + L = wcslen(wzFullName); + if((L==0)||(wzFullName[L-1]==L'.')) // Missing class name! + { + wcscat_s(wzFullName,dwUniBuf,W("$UNNAMED_TYPE$")); + } + + pClass->m_Attr = CheckClassFlagsIfNested(pClass->m_pEncloser, pClass->m_Attr); + + if (pClass->m_pEncloser) + { + hr = m_pEmitter->DefineNestedType( wzFullName, + pClass->m_Attr, // attributes + pClass->m_crExtends, // CR extends class + pClass->m_crImplements,// implements + pClass->m_pEncloser->m_cl, // Enclosing class. + &tok); + } + else + { + hr = m_pEmitter->DefineTypeDef( wzFullName, + pClass->m_Attr, // attributes + pClass->m_crExtends, // CR extends class + pClass->m_crImplements,// implements + &tok); + } + _ASSERTE(tok == pClass->m_cl); + if (FAILED(hr)) goto exit; + if (pClass->m_NumTyPars) + { + ULONG i; + mdToken* ptk; + mdToken tk; + for(i = 0; i < pClass->m_NumTyPars; i++) + { + //ptk = (pClass->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pClass->m_TyParBounds[i]->ptr()); + //if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyParAttrs[i],pClass->m_TyParNames[i],0,ptk,&tk))) + ptk = (pClass->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pClass->m_TyPars[i].Bounds()->ptr()); + if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyPars[i].Attrs(),pClass->m_TyPars[i].Name(),0,ptk,&tk))) + report->error("Unable to define generic param'\n"); + else + EmitCustomAttributes(tk, pClass->m_TyPars[i].CAList()); + } + } + + + EmitCustomAttributes(pClass->m_cl, &(pClass->m_CustDList)); + hr = S_OK; + +exit: + return SUCCEEDED(hr); +} + +BOOL Assembler::DoGlobalFixups() +{ + GlobalFixup *pSearch; + + for (int i=0; (pSearch = m_lstGlobalFixup.PEEK(i)); i++) + { + GlobalLabel * pLabel = FindGlobalLabel(pSearch->m_szLabel); + if (pLabel == NULL) + { + report->error("Unable to find forward reference global label '%s'\n", + pSearch->m_szLabel); + + m_State = STATE_FAIL; + return FALSE; + } + //BYTE * pReference = pSearch->m_pReference; + //DWORD GlobalOffset = pLabel->m_GlobalOffset; + //memcpy(pReference,&GlobalOffset,4); + SET_UNALIGNED_VAL32(pSearch->m_pReference,pLabel->m_GlobalOffset); + } + + return TRUE; +} + +state_t Assembler::AddGlobalLabel(__in __nullterminated char *pszName, HCEESECTION section) +{ + if (FindGlobalLabel(pszName) != NULL) + { + report->error("Duplicate global label '%s'\n", pszName); + m_State = STATE_FAIL; + return m_State; + } + + ULONG GlobalOffset; + + HRESULT hr; + hr = m_pCeeFileGen->GetSectionDataLen(section, &GlobalOffset); + _ASSERTE(SUCCEEDED(hr)); + + GlobalLabel *pNew = new GlobalLabel(pszName, GlobalOffset, section); + if (pNew == 0) + { + report->error("Failed to allocate global label '%s'\n",pszName); + m_State = STATE_FAIL; + return m_State; + } + + m_lstGlobalLabel.PUSH(pNew); + return m_State; +} + +void Assembler::AddLabel(DWORD CurPC, __in __nullterminated char *pszName) +{ + if (m_pCurMethod->FindLabel(pszName) != NULL) + { + report->error("Duplicate label: '%s'\n", pszName); + + m_State = STATE_FAIL; + } + else + { + Label *pNew = new Label(pszName, CurPC); + + if (pNew != NULL) + //m_pCurMethod->m_lstLabel.PUSH(pNew); + m_lstLabel.PUSH(pNew); + else + { + report->error("Failed to allocate label '%s'\n",pszName); + m_State = STATE_FAIL; + } + } +} + +void Assembler::DoDeferredILFixups(Method* pMethod) +{ // Now that we know where in the file the code bytes will wind up, + // we can update the RVAs and offsets. + ILFixup *pSearch; + HRESULT hr; + GlobalFixup *Fix = NULL; + int i; + for (i=0;(pSearch = pMethod->m_lstILFixup.PEEK(i));i++) + { + switch(pSearch->m_Kind) + { + case ilGlobal: + Fix = pSearch->m_Fixup; + _ASSERTE(Fix != NULL); + Fix->m_pReference = pMethod->m_pCode+pSearch->m_OffsetInMethod; + break; + + case ilToken: + hr = m_pCeeFileGen->AddSectionReloc(m_pILSection, + pSearch->m_OffsetInMethod+pMethod->m_methodOffset, + m_pILSection, + srRelocMapToken); + _ASSERTE(SUCCEEDED(hr)); + break; + + case ilRVA: + hr = m_pCeeFileGen->AddSectionReloc(m_pILSection, + pSearch->m_OffsetInMethod+pMethod->m_methodOffset, + m_pGlobalDataSection, + srRelocAbsolute); + _ASSERTE(SUCCEEDED(hr)); + break; + + default: + ; + } + } +} +/**************************************************************************/ +BOOL Assembler::DoFixups(Method* pMethod) +{ + Fixup *pSearch; + + for (int i=0; (pSearch = pMethod->m_lstFixup.PEEK(i)); i++) + { + Label * pLabel = pMethod->FindLabel(pSearch->m_szLabel); + long offset; + + if (pLabel == NULL) + { + report->error("Unable to find forward reference label '%s' called from PC=%d\n", + pSearch->m_szLabel, pSearch->m_RelativeToPC); + + //m_State = STATE_FAIL; + return FALSE; + } + + offset = pLabel->m_PC - pSearch->m_RelativeToPC; + + if (pSearch->m_FixupSize == 1) + { + if (offset > 127 || offset < -128) + { + report->error("Offset of forward reference label '%s' called from PC=%d is too large for 1 byte pcrel\n", + pLabel->m_szName, pSearch->m_RelativeToPC); + + //m_State = STATE_FAIL; + return FALSE; + } + + *pSearch->m_pBytes = (BYTE) offset; + } + else if (pSearch->m_FixupSize == 4) + { + SET_UNALIGNED_VAL32(pSearch->m_pBytes,offset); + } + } + + return TRUE; +} + + +OPCODE Assembler::DecodeOpcode(const BYTE *pCode, DWORD *pdwLen) +{ + OPCODE opcode; + + *pdwLen = 1; + opcode = OPCODE(pCode[0]); + switch(opcode) { + case CEE_PREFIX1: + opcode = OPCODE(pCode[1] + 256); + if (opcode < 0 || opcode >= CEE_COUNT) + return CEE_COUNT; + *pdwLen = 2; + break; + + case CEE_PREFIXREF: + case CEE_PREFIX2: + case CEE_PREFIX3: + case CEE_PREFIX4: + case CEE_PREFIX5: + case CEE_PREFIX6: + case CEE_PREFIX7: + return CEE_COUNT; + default: + break; + } + return opcode; +} + +char* Assembler::ReflectionNotation(mdToken tk) +{ + char *sz = (char*)&wzUniBuf[dwUniBuf>>1], *pc; + *sz=0; + switch(TypeFromToken(tk)) + { + case mdtTypeDef: + { + Class *pClass = m_lstClass.PEEK(RidFromToken(tk)-1); + if(pClass) + { + strcpy_s(sz,dwUniBuf>>1,pClass->m_szFQN); + pc = sz; + while((pc = strchr(pc,NESTING_SEP)) != NULL) + { + *pc = '+'; + pc++; + } + } + } + break; + + case mdtTypeRef: + { + ULONG N; + mdToken tkResScope; + if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,dwUniBuf>>1,&N))) + { + WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,dwUniBuf>>1,NULL,NULL); + if(TypeFromToken(tkResScope)==mdtAssemblyRef) + { + AsmManAssembly *pAsmRef = m_pManifest->m_AsmRefLst.PEEK(RidFromToken(tkResScope)-1); + if(pAsmRef) + { + pc = &sz[strlen(sz)]; + pc+=sprintf_s(pc,(dwUniBuf >> 1),", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName, + pAsmRef->usVerMajor,pAsmRef->usVerMinor,pAsmRef->usBuild,pAsmRef->usRevision); + ULONG L=0; + if(pAsmRef->pLocale && (L=pAsmRef->pLocale->length())) + { + memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L); + wzUniBuf[L>>1] = 0; + WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,dwUniBuf>>1,NULL,NULL); + } + else pc+=sprintf_s(pc,(dwUniBuf >> 1),"neutral"); + pc = &sz[strlen(sz)]; + if(pAsmRef->pPublicKeyToken && (L=pAsmRef->pPublicKeyToken->length())) + { + pc+=sprintf_s(pc,(dwUniBuf >> 1),", Publickeytoken="); + BYTE* pb = (BYTE*)(pAsmRef->pPublicKeyToken->ptr()); + for(N=0; N<L; N++,pb++) pc+=sprintf_s(pc,(dwUniBuf >> 1),"%2.2x",*pb); + } + } + } + } + } + break; + + default: + break; + } + return sz; +} + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bits set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c >> 13); \ + b -= c; b -= a; b ^= (a << 8); \ + c -= a; c -= b; c ^= (b >> 13); \ + a -= b; a -= c; a ^= (c >> 12); \ + b -= c; b -= a; b ^= (a << 16); \ + c -= a; c -= b; c ^= (b >> 5); \ + a -= b; a -= c; a ^= (c >> 3); \ + b -= c; b -= a; b ^= (a << 10); \ + c -= a; c -= b; c ^= (b >> 15); \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6*len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^^32 is +acceptable. Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +unsigned hash( + __in_ecount(length) const BYTE *k, /* the key */ + unsigned length, /* the length of the key */ + unsigned initval) /* the previous hash, or an arbitrary value */ +{ + register unsigned a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += (k[0] + ((unsigned)k[1] << 8) + ((unsigned)k[2] << 16) + ((unsigned)k[3] << 24)); + b += (k[4] + ((unsigned)k[5] << 8) + ((unsigned)k[6] << 16) + ((unsigned)k[7] << 24)); + c += (k[8] + ((unsigned)k[9] << 8) + ((unsigned)k[10] << 16) + ((unsigned)k[11] << 24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((unsigned)k[10] << 24); + case 10: c+=((unsigned)k[9] << 16); + case 9 : c+=((unsigned)k[8] << 8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((unsigned)k[7] << 24); + case 7 : b+=((unsigned)k[6] << 16); + case 6 : b+=((unsigned)k[5] << 8); + case 5 : b+=k[4]; + case 4 : a+=((unsigned)k[3] << 24); + case 3 : a+=((unsigned)k[2] << 16); + case 2 : a+=((unsigned)k[1] << 8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + |