1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
17 #include "assembler.h"
18 #ifdef FEATURE_CORECLR
20 #include "coreclrloader.h"
21 CoreCLRLoader *g_loader;
23 MetaDataGetDispenserFunc metaDataGetDispenser;
25 #include "MscorpeSxS.h"
26 #endif // FEATURE_CORECLR
28 void indexKeywords(Indx* indx); // defined in asmparse.y
30 unsigned int g_uCodePage = CP_ACP;
31 unsigned int g_uConsoleCP = CP_ACP;
33 char g_szSourceFileName[MAX_FILENAME_LENGTH*3];
35 WCHAR wzUniBuf[dwUniBuf]; // Unicode conversion global buffer
37 Assembler::Assembler()
45 char* pszFQN = new char[16];
46 strcpy_s(pszFQN,16,"<Module>");
47 m_pModuleClass = new Class(pszFQN);
48 m_lstClass.PUSH(m_pModuleClass);
49 m_hshClass.PUSH(m_pModuleClass);
50 m_pModuleClass->m_cl = mdTokenNil;
51 m_pModuleClass->m_bIsMaster = FALSE;
53 m_fStdMapping = FALSE;
54 m_fDisplayTraceOutput= FALSE;
56 m_fTolerateDupMethods = FALSE;
58 m_pCurOutputPos = NULL;
60 m_CurPC = 0; // PC offset in method
66 m_wzMetadataVersion = NULL;
70 m_wSSVersionMajor = 4;
71 m_wSSVersionMinor = 0;
72 m_fAppContainer = FALSE;
73 m_fHighEntropyVA = FALSE;
80 m_pCustomDescrList = NULL;
82 m_pGlobalDataSection = NULL;
86 m_fDidCoInitialise = FALSE;
89 m_fEntryPointPresent = FALSE;
90 m_fHaveFieldsWithRvas = FALSE;
92 m_dwMethodsFolded = 0;
95 m_crExtends = mdTypeDefNil;
101 m_firstArgName = NULL;
102 m_lastArgName = NULL;
103 m_szNamespace = new char[2];
104 m_szNamespace[0] = 0;
105 m_NSstack.PUSH(m_szNamespace);
107 m_szFullNS = new char[MAX_NAMESPACE_LENGTH];
108 memset(m_szFullNS,0,MAX_NAMESPACE_LENGTH);
109 m_ulFullNSLen = MAX_NAMESPACE_LENGTH;
112 m_fInitialisedMetaData = FALSE;
113 m_fAutoInheritFromObject = TRUE;
115 m_ulLastDebugLine = 0xFFFFFFFF;
116 m_ulLastDebugColumn = 0xFFFFFFFF;
117 m_ulLastDebugLineEnd = 0xFFFFFFFF;
118 m_ulLastDebugColumnEnd = 0xFFFFFFFF;
120 m_pSymDocument = NULL;
121 m_dwIncludeDebugInfo = 0;
122 m_fGeneratePDB = FALSE;
123 m_fIsMscorlib = FALSE;
134 m_fReportProgress = TRUE;
135 m_tkCurrentCVOwner = 1; // module
136 m_pOutputBuffer = NULL;
138 m_dwSubsystem = (DWORD)-1;
139 m_dwComImageFlags = COMIMAGE_FLAGS_ILONLY;
140 m_dwFileAlignment = 0;
142 m_stSizeOfStackReserve = 0;
143 m_dwCeeFileFlags = ICEE_CREATE_FILE_PURE_IL;
145 g_szSourceFileName[0] = 0;
147 m_guidLang = CorSym_LanguageType_ILAssembly;
148 m_guidLangVendor = CorSym_LanguageVendor_Microsoft;
149 m_guidDoc = CorSym_DocumentType_Text;
150 for(int i=0; i<INSTR_POOL_SIZE; i++) m_Instr[i].opcode = -1;
151 m_wzResourceFile = NULL;
152 m_wzKeySourceName = NULL;
158 m_pOutputBuffer = new BYTE[OUTPUT_BUFFER_SIZE];
160 m_pCurOutputPos = m_pOutputBuffer;
161 m_pEndOutputPos = m_pOutputBuffer + OUTPUT_BUFFER_SIZE;
163 m_crImplList = new mdTypeRef[MAX_INTERFACES_IMPLEMENTED];
164 m_nImplListSize = MAX_INTERFACES_IMPLEMENTED;
166 m_pManifest = new AsmMan((void*)this);
168 dummyClass = new Class(NULL);
169 indexKeywords(&indxKeywords);
173 Assembler::~Assembler()
175 if(m_pbsMD) delete m_pbsMD;
177 if(m_pMarshal) delete m_pMarshal;
178 if(m_pManifest) delete m_pManifest;
179 if(m_pPInvoke) delete m_pPInvoke;
181 if(m_pVTable) delete m_pVTable;
183 m_lstGlobalLabel.RESET(true);
184 m_lstGlobalFixup.RESET(true);
185 m_hshClass.RESET(false);
186 m_lstClass.RESET(true);
187 while((m_ClassStack.POP()));
188 while(m_CustomDescrListStack.POP());
190 dummyClass->m_szFQN = NULL;
193 if (m_pOutputBuffer) delete [] m_pOutputBuffer;
194 if (m_crImplList) delete [] m_crImplList;
195 if (m_TyParList) delete m_TyParList;
197 if (m_pCeeFileGen != NULL) {
199 m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
200 #ifdef FEATURE_CORECLR
201 DestroyICeeFileGen(&m_pCeeFileGen);
203 MscorpeSxS::DestroyICeeFileGen(&m_pCeeFileGen);
205 m_pCeeFileGen = NULL;
208 while((m_szNamespace = m_NSstack.POP())) ;
209 delete [] m_szFullNS;
211 m_DocWriterList.RESET(true);
213 m_MethodBodyList.RESET(true);
215 m_TypeDefDList.RESET(true);
217 if (m_pSymWriter != NULL)
219 m_pSymWriter->Close();
220 m_pSymWriter->Release();
223 if (m_pImporter != NULL)
225 m_pImporter->Release();
228 if (m_pEmitter != NULL)
230 m_pEmitter->Release();
240 #ifdef FEATURE_CORECLR
242 if (g_loader != NULL)
248 if (m_fDidCoInitialise)
250 #endif // FEATURE_CORECLR
255 BOOL Assembler::Init()
257 #ifdef FEATURE_CORECLR
259 g_loader = CoreCLRLoader::Create(g_pszExeFile);
260 if (g_loader == NULL)
264 metaDataGetDispenser = (MetaDataGetDispenserFunc)g_loader->LoadFunction("MetaDataGetDispenser");
266 metaDataGetDispenser = (MetaDataGetDispenserFunc)MetaDataGetDispenser;
267 #endif // FEATURE_PAL
269 if(!m_fDidCoInitialise)
271 if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
273 m_fDidCoInitialise = TRUE;
275 #endif // FEATURE_CORECLR
276 if (m_pCeeFileGen != NULL) {
278 m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
279 #ifdef FEATURE_CORECLR
280 DestroyICeeFileGen(&m_pCeeFileGen);
282 MscorpeSxS::DestroyICeeFileGen(&m_pCeeFileGen);
284 m_pCeeFileGen = NULL;
286 #ifdef FEATURE_CORECLR
287 if (FAILED(CreateICeeFileGen(&m_pCeeFileGen))) return FALSE;
289 if (FAILED(MscorpeSxS::CreateICeeFileGen(&m_pCeeFileGen))) return FALSE;
291 if (FAILED(m_pCeeFileGen->CreateCeeFileEx(&m_pCeeFile,(ULONG)m_dwCeeFileFlags))) return FALSE;
293 if (FAILED(m_pCeeFileGen->GetSectionCreate(m_pCeeFile, ".il", sdReadOnly, &m_pILSection))) return FALSE;
294 if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".sdata", sdReadWrite, &m_pGlobalDataSection))) return FALSE;
295 if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".tls", sdReadWrite, &m_pTLSSection))) return FALSE;
300 void Assembler::SetDLL(BOOL IsDll)
303 OK = m_pCeeFileGen->SetDllSwitch(m_pCeeFile, IsDll);
304 _ASSERTE(SUCCEEDED(OK));
309 void Assembler::SetOBJ(BOOL IsObj)
312 OK = m_pCeeFileGen->SetObjSwitch(m_pCeeFile, IsObj);
313 _ASSERTE(SUCCEEDED(OK));
319 void Assembler::ResetArgNameList()
321 if(m_firstArgName) delArgNameList(m_firstArgName);
322 m_firstArgName = NULL;
323 m_lastArgName = NULL;
326 void Assembler::ResetForNextMethod()
332 m_pCurOutputPos = m_pOutputBuffer;
337 void Assembler::ResetLineNumbers()
339 // reset line number information
340 m_ulLastDebugLine = 0xFFFFFFFF;
341 m_ulLastDebugColumn = 0xFFFFFFFF;
342 m_ulLastDebugLineEnd = 0xFFFFFFFF;
343 m_ulLastDebugColumnEnd = 0xFFFFFFFF;
346 BOOL Assembler::AddMethod(Method *pMethod)
348 BOOL fIsInterface=FALSE, fIsImport=FALSE;
349 ULONG PEFileOffset=0;
351 _ASSERTE(m_pCeeFileGen != NULL);
354 report->error("pMethod == NULL");
357 if(pMethod->m_pClass != NULL)
359 fIsInterface = IsTdInterface(pMethod->m_pClass->m_Attr);
360 fIsImport = IsTdImport(pMethod->m_pClass->m_Attr);
366 if(fIsInterface && (!IsMdStatic(pMethod->m_Attr))) strcat_s(sz,1024," non-static declared in interface");
367 if(fIsImport) strcat_s(sz,1024," imported");
368 if(IsMdAbstract(pMethod->m_Attr)) strcat_s(sz,1024," abstract");
369 if(IsMdPinvokeImpl(pMethod->m_Attr)) strcat_s(sz,1024," pinvoke");
370 if(!IsMiIL(pMethod->m_wImplAttr)) strcat_s(sz,1024," non-IL");
371 if(IsMiRuntime(pMethod->m_wImplAttr)) strcat_s(sz,1024," runtime-supplied");
372 if(IsMiInternalCall(pMethod->m_wImplAttr)) strcat_s(sz,1024," an internal call");
375 report->error("Method cannot have body if it is%s\n",sz);
378 else // method has no body
380 if(fIsImport || IsMdAbstract(pMethod->m_Attr) || IsMdPinvokeImpl(pMethod->m_Attr)
381 || IsMiRuntime(pMethod->m_wImplAttr) || IsMiInternalCall(pMethod->m_wImplAttr)) return TRUE;
384 report->error("Method has no body\n");
389 report->warn("Method has no body, 'ret' emitted\n");
390 Instr* pIns = GetInstr();
393 memset(pIns,0,sizeof(Instr));
394 pIns->opcode = CEE_RET;
400 if(pMethod->m_Locals.COUNT()) pMethod->m_LocalsSig=0x11000001; // placeholder, the real token 2b defined in EmitMethod
402 COR_ILMETHOD_FAT fatHeader;
403 fatHeader.SetFlags(pMethod->m_Flags);
404 fatHeader.SetMaxStack(pMethod->m_MaxStack);
405 fatHeader.SetLocalVarSigTok(pMethod->m_LocalsSig);
406 fatHeader.SetCodeSize(m_CurPC);
407 bool moreSections = (pMethod->m_dwNumExceptions != 0);
409 // if max stack is specified <8, force fat header, otherwise (with tiny header) it will default to 8
410 if((fatHeader.GetMaxStack() < 8)&&(fatHeader.GetLocalVarSigTok()==0)&&(fatHeader.GetCodeSize()<64)&&(!moreSections))
411 fatHeader.SetFlags(fatHeader.GetFlags() | CorILMethod_InitLocals); //forces fat header but does nothing else, since LocalVarSigTok==0
413 unsigned codeSize = m_CurPC;
414 unsigned codeSizeAligned = codeSize;
416 codeSizeAligned = (codeSizeAligned + 3) & ~3; // to insure EH section aligned
418 unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, moreSections);
419 unsigned ehSize = COR_ILMETHOD_SECT_EH::Size(pMethod->m_dwNumExceptions, pMethod->m_ExceptionList);
420 unsigned totalSize = headerSize + codeSizeAligned + ehSize;
425 if((pbsBody = new BinStr())==NULL) return FALSE;
426 if((outBuff = pbsBody->getBuff(totalSize))==NULL) return FALSE;
427 endbuf = &outBuff[totalSize];
430 outBuff += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, outBuff);
432 pMethod->m_pCode = outBuff;
433 pMethod->m_headerOffset= PEFileOffset;
434 pMethod->m_methodOffset= PEFileOffset + headerSize;
435 pMethod->m_CodeSize = codeSize;
440 memset(outBuff,0,codeSizeAligned);
441 memcpy(outBuff, m_pOutputBuffer, codeSize);
442 outBuff += codeSizeAligned;
445 if(pMethod->m_dwNumExceptions)
448 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pEx;
449 DWORD TryEnd,HandlerEnd, dwEx, dwEf;
450 for(dwEx = 0, pEx = pMethod->m_ExceptionList; dwEx < pMethod->m_dwNumExceptions; dwEx++, pEx++)
452 if(pEx->GetTryOffset() > m_CurPC) // i.e., pMethod->m_CodeSize
454 report->error("Invalid SEH clause #%d: Try block starts beyond code size\n",dwEx+1);
456 TryEnd = pEx->GetTryOffset()+pEx->GetTryLength();
459 report->error("Invalid SEH clause #%d: Try block ends beyond code size\n",dwEx+1);
461 if(pEx->GetHandlerOffset() > m_CurPC)
463 report->error("Invalid SEH clause #%d: Handler block starts beyond code size\n",dwEx+1);
465 HandlerEnd = pEx->GetHandlerOffset()+pEx->GetHandlerLength();
466 if(HandlerEnd > m_CurPC)
468 report->error("Invalid SEH clause #%d: Handler block ends beyond code size\n",dwEx+1);
470 if(pEx->Flags & COR_ILEXCEPTION_CLAUSE_FILTER)
472 if(!((pEx->GetFilterOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
474 report->error("Invalid SEH clause #%d: Try and Filter/Handler blocks overlap\n",dwEx+1);
476 for(dwEf = 0; dwEf < pMethod->m_dwNumEndfilters; dwEf++)
478 if(pMethod->m_EndfilterOffsetList[dwEf] == pEx->GetHandlerOffset()) break;
480 if(dwEf >= pMethod->m_dwNumEndfilters)
482 report->error("Invalid SEH clause #%d: Filter block separated from Handler, or not ending with endfilter\n",dwEx+1);
486 if(!((pEx->GetHandlerOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
488 report->error("Invalid SEH clause #%d: Try and Handler blocks overlap\n",dwEx+1);
493 outBuff += COR_ILMETHOD_SECT_EH::Emit(ehSize, pMethod->m_dwNumExceptions,
494 pMethod->m_ExceptionList, false, outBuff);
496 _ASSERTE(outBuff == endbuf);
498 pMethod->m_pbsBody = pbsBody;
500 LocalMemberRefFixup* pMRF;
501 while((pMRF = pMethod->m_LocalMemberRefFixupList.POP()))
503 pMRF->offset += (size_t)(pMethod->m_pCode);
504 m_LocalMemberRefFixupList.PUSH(pMRF); // transfer MRF to assembler's list
507 if(m_fReportProgress)
509 if (pMethod->IsGlobalMethod())
510 report->msg("Assembled global method %s\n", pMethod->m_szName);
511 else report->msg("Assembled method %s::%s\n", pMethod->m_pClass->m_szFQN,
518 BOOL Assembler::EmitMethodBody(Method* pMethod, BinStr* pbsOut)
522 BinStr* pbsBody = pMethod->m_pbsBody;
524 if(pbsBody && (totalSize = pbsBody->length()))
526 unsigned headerSize = pMethod->m_methodOffset-pMethod->m_headerOffset;
527 MethodBody* pMB = NULL;
528 // ----------emit locals signature-------------------
530 if((uLocals = pMethod->m_Locals.COUNT()))
533 BinStr* pbsSig = new BinStr();
537 const COR_SIGNATURE* mySig;
539 pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_LOCAL_SIG);
540 cnt = CorSigCompressData(uLocals,pbsSig->getBuff(5));
541 pbsSig->remove(5-cnt);
542 for(cnt = 0; (pVD = pMethod->m_Locals.PEEK(cnt)); cnt++)
544 if(pVD->pbsSig) pbsSig->append(pVD->pbsSig);
547 report->error("Undefined type of local var slot %d in method %s\n",cnt,pMethod->m_szName);
548 pbsSig->appendInt8(ELEMENT_TYPE_I4);
552 cSig = pbsSig->length();
553 mySig = (const COR_SIGNATURE *)(pbsSig->ptr());
555 if (cSig > 1) // non-empty signature
557 hr = m_pEmitter->GetTokenFromSig(mySig, cSig, &pMethod->m_LocalsSig);
558 _ASSERTE(SUCCEEDED(hr));
561 COR_ILMETHOD_FAT* pFH; // Fat header guaranteed, because there are local vars
562 pFH = (COR_ILMETHOD_FAT*)(pMethod->m_pbsBody->ptr());
563 pFH->SetLocalVarSigTok(pMethod->m_LocalsSig);
565 //--------------------------------------------------------------------------------
566 if(m_fGeneratePDB && (m_pSymWriter != NULL))
568 m_pSymWriter->OpenMethod(pMethod->m_Tok);
569 ULONG N = pMethod->m_LinePCList.COUNT();
570 if(pMethod->m_fEntryPoint) m_pSymWriter->SetUserEntryPoint(pMethod->m_Tok);
574 ULONG32 *offsets=new ULONG32[N], *lines = new ULONG32[N], *columns = new ULONG32[N];
575 ULONG32 *endlines=new ULONG32[N], *endcolumns=new ULONG32[N];
576 if(offsets && lines && columns && endlines && endcolumns)
580 while((pDW = m_DocWriterList.PEEK(j++)))
582 if((m_pSymDocument = pDW->pWriter))
585 for(i=0, n=0; (pLPC = pMethod->m_LinePCList.PEEK(i)); i++)
587 if(pLPC->pWriter == m_pSymDocument)
589 offsets[n] = pLPC->PC;
590 lines[n] = pLPC->Line;
591 columns[n] = pLPC->Column;
592 endlines[n] = pLPC->LineEnd;
593 endcolumns[n] = pLPC->ColumnEnd;
597 if(n) m_pSymWriter->DefineSequencePoints(m_pSymDocument,n,
598 offsets,lines,columns,endlines,endcolumns);
599 } // end if(pSymDocument)
600 } // end while(pDW = next doc.writer)
601 pMethod->m_LinePCList.RESET(true);
603 else report->error("\nOutOfMemory!\n");
608 delete [] endcolumns;
611 if(pMethod->m_ulLines[1])
612 hrr = m_pSymWriter->SetMethodSourceRange(m_pSymDocument,pMethod->m_ulLines[0], pMethod->m_ulColumns[0],
613 m_pSymDocument,pMethod->m_ulLines[1], pMethod->m_ulColumns[1]);
614 EmitScope(&(pMethod->m_MainScope)); // recursively emits all nested scopes
616 m_pSymWriter->CloseMethod();
617 } // end if(fIncludeDebugInfo)
618 //-----------------------------------------------------
622 for(int k=0; (pMB = m_MethodBodyList.PEEK(k)) != NULL; k++)
624 if((pMB->pbsBody->length() == totalSize)
625 && (memcmp(pMB->pbsBody->ptr(), pbsBody->ptr(),totalSize)==0))
630 pMethod->m_headerOffset= pMB->RVA;
631 pMethod->m_methodOffset= pMB->RVA + headerSize;
632 pMethod->m_pCode = pMB->pCode;
634 pMethod->m_pbsBody = NULL;
641 unsigned align = (headerSize == 1)? 1 : 4;
642 ULONG PEFileOffset, methodRVA;
647 PEFileOffset = pbsOut->length();
649 while(PEFileOffset & align)
651 pbsOut->appendInt8(0);
654 pbsOut->append(pbsBody);
655 outBuff = (BYTE*)(pbsOut->ptr()) + (pbsOut->length() - pbsBody->length());
662 if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize,
663 align, (void **) &outBuff))) return FALSE;
664 memcpy(outBuff,pbsBody->ptr(),totalSize);
665 // The offset where we start, (not where the alignment bytes start!
666 if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset)))
668 PEFileOffset -= totalSize;
671 pMethod->m_pCode = outBuff + headerSize;
672 pMethod->m_headerOffset= PEFileOffset;
673 pMethod->m_methodOffset= PEFileOffset + headerSize;
674 DoDeferredILFixups(pMethod);
676 if(m_fENCMode) methodRVA = PEFileOffset;
677 else m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA);
679 pMethod->m_headerOffset= methodRVA;
680 pMethod->m_methodOffset= methodRVA + headerSize;
683 if((pMB = new MethodBody)==NULL) return FALSE;
684 pMB->pbsBody = pbsBody;
685 pMB->RVA = methodRVA;
686 pMB->pCode = pMethod->m_pCode;
687 m_MethodBodyList.PUSH(pMB);
691 //pMethod->m_pbsBody = NULL;
693 m_pEmitter->SetRVA(pMethod->m_Tok,pMethod->m_headerOffset);
700 ImportDescriptor* Assembler::EmitImport(BinStr* DllName)
703 ImportDescriptor* pID;
706 if(DllName) l = DllName->length(); // No zero terminator here!
709 sz = (char*)DllName->ptr();
710 while((pID=m_ImportList.PEEK(i++)))
712 if((pID->dwDllName== (DWORD) l)&& !memcmp(pID->szDllName,sz,l)) return pID;
717 while((pID=m_ImportList.PEEK(i++)))
719 if(pID->dwDllName==0) return pID;
722 if((pID = new ImportDescriptor(sz,l)))
724 m_ImportList.PUSH(pID);
725 pID->mrDll = TokenFromRid(m_ImportList.COUNT(),mdtModuleRef);
728 else report->error("Failed to allocate import descriptor\n");
732 void Assembler::EmitImports()
734 WCHAR* wzDllName=&wzUniBuf[0];
735 ImportDescriptor* pID;
738 for(i=0; (pID = m_ImportList.PEEK(i)); i++)
740 WszMultiByteToWideChar(g_uCodePage,0,pID->szDllName,-1,wzDllName,dwUniBuf-1);
741 if(FAILED(m_pEmitter->DefineModuleRef( // S_OK or error.
742 wzDllName, // [IN] DLL name
743 &tk))) // [OUT] returned
744 report->error("Failed to define module ref '%s'\n",pID->szDllName);
746 _ASSERTE(tk == pID->mrDll);
750 HRESULT Assembler::EmitPinvokeMap(mdToken tk, PInvokeDescriptor* pDescr)
752 WCHAR* wzAlias=&wzUniBuf[0];
754 if(pDescr->szAlias) WszMultiByteToWideChar(g_uCodePage,0,pDescr->szAlias,-1,wzAlias,dwUniBuf-1);
756 return m_pEmitter->DefinePinvokeMap( // Return code.
757 tk, // [IN] FieldDef, MethodDef or MethodImpl.
758 pDescr->dwAttrs, // [IN] Flags used for mapping.
759 (LPCWSTR)wzAlias, // [IN] Import name.
760 pDescr->mrDll); // [IN] ModuleRef token for the target DLL.
763 void Assembler::EmitScope(Scope* pSCroot)
765 static ULONG32 scopeID;
766 static ARG_NAME_LIST *pVarList;
768 WCHAR* wzVarName=&wzUniBuf[0];
769 char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
770 Scope* pSC = pSCroot;
771 if(pSC && m_pSymWriter)
773 if(SUCCEEDED(m_pSymWriter->OpenScope(pSC->dwStart,&scopeID)))
777 for(pVarList = pSC->pLocals; pVarList; pVarList = pVarList->pNext)
781 if((pVarList->szName)&&(*(pVarList->szName))) strcpy_s(szPhonyName,dwUniBuf >> 1,pVarList->szName);
782 else sprintf_s(szPhonyName,(dwUniBuf >> 1),"V_%d",pVarList->dwAttr);
784 WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzVarName,dwUniBuf >> 1);
786 m_pSymWriter->DefineLocalVariable(wzVarName,0,pVarList->pSig->length(),
787 (BYTE*)pVarList->pSig->ptr(),ADDR_IL_OFFSET,pVarList->dwAttr,0,0,0,0);
791 report->error("Local Var '%s' has no signature\n",pVarList->szName);
795 for(i = 0; (pSC = pSCroot->SubScope.PEEK(i)); i++) EmitScope(pSC);
796 m_pSymWriter->CloseScope(pSCroot->dwEnd);
801 BOOL Assembler::EmitMethod(Method *pMethod)
803 // Emit the metadata for a method definition
804 BOOL fSuccess = FALSE;
805 WCHAR* wzMemberName=&wzUniBuf[0];
809 mdMethodDef MethodToken;
810 mdTypeDef ClassToken = mdTypeDefNil;
812 COR_SIGNATURE *mySig;
814 _ASSERTE((m_pCeeFileGen != NULL) && (pMethod != NULL));
815 fIsInterface = ((pMethod->m_pClass != NULL) && IsTdInterface(pMethod->m_pClass->m_Attr));
818 pszMethodName = pMethod->m_szName;
819 mySig = pMethod->m_pMethodSig;
820 cSig = pMethod->m_dwMethodCSig;
822 // If this is an instance method, make certain the signature says so
824 if (!(pMethod->m_Attr & mdStatic))
825 *mySig |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
827 ClassToken = (pMethod->IsGlobalMethod())? mdTokenNil
828 : pMethod->m_pClass->m_cl;
829 // Convert name to UNICODE
830 WszMultiByteToWideChar(g_uCodePage,0,pszMethodName,-1,wzMemberName,dwUniBuf-1);
832 if(IsMdPrivateScope(pMethod->m_Attr))
834 WCHAR* p = wcsstr(wzMemberName,W("$PST06"));
838 if (FAILED(m_pEmitter->DefineMethod(ClassToken, // parent class
839 wzMemberName, // member name
840 pMethod->m_Attr & ~mdReservedMask, // member attributes
841 mySig, // member signature
844 pMethod->m_wImplAttr, // implflags
847 report->error("Failed to define method '%s'\n",pszMethodName);
850 pMethod->m_Tok = MethodToken;
851 //--------------------------------------------------------------------------------
852 // the only way to set mdRequireSecObject:
853 if(pMethod->m_Attr & mdRequireSecObject)
855 mdToken tkPseudoClass;
856 if(FAILED(m_pEmitter->DefineTypeRefByName(1, COR_REQUIRES_SECOBJ_ATTRIBUTE, &tkPseudoClass)))
857 report->error("Unable to define type reference '%s'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
860 mdToken tkPseudoCtor;
861 BYTE bSig[3] = {IMAGE_CEE_CS_CALLCONV_HASTHIS,0,ELEMENT_TYPE_VOID};
862 if(FAILED(m_pEmitter->DefineMemberRef(tkPseudoClass, W(".ctor"), (PCCOR_SIGNATURE)bSig, 3, &tkPseudoCtor)))
863 report->error("Unable to define member reference '%s::.ctor'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
864 else DefineCV(new CustomDescr(MethodToken,tkPseudoCtor,NULL));
868 if (pMethod->m_NumTyPars)
873 for(i = 0; i < pMethod->m_NumTyPars; i++)
875 //ptk = (pMethod->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pMethod->m_TyParBounds[i]->ptr());
876 //if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,0,pMethod->m_TyParNames[i],0,ptk,&tk)))
877 ptk = (pMethod->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pMethod->m_TyPars[i].Bounds()->ptr());
878 if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,pMethod->m_TyPars[i].Attrs(),pMethod->m_TyPars[i].Name(),0,ptk,&tk)))
879 report->error("Unable to define generic param'\n");
881 EmitCustomAttributes(tk, pMethod->m_TyPars[i].CAList());
884 //--------------------------------------------------------------------------------
885 EmitSecurityInfo(MethodToken,
886 pMethod->m_pPermissions,
887 pMethod->m_pPermissionSets);
888 //--------------------------------------------------------------------------------
889 if (pMethod->m_fEntryPoint)
891 if(fIsInterface) report->error("Entrypoint in Interface: Method '%s'\n",pszMethodName);
893 if (FAILED(m_pCeeFileGen->SetEntryPoint(m_pCeeFile, MethodToken)))
895 report->error("Failed to set entry point for method '%s'\n",pszMethodName);
900 //--------------------------------------------------------------------------------
901 if(IsMdPinvokeImpl(pMethod->m_Attr))
903 if(pMethod->m_pPInvoke)
906 if(pMethod->m_pPInvoke->szAlias == NULL) pMethod->m_pPInvoke->szAlias = pszMethodName;
907 hr = EmitPinvokeMap(MethodToken,pMethod->m_pPInvoke);
908 if(pMethod->m_pPInvoke->szAlias == pszMethodName) pMethod->m_pPInvoke->szAlias = NULL;
912 report->error("Failed to set PInvoke map for method '%s'\n",pszMethodName);
918 { // add parameters to metadata
919 void const *pValue=NULL;
921 DWORD dwCPlusTypeFlag=0;
923 WCHAR* wzParName=&wzUniBuf[0];
924 char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
925 if(pMethod->m_dwRetAttr || pMethod->m_pRetMarshal || pMethod->m_RetCustDList.COUNT())
927 if(pMethod->m_pRetValue)
929 dwCPlusTypeFlag= (DWORD)*(pMethod->m_pRetValue->ptr());
930 pValue = (void const *)(pMethod->m_pRetValue->ptr()+1);
931 cbValue = pMethod->m_pRetValue->length()-1;
932 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
940 m_pEmitter->DefineParam(MethodToken,0,NULL,pMethod->m_dwRetAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
942 if(pMethod->m_pRetMarshal)
944 if(FAILED(m_pEmitter->SetFieldMarshal (
945 pdef, // [IN] given a fieldDef or paramDef token
946 (PCCOR_SIGNATURE)(pMethod->m_pRetMarshal->ptr()), // [IN] native type specification
947 pMethod->m_pRetMarshal->length()))) // [IN] count of bytes of pvNativeType
948 report->error("Failed to set param marshaling for return\n");
951 EmitCustomAttributes(pdef, &(pMethod->m_RetCustDList));
953 for(ARG_NAME_LIST *pAN=pMethod->m_firstArgName; pAN; pAN = pAN->pNext)
955 if(pAN->nNum >= 65535)
957 report->error("Method '%s': Param.sequence number (%d) exceeds 65535, unable to define parameter\n",pszMethodName,pAN->nNum+1);
960 if(pAN->dwName) strcpy_s(szPhonyName,dwUniBuf >> 1,pAN->szName);
961 else sprintf_s(szPhonyName,(dwUniBuf >> 1),"A_%d",pAN->nNum);
963 WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzParName,dwUniBuf >> 1);
967 dwCPlusTypeFlag= (DWORD)*(pAN->pValue->ptr());
968 pValue = (void const *)(pAN->pValue->ptr()+1);
969 cbValue = pAN->pValue->length()-1;
970 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
978 m_pEmitter->DefineParam(MethodToken,pAN->nNum+1,wzParName,pAN->dwAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
981 if(FAILED(m_pEmitter->SetFieldMarshal (
982 pdef, // [IN] given a fieldDef or paramDef token
983 (PCCOR_SIGNATURE)(pAN->pMarshal->ptr()), // [IN] native type specification
984 pAN->pMarshal->length()))) // [IN] count of bytes of pvNativeType
985 report->error("Failed to set param marshaling for '%s'\n",pAN->szName);
987 EmitCustomAttributes(pdef, &(pAN->CustDList));
991 //--------------------------------------------------------------------------------
992 // Update method implementations for this method
994 MethodImplDescriptor* pMID;
996 for(i=0;(pMID = pMethod->m_MethodImplDList.PEEK(i));i++)
998 pMID->m_tkImplementingMethod = MethodToken;
999 // don't delete it here, it's still in the general list
1002 //--------------------------------------------------------------------------------
1003 EmitCustomAttributes(MethodToken, &(pMethod->m_CustomDescrList));
1005 if (fSuccess == FALSE) m_State = STATE_FAIL;
1009 BOOL Assembler::EmitMethodImpls()
1011 MethodImplDescriptor* pMID;
1014 for(i=0; (pMID = m_MethodImplDList.PEEK(i)); i++)
1016 if(m_fENCMode && (!pMID->m_fNew)) continue;
1017 pMID->m_tkImplementingMethod = ResolveLocalMemberRef(pMID->m_tkImplementingMethod);
1018 pMID->m_tkImplementedMethod = ResolveLocalMemberRef(pMID->m_tkImplementedMethod);
1019 if(FAILED(m_pEmitter->DefineMethodImpl( pMID->m_tkDefiningClass,
1020 pMID->m_tkImplementingMethod,
1021 pMID->m_tkImplementedMethod)))
1023 report->error("Failed to define Method Implementation");
1026 pMID->m_fNew = FALSE;
1031 mdToken Assembler::ResolveLocalMemberRef(mdToken tok)
1033 if(TypeFromToken(tok) == 0x99000000)
1035 tok = RidFromToken(tok);
1036 if(tok) tok = m_LocalMethodRefDList.PEEK(tok-1)->m_tkResolved;
1038 else if(TypeFromToken(tok) == 0x98000000)
1040 tok = RidFromToken(tok);
1041 if(tok) tok = m_LocalFieldRefDList.PEEK(tok-1)->m_tkResolved;
1046 BOOL Assembler::EmitEvent(EventDescriptor* pED)
1048 mdMethodDef mdAddOn=mdMethodDefNil,
1049 mdRemoveOn=mdMethodDefNil,
1050 mdFire=mdMethodDefNil,
1053 WCHAR* wzMemberName=&wzUniBuf[0];
1055 if(!pED) return FALSE;
1057 WszMultiByteToWideChar(g_uCodePage,0,pED->m_szName,-1,wzMemberName,dwUniBuf-1);
1059 mdAddOn = ResolveLocalMemberRef(pED->m_tkAddOn);
1060 if(TypeFromToken(mdAddOn) != mdtMethodDef)
1062 report->error("Invalid Add method of event '%s'\n",pED->m_szName);
1065 mdRemoveOn = ResolveLocalMemberRef(pED->m_tkRemoveOn);
1066 if(TypeFromToken(mdRemoveOn) != mdtMethodDef)
1068 report->error("Invalid Remove method of event '%s'\n",pED->m_szName);
1071 mdFire = ResolveLocalMemberRef(pED->m_tkFire);
1072 if((RidFromToken(mdFire)!=0)&&(TypeFromToken(mdFire) != mdtMethodDef))
1074 report->error("Invalid Fire method of event '%s'\n",pED->m_szName);
1078 nOthers = pED->m_tklOthers.COUNT();
1079 mdOthers = new mdMethodDef[nOthers+1];
1080 if(mdOthers == NULL)
1082 report->error("Failed to allocate Others array for event descriptor\n");
1085 for(int j=0; j < nOthers; j++)
1087 mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pED->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken'
1089 mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1091 if(FAILED(m_pEmitter->DefineEvent( pED->m_tdClass,
1099 &(pED->m_edEventTok))))
1101 report->error("Failed to define event '%s'.\n",pED->m_szName);
1105 EmitCustomAttributes(pED->m_edEventTok, &(pED->m_CustomDescrList));
1109 BOOL Assembler::EmitProp(PropDescriptor* pPD)
1111 mdMethodDef mdSet, mdGet, *mdOthers;
1113 WCHAR* wzMemberName=&wzUniBuf[0];
1115 if(!pPD) return FALSE;
1117 WszMultiByteToWideChar(g_uCodePage,0,pPD->m_szName,-1,wzMemberName,dwUniBuf-1);
1119 mdSet = ResolveLocalMemberRef(pPD->m_tkSet);
1120 if((RidFromToken(mdSet)!=0)&&(TypeFromToken(mdSet) != mdtMethodDef))
1122 report->error("Invalid Set method of property '%s'\n",pPD->m_szName);
1125 mdGet = ResolveLocalMemberRef(pPD->m_tkGet);
1126 if((RidFromToken(mdGet)!=0)&&(TypeFromToken(mdGet) != mdtMethodDef))
1128 report->error("Invalid Get method of property '%s'\n",pPD->m_szName);
1132 nOthers = pPD->m_tklOthers.COUNT();
1133 mdOthers = new mdMethodDef[nOthers+1];
1134 if(mdOthers == NULL)
1136 report->error("Failed to allocate Others array for prop descriptor\n");
1139 for(int j=0; j < nOthers; j++)
1141 mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pPD->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken'
1143 if((RidFromToken(mdOthers[j])!=0)&&(TypeFromToken(mdOthers[j]) != mdtMethodDef))
1145 report->error("Invalid Other method of property '%s'\n",pPD->m_szName);
1151 mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1153 if(FAILED(m_pEmitter->DefineProperty( pPD->m_tdClass,
1158 pPD->m_dwCPlusTypeFlag,
1164 &(pPD->m_pdPropTok))))
1166 report->error("Failed to define property '%s'.\n",pPD->m_szName);
1170 EmitCustomAttributes(pPD->m_pdPropTok, &(pPD->m_CustomDescrList));
1174 Class *Assembler::FindCreateClass(__in __nullterminated const char *pszFQN)
1176 Class *pSearch = NULL;
1180 dummyClass->m_szFQN = pszFQN;
1181 dummyClass->m_Hash = hash((BYTE*)pszFQN, (unsigned)strlen(pszFQN), 10);
1182 pSearch = m_hshClass.FIND(dummyClass);
1183 dummyClass->m_szFQN = NULL;
1184 dummyClass->m_Hash = 0;
1189 DWORD dwFQN = (DWORD)strlen(pszFQN);
1191 Class *pEncloser = NULL;
1192 char* pszNewFQN = new char[dwFQN+1];
1193 strcpy_s(pszNewFQN,dwFQN+1,pszFQN);
1194 if((pch = strrchr(pszNewFQN, NESTING_SEP)) != NULL)
1197 pEncloser = FindCreateClass(pszNewFQN);
1200 pSearch = new Class(pszNewFQN);
1201 if (pSearch == NULL)
1202 report->error("Failed to create class '%s'\n",pszNewFQN);
1205 pSearch->m_pEncloser = pEncloser;
1206 m_lstClass.PUSH(pSearch);
1207 pSearch->m_cl = mdtTypeDef | m_lstClass.COUNT();
1208 m_hshClass.PUSH(pSearch);
1217 BOOL Assembler::EmitClass(Class *pClass)
1220 WCHAR* wzFullName=&wzUniBuf[0];
1221 HRESULT hr = E_FAIL;
1226 if(pClass == NULL) return FALSE;
1228 hr = CoCreateGuid(&guid);
1231 printf("Unable to create GUID\n");
1232 m_State = STATE_FAIL;
1236 if(pClass->m_pEncloser)
1237 szFullName = strrchr(pClass->m_szFQN,NESTING_SEP) + 1;
1239 szFullName = pClass->m_szFQN;
1241 WszMultiByteToWideChar(g_uCodePage,0,szFullName,-1,wzFullName,dwUniBuf);
1243 L = wcslen(wzFullName);
1244 if((L==0)||(wzFullName[L-1]==L'.')) // Missing class name!
1246 wcscat_s(wzFullName,dwUniBuf,W("$UNNAMED_TYPE$"));
1249 pClass->m_Attr = CheckClassFlagsIfNested(pClass->m_pEncloser, pClass->m_Attr);
1251 if (pClass->m_pEncloser)
1253 hr = m_pEmitter->DefineNestedType( wzFullName,
1254 pClass->m_Attr, // attributes
1255 pClass->m_crExtends, // CR extends class
1256 pClass->m_crImplements,// implements
1257 pClass->m_pEncloser->m_cl, // Enclosing class.
1262 hr = m_pEmitter->DefineTypeDef( wzFullName,
1263 pClass->m_Attr, // attributes
1264 pClass->m_crExtends, // CR extends class
1265 pClass->m_crImplements,// implements
1268 _ASSERTE(tok == pClass->m_cl);
1269 if (FAILED(hr)) goto exit;
1270 if (pClass->m_NumTyPars)
1275 for(i = 0; i < pClass->m_NumTyPars; i++)
1277 //ptk = (pClass->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pClass->m_TyParBounds[i]->ptr());
1278 //if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyParAttrs[i],pClass->m_TyParNames[i],0,ptk,&tk)))
1279 ptk = (pClass->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pClass->m_TyPars[i].Bounds()->ptr());
1280 if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyPars[i].Attrs(),pClass->m_TyPars[i].Name(),0,ptk,&tk)))
1281 report->error("Unable to define generic param'\n");
1283 EmitCustomAttributes(tk, pClass->m_TyPars[i].CAList());
1288 EmitCustomAttributes(pClass->m_cl, &(pClass->m_CustDList));
1292 return SUCCEEDED(hr);
1295 BOOL Assembler::DoGlobalFixups()
1297 GlobalFixup *pSearch;
1299 for (int i=0; (pSearch = m_lstGlobalFixup.PEEK(i)); i++)
1301 GlobalLabel * pLabel = FindGlobalLabel(pSearch->m_szLabel);
1304 report->error("Unable to find forward reference global label '%s'\n",
1305 pSearch->m_szLabel);
1307 m_State = STATE_FAIL;
1310 //BYTE * pReference = pSearch->m_pReference;
1311 //DWORD GlobalOffset = pLabel->m_GlobalOffset;
1312 //memcpy(pReference,&GlobalOffset,4);
1313 SET_UNALIGNED_VAL32(pSearch->m_pReference,pLabel->m_GlobalOffset);
1319 state_t Assembler::AddGlobalLabel(__in __nullterminated char *pszName, HCEESECTION section)
1321 if (FindGlobalLabel(pszName) != NULL)
1323 report->error("Duplicate global label '%s'\n", pszName);
1324 m_State = STATE_FAIL;
1331 hr = m_pCeeFileGen->GetSectionDataLen(section, &GlobalOffset);
1332 _ASSERTE(SUCCEEDED(hr));
1334 GlobalLabel *pNew = new GlobalLabel(pszName, GlobalOffset, section);
1337 report->error("Failed to allocate global label '%s'\n",pszName);
1338 m_State = STATE_FAIL;
1342 m_lstGlobalLabel.PUSH(pNew);
1346 void Assembler::AddLabel(DWORD CurPC, __in __nullterminated char *pszName)
1348 if (m_pCurMethod->FindLabel(pszName) != NULL)
1350 report->error("Duplicate label: '%s'\n", pszName);
1352 m_State = STATE_FAIL;
1356 Label *pNew = new Label(pszName, CurPC);
1359 //m_pCurMethod->m_lstLabel.PUSH(pNew);
1360 m_lstLabel.PUSH(pNew);
1363 report->error("Failed to allocate label '%s'\n",pszName);
1364 m_State = STATE_FAIL;
1369 void Assembler::DoDeferredILFixups(Method* pMethod)
1370 { // Now that we know where in the file the code bytes will wind up,
1371 // we can update the RVAs and offsets.
1374 GlobalFixup *Fix = NULL;
1376 for (i=0;(pSearch = pMethod->m_lstILFixup.PEEK(i));i++)
1378 switch(pSearch->m_Kind)
1381 Fix = pSearch->m_Fixup;
1382 _ASSERTE(Fix != NULL);
1383 Fix->m_pReference = pMethod->m_pCode+pSearch->m_OffsetInMethod;
1387 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1388 pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1391 _ASSERTE(SUCCEEDED(hr));
1395 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1396 pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1397 m_pGlobalDataSection,
1399 _ASSERTE(SUCCEEDED(hr));
1407 /**************************************************************************/
1408 BOOL Assembler::DoFixups(Method* pMethod)
1412 for (int i=0; (pSearch = pMethod->m_lstFixup.PEEK(i)); i++)
1414 Label * pLabel = pMethod->FindLabel(pSearch->m_szLabel);
1419 report->error("Unable to find forward reference label '%s' called from PC=%d\n",
1420 pSearch->m_szLabel, pSearch->m_RelativeToPC);
1422 //m_State = STATE_FAIL;
1426 offset = pLabel->m_PC - pSearch->m_RelativeToPC;
1428 if (pSearch->m_FixupSize == 1)
1430 if (offset > 127 || offset < -128)
1432 report->error("Offset of forward reference label '%s' called from PC=%d is too large for 1 byte pcrel\n",
1433 pLabel->m_szName, pSearch->m_RelativeToPC);
1435 //m_State = STATE_FAIL;
1439 *pSearch->m_pBytes = (BYTE) offset;
1441 else if (pSearch->m_FixupSize == 4)
1443 SET_UNALIGNED_VAL32(pSearch->m_pBytes,offset);
1451 OPCODE Assembler::DecodeOpcode(const BYTE *pCode, DWORD *pdwLen)
1456 opcode = OPCODE(pCode[0]);
1459 opcode = OPCODE(pCode[1] + 256);
1460 if (opcode < 0 || opcode >= CEE_COUNT)
1479 char* Assembler::ReflectionNotation(mdToken tk)
1481 char *sz = (char*)&wzUniBuf[dwUniBuf>>1], *pc;
1483 switch(TypeFromToken(tk))
1487 Class *pClass = m_lstClass.PEEK(RidFromToken(tk)-1);
1490 strcpy_s(sz,dwUniBuf>>1,pClass->m_szFQN);
1492 while((pc = strchr(pc,NESTING_SEP)) != NULL)
1505 if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,dwUniBuf>>1,&N)))
1507 WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,dwUniBuf>>1,NULL,NULL);
1508 if(TypeFromToken(tkResScope)==mdtAssemblyRef)
1510 AsmManAssembly *pAsmRef = m_pManifest->m_AsmRefLst.PEEK(RidFromToken(tkResScope)-1);
1513 pc = &sz[strlen(sz)];
1514 pc+=sprintf_s(pc,(dwUniBuf >> 1),", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName,
1515 pAsmRef->usVerMajor,pAsmRef->usVerMinor,pAsmRef->usBuild,pAsmRef->usRevision);
1517 if(pAsmRef->pLocale && (L=pAsmRef->pLocale->length()))
1519 memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L);
1521 WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,dwUniBuf>>1,NULL,NULL);
1523 else pc+=sprintf_s(pc,(dwUniBuf >> 1),"neutral");
1524 pc = &sz[strlen(sz)];
1525 if(pAsmRef->pPublicKeyToken && (L=pAsmRef->pPublicKeyToken->length()))
1527 pc+=sprintf_s(pc,(dwUniBuf >> 1),", Publickeytoken=");
1528 BYTE* pb = (BYTE*)(pAsmRef->pPublicKeyToken->ptr());
1529 for(N=0; N<L; N++,pb++) pc+=sprintf_s(pc,(dwUniBuf >> 1),"%2.2x",*pb);
1544 --------------------------------------------------------------------
1545 mix -- mix 3 32-bit values reversibly.
1546 For every delta with one or two bits set, and the deltas of all three
1547 high bits or all three low bits, whether the original value of a,b,c
1548 is almost all zero or is uniformly distributed,
1549 * If mix() is run forward or backward, at least 32 bits in a,b,c
1550 have at least 1/4 probability of changing.
1551 * If mix() is run forward, every bit of c will change between 1/3 and
1552 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
1553 mix() was built out of 36 single-cycle latency instructions in a
1554 structure that could supported 2x parallelism, like so:
1556 a -= c; x = (c>>13);
1560 c -= b; x = (b>>13);
1562 Unfortunately, superscalar Pentiums and Sparcs can't take advantage
1563 of that parallelism. They've also turned some of those single-cycle
1564 latency instructions into multi-cycle latency instructions. Still,
1565 this is the fastest good hash I could find. There were about 2^^68
1566 to choose from. I only looked at a billion or so.
1567 --------------------------------------------------------------------
1569 #define mix(a,b,c) \
1571 a -= b; a -= c; a ^= (c >> 13); \
1572 b -= c; b -= a; b ^= (a << 8); \
1573 c -= a; c -= b; c ^= (b >> 13); \
1574 a -= b; a -= c; a ^= (c >> 12); \
1575 b -= c; b -= a; b ^= (a << 16); \
1576 c -= a; c -= b; c ^= (b >> 5); \
1577 a -= b; a -= c; a ^= (c >> 3); \
1578 b -= c; b -= a; b ^= (a << 10); \
1579 c -= a; c -= b; c ^= (b >> 15); \
1583 --------------------------------------------------------------------
1584 hash() -- hash a variable-length key into a 32-bit value
1585 k : the key (the unaligned variable-length array of bytes)
1586 len : the length of the key, counting by bytes
1587 initval : can be any 4-byte value
1588 Returns a 32-bit value. Every bit of the key affects every bit of
1589 the return value. Every 1-bit and 2-bit delta achieves avalanche.
1590 About 6*len+35 instructions.
1592 The best hash table sizes are powers of 2. There is no need to do
1593 mod a prime (mod is sooo slow!). If you need less than 32 bits,
1594 use a bitmask. For example, if you need only 10 bits, do
1595 h = (h & hashmask(10));
1596 In which case, the hash table should have hashsize(10) elements.
1598 If you are hashing n strings (ub1 **)k, do it like this:
1599 for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
1601 By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
1602 code any way you wish, private, educational, or commercial. It's free.
1604 See http://burtleburtle.net/bob/hash/evahash.html
1605 Use for hash table lookup, or anything where one collision in 2^^32 is
1606 acceptable. Do NOT use for cryptographic purposes.
1607 --------------------------------------------------------------------
1611 __in_ecount(length) const BYTE *k, /* the key */
1612 unsigned length, /* the length of the key */
1613 unsigned initval) /* the previous hash, or an arbitrary value */
1615 register unsigned a,b,c,len;
1617 /* Set up the internal state */
1619 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
1620 c = initval; /* the previous hash value */
1622 /*---------------------------------------- handle most of the key */
1625 a += (k[0] + ((unsigned)k[1] << 8) + ((unsigned)k[2] << 16) + ((unsigned)k[3] << 24));
1626 b += (k[4] + ((unsigned)k[5] << 8) + ((unsigned)k[6] << 16) + ((unsigned)k[7] << 24));
1627 c += (k[8] + ((unsigned)k[9] << 8) + ((unsigned)k[10] << 16) + ((unsigned)k[11] << 24));
1632 /*------------------------------------- handle the last 11 bytes */
1634 switch(len) /* all the case statements fall through */
1636 case 11: c+=((unsigned)k[10] << 24);
1637 case 10: c+=((unsigned)k[9] << 16);
1638 case 9 : c+=((unsigned)k[8] << 8);
1639 /* the first byte of c is reserved for the length */
1640 case 8 : b+=((unsigned)k[7] << 24);
1641 case 7 : b+=((unsigned)k[6] << 16);
1642 case 6 : b+=((unsigned)k[5] << 8);
1644 case 4 : a+=((unsigned)k[3] << 24);
1645 case 3 : a+=((unsigned)k[2] << 16);
1646 case 2 : a+=((unsigned)k[1] << 8);
1648 /* case 0: nothing left to add */
1651 /*-------------------------------------------- report the result */