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.
4//
5// File: assem.cpp
6//
7
8//
9// COM+ IL assembler
10//
11#include "ilasmpch.h"
12
13#define INITGUID
14
15#define DECLARE_DATA
16
17#include "assembler.h"
18#ifdef FEATURE_PAL
19#include "coreclrloader.h"
20CoreCLRLoader *g_loader;
21#endif // FEATURE_PAL
22MetaDataGetDispenserFunc metaDataGetDispenser;
23
24void indexKeywords(Indx* indx); // defined in asmparse.y
25
26unsigned int g_uCodePage = CP_ACP;
27unsigned int g_uConsoleCP = CP_ACP;
28
29char g_szSourceFileName[MAX_FILENAME_LENGTH*3];
30
31WCHAR wzUniBuf[dwUniBuf]; // Unicode conversion global buffer
32
33Assembler::Assembler()
34{
35 m_pDisp = NULL;
36 m_pEmitter = NULL;
37 m_pImporter = NULL;
38
39 m_fCPlusPlus = FALSE;
40 m_fWindowsCE = FALSE;
41 char* pszFQN = new char[16];
42 strcpy_s(pszFQN,16,"<Module>");
43 m_pModuleClass = new Class(pszFQN);
44 m_lstClass.PUSH(m_pModuleClass);
45 m_hshClass.PUSH(m_pModuleClass);
46 m_pModuleClass->m_cl = mdTokenNil;
47 m_pModuleClass->m_bIsMaster = FALSE;
48
49 m_fStdMapping = FALSE;
50 m_fDisplayTraceOutput= FALSE;
51 m_fENCMode = FALSE;
52 m_fTolerateDupMethods = FALSE;
53
54 m_pCurOutputPos = NULL;
55
56 m_CurPC = 0; // PC offset in method
57 m_pCurMethod = NULL;
58 m_pCurClass = NULL;
59 m_pCurEvent = NULL;
60 m_pCurProp = NULL;
61
62 m_wzMetadataVersion = NULL;
63 m_wMSVmajor = 0xFFFF;
64 m_wMSVminor = 0xFFFF;
65
66 m_wSSVersionMajor = 4;
67 m_wSSVersionMinor = 0;
68 m_fAppContainer = FALSE;
69 m_fHighEntropyVA = FALSE;
70
71 m_pCeeFileGen = NULL;
72 m_pCeeFile = 0;
73
74 m_pManifest = NULL;
75
76 m_pCustomDescrList = NULL;
77
78 m_pGlobalDataSection = NULL;
79 m_pILSection = NULL;
80 m_pTLSSection = NULL;
81
82 m_fDidCoInitialise = FALSE;
83
84 m_fDLL = FALSE;
85 m_fEntryPointPresent = FALSE;
86 m_fHaveFieldsWithRvas = FALSE;
87 m_fFoldCode = FALSE;
88 m_dwMethodsFolded = 0;
89
90 m_szScopeName[0] = 0;
91 m_crExtends = mdTypeDefNil;
92
93 m_nImplList = 0;
94 m_TyParList = NULL;
95
96 m_SEHD = NULL;
97 m_firstArgName = NULL;
98 m_lastArgName = NULL;
99 m_szNamespace = new char[2];
100 m_szNamespace[0] = 0;
101 m_NSstack.PUSH(m_szNamespace);
102
103 m_szFullNS = new char[MAX_NAMESPACE_LENGTH];
104 memset(m_szFullNS,0,MAX_NAMESPACE_LENGTH);
105 m_ulFullNSLen = MAX_NAMESPACE_LENGTH;
106
107 m_State = STATE_OK;
108 m_fInitialisedMetaData = FALSE;
109 m_fAutoInheritFromObject = TRUE;
110
111 m_ulLastDebugLine = 0xFFFFFFFF;
112 m_ulLastDebugColumn = 0xFFFFFFFF;
113 m_ulLastDebugLineEnd = 0xFFFFFFFF;
114 m_ulLastDebugColumnEnd = 0xFFFFFFFF;
115 m_pSymWriter = NULL;
116 m_pSymDocument = NULL;
117 m_dwIncludeDebugInfo = 0;
118 m_fGeneratePDB = FALSE;
119 m_fIsMscorlib = FALSE;
120 m_fOptimize = FALSE;
121 m_tkSysObject = 0;
122 m_tkSysString = 0;
123 m_tkSysValue = 0;
124 m_tkSysEnum = 0;
125
126 m_pVTable = NULL;
127 m_pMarshal = NULL;
128 m_pPInvoke = NULL;
129
130 m_fReportProgress = TRUE;
131 m_tkCurrentCVOwner = 1; // module
132 m_pOutputBuffer = NULL;
133
134 m_dwSubsystem = (DWORD)-1;
135 m_dwComImageFlags = COMIMAGE_FLAGS_ILONLY;
136 m_dwFileAlignment = 0;
137 m_stBaseAddress = 0;
138 m_stSizeOfStackReserve = 0;
139 m_dwCeeFileFlags = ICEE_CREATE_FILE_PURE_IL;
140
141 g_szSourceFileName[0] = 0;
142
143 m_guidLang = CorSym_LanguageType_ILAssembly;
144 m_guidLangVendor = CorSym_LanguageVendor_Microsoft;
145 m_guidDoc = CorSym_DocumentType_Text;
146 for(int i=0; i<INSTR_POOL_SIZE; i++) m_Instr[i].opcode = -1;
147 m_wzResourceFile = NULL;
148 m_wzKeySourceName = NULL;
149 OnErrGo = false;
150 bClock = NULL;
151
152 m_pbsMD = NULL;
153
154 m_pOutputBuffer = new BYTE[OUTPUT_BUFFER_SIZE];
155
156 m_pCurOutputPos = m_pOutputBuffer;
157 m_pEndOutputPos = m_pOutputBuffer + OUTPUT_BUFFER_SIZE;
158
159 m_crImplList = new mdTypeRef[MAX_INTERFACES_IMPLEMENTED];
160 m_nImplListSize = MAX_INTERFACES_IMPLEMENTED;
161
162 m_pManifest = new AsmMan((void*)this);
163
164 dummyClass = new Class(NULL);
165 indexKeywords(&indxKeywords);
166}
167
168
169Assembler::~Assembler()
170{
171 if(m_pbsMD) delete m_pbsMD;
172
173 if(m_pMarshal) delete m_pMarshal;
174 if(m_pManifest) delete m_pManifest;
175 if(m_pPInvoke) delete m_pPInvoke;
176
177 if(m_pVTable) delete m_pVTable;
178
179 m_lstGlobalLabel.RESET(true);
180 m_lstGlobalFixup.RESET(true);
181 m_hshClass.RESET(false);
182 m_lstClass.RESET(true);
183 while((m_ClassStack.POP()));
184 while(m_CustomDescrListStack.POP());
185 m_pCurClass = NULL;
186 dummyClass->m_szFQN = NULL;
187 delete dummyClass;
188
189 if (m_pOutputBuffer) delete [] m_pOutputBuffer;
190 if (m_crImplList) delete [] m_crImplList;
191 if (m_TyParList) delete m_TyParList;
192
193 if (m_pCeeFileGen != NULL) {
194 if (m_pCeeFile)
195 m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
196
197 DestroyICeeFileGen(&m_pCeeFileGen);
198
199 m_pCeeFileGen = NULL;
200 }
201
202 while((m_szNamespace = m_NSstack.POP())) ;
203 delete [] m_szFullNS;
204
205 m_DocWriterList.RESET(true);
206
207 m_MethodBodyList.RESET(true);
208
209 m_TypeDefDList.RESET(true);
210
211 if (m_pSymWriter != NULL)
212 {
213 m_pSymWriter->Close();
214 m_pSymWriter->Release();
215 m_pSymWriter = NULL;
216 }
217 if (m_pImporter != NULL)
218 {
219 m_pImporter->Release();
220 m_pImporter = NULL;
221 }
222 if (m_pEmitter != NULL)
223 {
224 m_pEmitter->Release();
225 m_pEmitter = NULL;
226 }
227
228 if (m_pDisp != NULL)
229 {
230 m_pDisp->Release();
231 m_pDisp = NULL;
232 }
233
234#ifdef FEATURE_PAL
235 if (g_loader != NULL)
236 {
237 g_loader->Finish();
238 }
239#endif
240
241}
242
243
244BOOL Assembler::Init()
245{
246#ifdef FEATURE_PAL
247 g_loader = CoreCLRLoader::Create(g_pszExeFile);
248 if (g_loader == NULL)
249 {
250 return FALSE;
251 }
252 metaDataGetDispenser = (MetaDataGetDispenserFunc)g_loader->LoadFunction("MetaDataGetDispenser");
253#else
254 metaDataGetDispenser = (MetaDataGetDispenserFunc)MetaDataGetDispenser;
255#endif // FEATURE_PAL
256 if (m_pCeeFileGen != NULL) {
257 if (m_pCeeFile)
258 m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
259
260 DestroyICeeFileGen(&m_pCeeFileGen);
261
262 m_pCeeFileGen = NULL;
263 }
264
265 if (FAILED(CreateICeeFileGen(&m_pCeeFileGen))) return FALSE;
266
267 if (FAILED(m_pCeeFileGen->CreateCeeFileEx(&m_pCeeFile,(ULONG)m_dwCeeFileFlags))) return FALSE;
268
269 if (FAILED(m_pCeeFileGen->GetSectionCreate(m_pCeeFile, ".il", sdReadOnly, &m_pILSection))) return FALSE;
270 if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".sdata", sdReadWrite, &m_pGlobalDataSection))) return FALSE;
271 if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".tls", sdReadWrite, &m_pTLSSection))) return FALSE;
272
273 return TRUE;
274}
275
276void Assembler::SetDLL(BOOL IsDll)
277{
278 HRESULT OK;
279 OK = m_pCeeFileGen->SetDllSwitch(m_pCeeFile, IsDll);
280 _ASSERTE(SUCCEEDED(OK));
281
282 m_fDLL = IsDll;
283}
284
285void Assembler::SetOBJ(BOOL IsObj)
286{
287 HRESULT OK;
288 OK = m_pCeeFileGen->SetObjSwitch(m_pCeeFile, IsObj);
289 _ASSERTE(SUCCEEDED(OK));
290
291 m_fOBJ = IsObj;
292}
293
294
295void Assembler::ResetArgNameList()
296{
297 if(m_firstArgName) delArgNameList(m_firstArgName);
298 m_firstArgName = NULL;
299 m_lastArgName = NULL;
300}
301
302void Assembler::ResetForNextMethod()
303{
304
305 ResetArgNameList();
306
307 m_CurPC = 0;
308 m_pCurOutputPos = m_pOutputBuffer;
309 m_State = STATE_OK;
310 m_pCurMethod = NULL;
311}
312
313void Assembler::ResetLineNumbers()
314{
315 // reset line number information
316 m_ulLastDebugLine = 0xFFFFFFFF;
317 m_ulLastDebugColumn = 0xFFFFFFFF;
318 m_ulLastDebugLineEnd = 0xFFFFFFFF;
319 m_ulLastDebugColumnEnd = 0xFFFFFFFF;
320}
321
322BOOL Assembler::AddMethod(Method *pMethod)
323{
324 BOOL fIsInterface=FALSE, fIsImport=FALSE;
325 ULONG PEFileOffset=0;
326
327 _ASSERTE(m_pCeeFileGen != NULL);
328 if (pMethod == NULL)
329 {
330 report->error("pMethod == NULL");
331 return FALSE;
332 }
333 if(pMethod->m_pClass != NULL)
334 {
335 fIsInterface = IsTdInterface(pMethod->m_pClass->m_Attr);
336 fIsImport = IsTdImport(pMethod->m_pClass->m_Attr);
337 }
338 if(m_CurPC)
339 {
340 char sz[1024];
341 sz[0] = 0;
342 if(fIsImport) strcat_s(sz,1024," imported");
343 if(IsMdAbstract(pMethod->m_Attr)) strcat_s(sz,1024," abstract");
344 if(IsMdPinvokeImpl(pMethod->m_Attr)) strcat_s(sz,1024," pinvoke");
345 if(!IsMiIL(pMethod->m_wImplAttr)) strcat_s(sz,1024," non-IL");
346 if(IsMiRuntime(pMethod->m_wImplAttr)) strcat_s(sz,1024," runtime-supplied");
347 if(IsMiInternalCall(pMethod->m_wImplAttr)) strcat_s(sz,1024," an internal call");
348 if(strlen(sz))
349 {
350 report->error("Method cannot have body if it is%s\n",sz);
351 }
352 }
353 else // method has no body
354 {
355 if(fIsImport || IsMdAbstract(pMethod->m_Attr) || IsMdPinvokeImpl(pMethod->m_Attr)
356 || IsMiRuntime(pMethod->m_wImplAttr) || IsMiInternalCall(pMethod->m_wImplAttr)) return TRUE;
357 if(OnErrGo)
358 {
359 report->error("Method has no body\n");
360 return TRUE;
361 }
362 else
363 {
364 report->warn("Method has no body, 'ret' emitted\n");
365 Instr* pIns = GetInstr();
366 if(pIns)
367 {
368 memset(pIns,0,sizeof(Instr));
369 pIns->opcode = CEE_RET;
370 EmitOpcode(pIns);
371 }
372 }
373 }
374
375 if(pMethod->m_Locals.COUNT()) pMethod->m_LocalsSig=0x11000001; // placeholder, the real token 2b defined in EmitMethod
376
377 COR_ILMETHOD_FAT fatHeader;
378 fatHeader.SetFlags(pMethod->m_Flags);
379 fatHeader.SetMaxStack(pMethod->m_MaxStack);
380 fatHeader.SetLocalVarSigTok(pMethod->m_LocalsSig);
381 fatHeader.SetCodeSize(m_CurPC);
382 bool moreSections = (pMethod->m_dwNumExceptions != 0);
383
384 // if max stack is specified <8, force fat header, otherwise (with tiny header) it will default to 8
385 if((fatHeader.GetMaxStack() < 8)&&(fatHeader.GetLocalVarSigTok()==0)&&(fatHeader.GetCodeSize()<64)&&(!moreSections))
386 fatHeader.SetFlags(fatHeader.GetFlags() | CorILMethod_InitLocals); //forces fat header but does nothing else, since LocalVarSigTok==0
387
388 unsigned codeSize = m_CurPC;
389 unsigned codeSizeAligned = codeSize;
390 if (moreSections)
391 codeSizeAligned = (codeSizeAligned + 3) & ~3; // to insure EH section aligned
392
393 unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, moreSections);
394 unsigned ehSize = COR_ILMETHOD_SECT_EH::Size(pMethod->m_dwNumExceptions, pMethod->m_ExceptionList);
395 unsigned totalSize = headerSize + codeSizeAligned + ehSize;
396
397 BYTE* outBuff;
398 BYTE* endbuf;
399 BinStr* pbsBody;
400 if((pbsBody = new BinStr())==NULL) return FALSE;
401 if((outBuff = pbsBody->getBuff(totalSize))==NULL) return FALSE;
402 endbuf = &outBuff[totalSize];
403
404 // Emit the header
405 outBuff += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, outBuff);
406
407 pMethod->m_pCode = outBuff;
408 pMethod->m_headerOffset= PEFileOffset;
409 pMethod->m_methodOffset= PEFileOffset + headerSize;
410 pMethod->m_CodeSize = codeSize;
411
412 // Emit the code
413 if (codeSizeAligned)
414 {
415 memset(outBuff,0,codeSizeAligned);
416 memcpy(outBuff, m_pOutputBuffer, codeSize);
417 outBuff += codeSizeAligned;
418 }
419
420 if(pMethod->m_dwNumExceptions)
421 {
422 // Validate the eh
423 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pEx;
424 DWORD TryEnd,HandlerEnd, dwEx, dwEf;
425 for(dwEx = 0, pEx = pMethod->m_ExceptionList; dwEx < pMethod->m_dwNumExceptions; dwEx++, pEx++)
426 {
427 if(pEx->GetTryOffset() > m_CurPC) // i.e., pMethod->m_CodeSize
428 {
429 report->error("Invalid SEH clause #%d: Try block starts beyond code size\n",dwEx+1);
430 }
431 TryEnd = pEx->GetTryOffset()+pEx->GetTryLength();
432 if(TryEnd > m_CurPC)
433 {
434 report->error("Invalid SEH clause #%d: Try block ends beyond code size\n",dwEx+1);
435 }
436 if(pEx->GetHandlerOffset() > m_CurPC)
437 {
438 report->error("Invalid SEH clause #%d: Handler block starts beyond code size\n",dwEx+1);
439 }
440 HandlerEnd = pEx->GetHandlerOffset()+pEx->GetHandlerLength();
441 if(HandlerEnd > m_CurPC)
442 {
443 report->error("Invalid SEH clause #%d: Handler block ends beyond code size\n",dwEx+1);
444 }
445 if(pEx->Flags & COR_ILEXCEPTION_CLAUSE_FILTER)
446 {
447 if(!((pEx->GetFilterOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
448 {
449 report->error("Invalid SEH clause #%d: Try and Filter/Handler blocks overlap\n",dwEx+1);
450 }
451 for(dwEf = 0; dwEf < pMethod->m_dwNumEndfilters; dwEf++)
452 {
453 if(pMethod->m_EndfilterOffsetList[dwEf] == pEx->GetHandlerOffset()) break;
454 }
455 if(dwEf >= pMethod->m_dwNumEndfilters)
456 {
457 report->error("Invalid SEH clause #%d: Filter block separated from Handler, or not ending with endfilter\n",dwEx+1);
458 }
459 }
460 else
461 if(!((pEx->GetHandlerOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
462 {
463 report->error("Invalid SEH clause #%d: Try and Handler blocks overlap\n",dwEx+1);
464 }
465
466 }
467 // Emit the eh
468 outBuff += COR_ILMETHOD_SECT_EH::Emit(ehSize, pMethod->m_dwNumExceptions,
469 pMethod->m_ExceptionList, false, outBuff);
470 }
471 _ASSERTE(outBuff == endbuf);
472
473 pMethod->m_pbsBody = pbsBody;
474
475 LocalMemberRefFixup* pMRF;
476 while((pMRF = pMethod->m_LocalMemberRefFixupList.POP()))
477 {
478 pMRF->offset += (size_t)(pMethod->m_pCode);
479 m_LocalMemberRefFixupList.PUSH(pMRF); // transfer MRF to assembler's list
480 }
481
482 if(m_fReportProgress)
483 {
484 if (pMethod->IsGlobalMethod())
485 report->msg("Assembled global method %s\n", pMethod->m_szName);
486 else report->msg("Assembled method %s::%s\n", pMethod->m_pClass->m_szFQN,
487 pMethod->m_szName);
488 }
489 return TRUE;
490}
491
492
493BOOL Assembler::EmitMethodBody(Method* pMethod, BinStr* pbsOut)
494{
495 if(pMethod)
496 {
497 BinStr* pbsBody = pMethod->m_pbsBody;
498 unsigned totalSize;
499 if(pbsBody && (totalSize = pbsBody->length()))
500 {
501 unsigned headerSize = pMethod->m_methodOffset-pMethod->m_headerOffset;
502 MethodBody* pMB = NULL;
503 // ----------emit locals signature-------------------
504 unsigned uLocals;
505 if((uLocals = pMethod->m_Locals.COUNT()))
506 {
507 VarDescr* pVD;
508 BinStr* pbsSig = new BinStr();
509 unsigned cnt;
510 HRESULT hr;
511 DWORD cSig;
512 const COR_SIGNATURE* mySig;
513
514 pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_LOCAL_SIG);
515 cnt = CorSigCompressData(uLocals,pbsSig->getBuff(5));
516 pbsSig->remove(5-cnt);
517 for(cnt = 0; (pVD = pMethod->m_Locals.PEEK(cnt)); cnt++)
518 {
519 if(pVD->pbsSig) pbsSig->append(pVD->pbsSig);
520 else
521 {
522 report->error("Undefined type of local var slot %d in method %s\n",cnt,pMethod->m_szName);
523 pbsSig->appendInt8(ELEMENT_TYPE_I4);
524 }
525 }
526
527 cSig = pbsSig->length();
528 mySig = (const COR_SIGNATURE *)(pbsSig->ptr());
529
530 if (cSig > 1) // non-empty signature
531 {
532 hr = m_pEmitter->GetTokenFromSig(mySig, cSig, &pMethod->m_LocalsSig);
533 _ASSERTE(SUCCEEDED(hr));
534 }
535 delete pbsSig;
536 COR_ILMETHOD_FAT* pFH; // Fat header guaranteed, because there are local vars
537 pFH = (COR_ILMETHOD_FAT*)(pMethod->m_pbsBody->ptr());
538 pFH->SetLocalVarSigTok(pMethod->m_LocalsSig);
539 }
540 //--------------------------------------------------------------------------------
541 if(m_fGeneratePDB && (m_pSymWriter != NULL))
542 {
543 m_pSymWriter->OpenMethod(pMethod->m_Tok);
544 ULONG N = pMethod->m_LinePCList.COUNT();
545 if(pMethod->m_fEntryPoint) m_pSymWriter->SetUserEntryPoint(pMethod->m_Tok);
546 if(N)
547 {
548 LinePC *pLPC;
549 ULONG32 *offsets=new ULONG32[N], *lines = new ULONG32[N], *columns = new ULONG32[N];
550 ULONG32 *endlines=new ULONG32[N], *endcolumns=new ULONG32[N];
551 if(offsets && lines && columns && endlines && endcolumns)
552 {
553 DocWriter* pDW;
554 unsigned j=0;
555 while((pDW = m_DocWriterList.PEEK(j++)))
556 {
557 if((m_pSymDocument = pDW->pWriter))
558 {
559 int i, n;
560 for(i=0, n=0; (pLPC = pMethod->m_LinePCList.PEEK(i)); i++)
561 {
562 if(pLPC->pWriter == m_pSymDocument)
563 {
564 offsets[n] = pLPC->PC;
565 lines[n] = pLPC->Line;
566 columns[n] = pLPC->Column;
567 endlines[n] = pLPC->LineEnd;
568 endcolumns[n] = pLPC->ColumnEnd;
569 n++;
570 }
571 }
572 if(n) m_pSymWriter->DefineSequencePoints(m_pSymDocument,n,
573 offsets,lines,columns,endlines,endcolumns);
574 } // end if(pSymDocument)
575 } // end while(pDW = next doc.writer)
576 pMethod->m_LinePCList.RESET(true);
577 }
578 else report->error("\nOutOfMemory!\n");
579 delete [] offsets;
580 delete [] lines;
581 delete [] columns;
582 delete [] endlines;
583 delete [] endcolumns;
584 }//enf if(N)
585 HRESULT hrr;
586 if(pMethod->m_ulLines[1])
587 hrr = m_pSymWriter->SetMethodSourceRange(m_pSymDocument,pMethod->m_ulLines[0], pMethod->m_ulColumns[0],
588 m_pSymDocument,pMethod->m_ulLines[1], pMethod->m_ulColumns[1]);
589 EmitScope(&(pMethod->m_MainScope)); // recursively emits all nested scopes
590
591 m_pSymWriter->CloseMethod();
592 } // end if(fIncludeDebugInfo)
593 //-----------------------------------------------------
594
595 if(m_fFoldCode)
596 {
597 for(int k=0; (pMB = m_MethodBodyList.PEEK(k)) != NULL; k++)
598 {
599 if((pMB->pbsBody->length() == totalSize)
600 && (memcmp(pMB->pbsBody->ptr(), pbsBody->ptr(),totalSize)==0))
601 break;
602 }
603 if(pMB)
604 {
605 pMethod->m_headerOffset= pMB->RVA;
606 pMethod->m_methodOffset= pMB->RVA + headerSize;
607 pMethod->m_pCode = pMB->pCode;
608 delete pbsBody;
609 pMethod->m_pbsBody = NULL;
610 m_dwMethodsFolded++;
611 }
612 }
613 if(pMB == NULL)
614 {
615 BYTE* outBuff;
616 unsigned align = (headerSize == 1)? 1 : 4;
617 ULONG PEFileOffset, methodRVA;
618 if(m_fENCMode)
619 {
620 if(pbsOut)
621 {
622 PEFileOffset = pbsOut->length();
623 align--;
624 while(PEFileOffset & align)
625 {
626 pbsOut->appendInt8(0);
627 PEFileOffset++;
628 }
629 pbsOut->append(pbsBody);
630 outBuff = (BYTE*)(pbsOut->ptr()) + (pbsOut->length() - pbsBody->length());
631 }
632 else return FALSE;
633
634 }
635 else
636 {
637 if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize,
638 align, (void **) &outBuff))) return FALSE;
639 memcpy(outBuff,pbsBody->ptr(),totalSize);
640 // The offset where we start, (not where the alignment bytes start!
641 if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset)))
642 return FALSE;
643 PEFileOffset -= totalSize;
644 }
645
646 pMethod->m_pCode = outBuff + headerSize;
647 pMethod->m_headerOffset= PEFileOffset;
648 pMethod->m_methodOffset= PEFileOffset + headerSize;
649 DoDeferredILFixups(pMethod);
650
651 if(m_fENCMode) methodRVA = PEFileOffset;
652 else m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA);
653
654 pMethod->m_headerOffset= methodRVA;
655 pMethod->m_methodOffset= methodRVA + headerSize;
656 if(m_fFoldCode)
657 {
658 if((pMB = new MethodBody)==NULL) return FALSE;
659 pMB->pbsBody = pbsBody;
660 pMB->RVA = methodRVA;
661 pMB->pCode = pMethod->m_pCode;
662 m_MethodBodyList.PUSH(pMB);
663 }
664 //else
665 // delete pbsBody;
666 //pMethod->m_pbsBody = NULL;
667 }
668 m_pEmitter->SetRVA(pMethod->m_Tok,pMethod->m_headerOffset);
669 }
670 return TRUE;
671 }
672 else return FALSE;
673}
674
675ImportDescriptor* Assembler::EmitImport(BinStr* DllName)
676{
677 int i = 0, l = 0;
678 ImportDescriptor* pID;
679 char* sz=NULL;
680
681 if(DllName) l = DllName->length(); // No zero terminator here!
682 if(l)
683 {
684 sz = (char*)DllName->ptr();
685 while((pID=m_ImportList.PEEK(i++)))
686 {
687 if((pID->dwDllName== (DWORD) l)&& !memcmp(pID->szDllName,sz,l)) return pID;
688 }
689 }
690 else
691 {
692 while((pID=m_ImportList.PEEK(i++)))
693 {
694 if(pID->dwDllName==0) return pID;
695 }
696 }
697 if((pID = new ImportDescriptor(sz,l)))
698 {
699 m_ImportList.PUSH(pID);
700 pID->mrDll = TokenFromRid(m_ImportList.COUNT(),mdtModuleRef);
701 return pID;
702 }
703 else report->error("Failed to allocate import descriptor\n");
704 return NULL;
705}
706
707void Assembler::EmitImports()
708{
709 WCHAR* wzDllName=&wzUniBuf[0];
710 ImportDescriptor* pID;
711 int i;
712 mdToken tk;
713 for(i=0; (pID = m_ImportList.PEEK(i)); i++)
714 {
715 WszMultiByteToWideChar(g_uCodePage,0,pID->szDllName,-1,wzDllName,dwUniBuf-1);
716 if(FAILED(m_pEmitter->DefineModuleRef( // S_OK or error.
717 wzDllName, // [IN] DLL name
718 &tk))) // [OUT] returned
719 report->error("Failed to define module ref '%s'\n",pID->szDllName);
720 else
721 _ASSERTE(tk == pID->mrDll);
722 }
723}
724
725HRESULT Assembler::EmitPinvokeMap(mdToken tk, PInvokeDescriptor* pDescr)
726{
727 WCHAR* wzAlias=&wzUniBuf[0];
728
729 if(pDescr->szAlias) WszMultiByteToWideChar(g_uCodePage,0,pDescr->szAlias,-1,wzAlias,dwUniBuf-1);
730
731 return m_pEmitter->DefinePinvokeMap( // Return code.
732 tk, // [IN] FieldDef, MethodDef or MethodImpl.
733 pDescr->dwAttrs, // [IN] Flags used for mapping.
734 (LPCWSTR)wzAlias, // [IN] Import name.
735 pDescr->mrDll); // [IN] ModuleRef token for the target DLL.
736}
737
738void Assembler::EmitScope(Scope* pSCroot)
739{
740 static ULONG32 scopeID;
741 static ARG_NAME_LIST *pVarList;
742 int i;
743 WCHAR* wzVarName=&wzUniBuf[0];
744 char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
745 Scope* pSC = pSCroot;
746 if(pSC && m_pSymWriter)
747 {
748 if(SUCCEEDED(m_pSymWriter->OpenScope(pSC->dwStart,&scopeID)))
749 {
750 if(pSC->pLocals)
751 {
752 for(pVarList = pSC->pLocals; pVarList; pVarList = pVarList->pNext)
753 {
754 if(pVarList->pSig)
755 {
756 if((pVarList->szName)&&(*(pVarList->szName))) strcpy_s(szPhonyName,dwUniBuf >> 1,pVarList->szName);
757 else sprintf_s(szPhonyName,(dwUniBuf >> 1),"V_%d",pVarList->dwAttr);
758
759 WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzVarName,dwUniBuf >> 1);
760
761 m_pSymWriter->DefineLocalVariable(wzVarName,0,pVarList->pSig->length(),
762 (BYTE*)pVarList->pSig->ptr(),ADDR_IL_OFFSET,pVarList->dwAttr,0,0,0,0);
763 }
764 else
765 {
766 report->error("Local Var '%s' has no signature\n",pVarList->szName);
767 }
768 }
769 }
770 for(i = 0; (pSC = pSCroot->SubScope.PEEK(i)); i++) EmitScope(pSC);
771 m_pSymWriter->CloseScope(pSCroot->dwEnd);
772 }
773 }
774}
775
776BOOL Assembler::EmitMethod(Method *pMethod)
777{
778// Emit the metadata for a method definition
779 BOOL fSuccess = FALSE;
780 WCHAR* wzMemberName=&wzUniBuf[0];
781 BOOL fIsInterface;
782 DWORD cSig;
783 ULONG methodRVA = 0;
784 mdMethodDef MethodToken;
785 mdTypeDef ClassToken = mdTypeDefNil;
786 char *pszMethodName;
787 COR_SIGNATURE *mySig;
788
789 _ASSERTE((m_pCeeFileGen != NULL) && (pMethod != NULL));
790 fIsInterface = ((pMethod->m_pClass != NULL) && IsTdInterface(pMethod->m_pClass->m_Attr));
791
792
793 pszMethodName = pMethod->m_szName;
794 mySig = pMethod->m_pMethodSig;
795 cSig = pMethod->m_dwMethodCSig;
796
797 // If this is an instance method, make certain the signature says so
798
799 if (!(pMethod->m_Attr & mdStatic))
800 *mySig |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
801
802 ClassToken = (pMethod->IsGlobalMethod())? mdTokenNil
803 : pMethod->m_pClass->m_cl;
804 // Convert name to UNICODE
805 WszMultiByteToWideChar(g_uCodePage,0,pszMethodName,-1,wzMemberName,dwUniBuf-1);
806
807 if(IsMdPrivateScope(pMethod->m_Attr))
808 {
809 WCHAR* p = wcsstr(wzMemberName,W("$PST06"));
810 if(p) *p = 0;
811 }
812
813 if (FAILED(m_pEmitter->DefineMethod(ClassToken, // parent class
814 wzMemberName, // member name
815 pMethod->m_Attr & ~mdReservedMask, // member attributes
816 mySig, // member signature
817 cSig,
818 methodRVA, // RVA
819 pMethod->m_wImplAttr, // implflags
820 &MethodToken)))
821 {
822 report->error("Failed to define method '%s'\n",pszMethodName);
823 goto exit;
824 }
825 pMethod->m_Tok = MethodToken;
826 //--------------------------------------------------------------------------------
827 // the only way to set mdRequireSecObject:
828 if(pMethod->m_Attr & mdRequireSecObject)
829 {
830 mdToken tkPseudoClass;
831 if(FAILED(m_pEmitter->DefineTypeRefByName(1, COR_REQUIRES_SECOBJ_ATTRIBUTE, &tkPseudoClass)))
832 report->error("Unable to define type reference '%s'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
833 else
834 {
835 mdToken tkPseudoCtor;
836 BYTE bSig[3] = {IMAGE_CEE_CS_CALLCONV_HASTHIS,0,ELEMENT_TYPE_VOID};
837 if(FAILED(m_pEmitter->DefineMemberRef(tkPseudoClass, W(".ctor"), (PCCOR_SIGNATURE)bSig, 3, &tkPseudoCtor)))
838 report->error("Unable to define member reference '%s::.ctor'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
839 else DefineCV(new CustomDescr(MethodToken,tkPseudoCtor,NULL));
840 }
841 }
842
843 if (pMethod->m_NumTyPars)
844 {
845 ULONG i;
846 mdToken* ptk;
847 mdToken tk;
848 for(i = 0; i < pMethod->m_NumTyPars; i++)
849 {
850 //ptk = (pMethod->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pMethod->m_TyParBounds[i]->ptr());
851 //if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,0,pMethod->m_TyParNames[i],0,ptk,&tk)))
852 ptk = (pMethod->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pMethod->m_TyPars[i].Bounds()->ptr());
853 if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,pMethod->m_TyPars[i].Attrs(),pMethod->m_TyPars[i].Name(),0,ptk,&tk)))
854 report->error("Unable to define generic param'\n");
855 else
856 EmitCustomAttributes(tk, pMethod->m_TyPars[i].CAList());
857 }
858 }
859 //--------------------------------------------------------------------------------
860 EmitSecurityInfo(MethodToken,
861 pMethod->m_pPermissions,
862 pMethod->m_pPermissionSets);
863 //--------------------------------------------------------------------------------
864 if (pMethod->m_fEntryPoint)
865 {
866 if(fIsInterface) report->error("Entrypoint in Interface: Method '%s'\n",pszMethodName);
867
868 if (FAILED(m_pCeeFileGen->SetEntryPoint(m_pCeeFile, MethodToken)))
869 {
870 report->error("Failed to set entry point for method '%s'\n",pszMethodName);
871 goto exit;
872 }
873
874 }
875 //--------------------------------------------------------------------------------
876 if(IsMdPinvokeImpl(pMethod->m_Attr))
877 {
878 if(pMethod->m_pPInvoke)
879 {
880 HRESULT hr;
881 if(pMethod->m_pPInvoke->szAlias == NULL) pMethod->m_pPInvoke->szAlias = pszMethodName;
882 hr = EmitPinvokeMap(MethodToken,pMethod->m_pPInvoke);
883 if(pMethod->m_pPInvoke->szAlias == pszMethodName) pMethod->m_pPInvoke->szAlias = NULL;
884
885 if(FAILED(hr))
886 {
887 report->error("Failed to set PInvoke map for method '%s'\n",pszMethodName);
888 goto exit;
889 }
890 }
891 }
892
893 { // add parameters to metadata
894 void const *pValue=NULL;
895 ULONG cbValue;
896 DWORD dwCPlusTypeFlag=0;
897 mdParamDef pdef;
898 WCHAR* wzParName=&wzUniBuf[0];
899 char* szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
900 if(pMethod->m_dwRetAttr || pMethod->m_pRetMarshal || pMethod->m_RetCustDList.COUNT())
901 {
902 if(pMethod->m_pRetValue)
903 {
904 dwCPlusTypeFlag= (DWORD)*(pMethod->m_pRetValue->ptr());
905 pValue = (void const *)(pMethod->m_pRetValue->ptr()+1);
906 cbValue = pMethod->m_pRetValue->length()-1;
907 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
908 }
909 else
910 {
911 pValue = NULL;
912 cbValue = (ULONG)-1;
913 dwCPlusTypeFlag=0;
914 }
915 m_pEmitter->DefineParam(MethodToken,0,NULL,pMethod->m_dwRetAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
916
917 if(pMethod->m_pRetMarshal)
918 {
919 if(FAILED(m_pEmitter->SetFieldMarshal (
920 pdef, // [IN] given a fieldDef or paramDef token
921 (PCCOR_SIGNATURE)(pMethod->m_pRetMarshal->ptr()), // [IN] native type specification
922 pMethod->m_pRetMarshal->length()))) // [IN] count of bytes of pvNativeType
923 report->error("Failed to set param marshaling for return\n");
924
925 }
926 EmitCustomAttributes(pdef, &(pMethod->m_RetCustDList));
927 }
928 for(ARG_NAME_LIST *pAN=pMethod->m_firstArgName; pAN; pAN = pAN->pNext)
929 {
930 if(pAN->nNum >= 65535)
931 {
932 report->error("Method '%s': Param.sequence number (%d) exceeds 65535, unable to define parameter\n",pszMethodName,pAN->nNum+1);
933 continue;
934 }
935 if(pAN->dwName) strcpy_s(szPhonyName,dwUniBuf >> 1,pAN->szName);
936 else sprintf_s(szPhonyName,(dwUniBuf >> 1),"A_%d",pAN->nNum);
937
938 WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzParName,dwUniBuf >> 1);
939
940 if(pAN->pValue)
941 {
942 dwCPlusTypeFlag= (DWORD)*(pAN->pValue->ptr());
943 pValue = (void const *)(pAN->pValue->ptr()+1);
944 cbValue = pAN->pValue->length()-1;
945 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
946 }
947 else
948 {
949 pValue = NULL;
950 cbValue = (ULONG)-1;
951 dwCPlusTypeFlag=0;
952 }
953 m_pEmitter->DefineParam(MethodToken,pAN->nNum+1,wzParName,pAN->dwAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
954 if(pAN->pMarshal)
955 {
956 if(FAILED(m_pEmitter->SetFieldMarshal (
957 pdef, // [IN] given a fieldDef or paramDef token
958 (PCCOR_SIGNATURE)(pAN->pMarshal->ptr()), // [IN] native type specification
959 pAN->pMarshal->length()))) // [IN] count of bytes of pvNativeType
960 report->error("Failed to set param marshaling for '%s'\n",pAN->szName);
961 }
962 EmitCustomAttributes(pdef, &(pAN->CustDList));
963 }
964 }
965 fSuccess = TRUE;
966 //--------------------------------------------------------------------------------
967 // Update method implementations for this method
968 {
969 MethodImplDescriptor* pMID;
970 int i;
971 for(i=0;(pMID = pMethod->m_MethodImplDList.PEEK(i));i++)
972 {
973 pMID->m_tkImplementingMethod = MethodToken;
974 // don't delete it here, it's still in the general list
975 }
976 }
977 //--------------------------------------------------------------------------------
978 EmitCustomAttributes(MethodToken, &(pMethod->m_CustomDescrList));
979exit:
980 if (fSuccess == FALSE) m_State = STATE_FAIL;
981 return fSuccess;
982}
983
984BOOL Assembler::EmitMethodImpls()
985{
986 MethodImplDescriptor* pMID;
987 BOOL ret = TRUE;
988 int i;
989 for(i=0; (pMID = m_MethodImplDList.PEEK(i)); i++)
990 {
991 if(m_fENCMode && (!pMID->m_fNew)) continue;
992 pMID->m_tkImplementingMethod = ResolveLocalMemberRef(pMID->m_tkImplementingMethod);
993 pMID->m_tkImplementedMethod = ResolveLocalMemberRef(pMID->m_tkImplementedMethod);
994 if(FAILED(m_pEmitter->DefineMethodImpl( pMID->m_tkDefiningClass,
995 pMID->m_tkImplementingMethod,
996 pMID->m_tkImplementedMethod)))
997 {
998 report->error("Failed to define Method Implementation");
999 ret = FALSE;
1000 }
1001 pMID->m_fNew = FALSE;
1002 }// end while
1003 return ret;
1004}
1005
1006mdToken Assembler::ResolveLocalMemberRef(mdToken tok)
1007{
1008 if(TypeFromToken(tok) == 0x99000000)
1009 {
1010 tok = RidFromToken(tok);
1011 if(tok) tok = m_LocalMethodRefDList.PEEK(tok-1)->m_tkResolved;
1012 }
1013 else if(TypeFromToken(tok) == 0x98000000)
1014 {
1015 tok = RidFromToken(tok);
1016 if(tok) tok = m_LocalFieldRefDList.PEEK(tok-1)->m_tkResolved;
1017 }
1018 return tok;
1019}
1020
1021BOOL Assembler::EmitEvent(EventDescriptor* pED)
1022{
1023 mdMethodDef mdAddOn=mdMethodDefNil,
1024 mdRemoveOn=mdMethodDefNil,
1025 mdFire=mdMethodDefNil,
1026 *mdOthers;
1027 int nOthers;
1028 WCHAR* wzMemberName=&wzUniBuf[0];
1029
1030 if(!pED) return FALSE;
1031
1032 WszMultiByteToWideChar(g_uCodePage,0,pED->m_szName,-1,wzMemberName,dwUniBuf-1);
1033
1034 mdAddOn = ResolveLocalMemberRef(pED->m_tkAddOn);
1035 if(TypeFromToken(mdAddOn) != mdtMethodDef)
1036 {
1037 report->error("Invalid Add method of event '%s'\n",pED->m_szName);
1038 return FALSE;
1039 }
1040 mdRemoveOn = ResolveLocalMemberRef(pED->m_tkRemoveOn);
1041 if(TypeFromToken(mdRemoveOn) != mdtMethodDef)
1042 {
1043 report->error("Invalid Remove method of event '%s'\n",pED->m_szName);
1044 return FALSE;
1045 }
1046 mdFire = ResolveLocalMemberRef(pED->m_tkFire);
1047 if((RidFromToken(mdFire)!=0)&&(TypeFromToken(mdFire) != mdtMethodDef))
1048 {
1049 report->error("Invalid Fire method of event '%s'\n",pED->m_szName);
1050 return FALSE;
1051 }
1052
1053 nOthers = pED->m_tklOthers.COUNT();
1054 mdOthers = new mdMethodDef[nOthers+1];
1055 if(mdOthers == NULL)
1056 {
1057 report->error("Failed to allocate Others array for event descriptor\n");
1058 nOthers = 0;
1059 }
1060 for(int j=0; j < nOthers; j++)
1061 {
1062 mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pED->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken'
1063 }
1064 mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1065
1066 if(FAILED(m_pEmitter->DefineEvent( pED->m_tdClass,
1067 wzMemberName,
1068 pED->m_dwAttr,
1069 pED->m_tkEventType,
1070 mdAddOn,
1071 mdRemoveOn,
1072 mdFire,
1073 mdOthers,
1074 &(pED->m_edEventTok))))
1075 {
1076 report->error("Failed to define event '%s'.\n",pED->m_szName);
1077 delete [] mdOthers;
1078 return FALSE;
1079 }
1080 EmitCustomAttributes(pED->m_edEventTok, &(pED->m_CustomDescrList));
1081 return TRUE;
1082}
1083
1084BOOL Assembler::EmitProp(PropDescriptor* pPD)
1085{
1086 mdMethodDef mdSet, mdGet, *mdOthers;
1087 int nOthers;
1088 WCHAR* wzMemberName=&wzUniBuf[0];
1089
1090 if(!pPD) return FALSE;
1091
1092 WszMultiByteToWideChar(g_uCodePage,0,pPD->m_szName,-1,wzMemberName,dwUniBuf-1);
1093
1094 mdSet = ResolveLocalMemberRef(pPD->m_tkSet);
1095 if((RidFromToken(mdSet)!=0)&&(TypeFromToken(mdSet) != mdtMethodDef))
1096 {
1097 report->error("Invalid Set method of property '%s'\n",pPD->m_szName);
1098 return FALSE;
1099 }
1100 mdGet = ResolveLocalMemberRef(pPD->m_tkGet);
1101 if((RidFromToken(mdGet)!=0)&&(TypeFromToken(mdGet) != mdtMethodDef))
1102 {
1103 report->error("Invalid Get method of property '%s'\n",pPD->m_szName);
1104 return FALSE;
1105 }
1106
1107 nOthers = pPD->m_tklOthers.COUNT();
1108 mdOthers = new mdMethodDef[nOthers+1];
1109 if(mdOthers == NULL)
1110 {
1111 report->error("Failed to allocate Others array for prop descriptor\n");
1112 nOthers = 0;
1113 }
1114 for(int j=0; j < nOthers; j++)
1115 {
1116 mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pPD->m_tklOthers.PEEK(j))); // @WARNING: casting down from 'mdToken*' to 'mdToken'
1117
1118 if((RidFromToken(mdOthers[j])!=0)&&(TypeFromToken(mdOthers[j]) != mdtMethodDef))
1119 {
1120 report->error("Invalid Other method of property '%s'\n",pPD->m_szName);
1121 delete [] mdOthers;
1122 return FALSE;
1123 }
1124
1125 }
1126 mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1127
1128 if(FAILED(m_pEmitter->DefineProperty( pPD->m_tdClass,
1129 wzMemberName,
1130 pPD->m_dwAttr,
1131 pPD->m_pSig,
1132 pPD->m_dwCSig,
1133 pPD->m_dwCPlusTypeFlag,
1134 pPD->m_pValue,
1135 pPD->m_cbValue,
1136 mdSet,
1137 mdGet,
1138 mdOthers,
1139 &(pPD->m_pdPropTok))))
1140 {
1141 report->error("Failed to define property '%s'.\n",pPD->m_szName);
1142 delete [] mdOthers;
1143 return FALSE;
1144 }
1145 EmitCustomAttributes(pPD->m_pdPropTok, &(pPD->m_CustomDescrList));
1146 return TRUE;
1147}
1148
1149Class *Assembler::FindCreateClass(__in __nullterminated const char *pszFQN)
1150{
1151 Class *pSearch = NULL;
1152
1153 if(pszFQN)
1154 {
1155 dummyClass->m_szFQN = pszFQN;
1156 dummyClass->m_Hash = hash((BYTE*)pszFQN, (unsigned)strlen(pszFQN), 10);
1157 pSearch = m_hshClass.FIND(dummyClass);
1158 dummyClass->m_szFQN = NULL;
1159 dummyClass->m_Hash = 0;
1160
1161 if(!pSearch)
1162 {
1163 char* pch;
1164 DWORD dwFQN = (DWORD)strlen(pszFQN);
1165
1166 Class *pEncloser = NULL;
1167 char* pszNewFQN = new char[dwFQN+1];
1168 strcpy_s(pszNewFQN,dwFQN+1,pszFQN);
1169 if((pch = strrchr(pszNewFQN, NESTING_SEP)) != NULL)
1170 {
1171 *pch = 0;
1172 pEncloser = FindCreateClass(pszNewFQN);
1173 *pch = NESTING_SEP;
1174 }
1175 pSearch = new Class(pszNewFQN);
1176 if (pSearch == NULL)
1177 report->error("Failed to create class '%s'\n",pszNewFQN);
1178 else
1179 {
1180 pSearch->m_pEncloser = pEncloser;
1181 m_lstClass.PUSH(pSearch);
1182 pSearch->m_cl = mdtTypeDef | m_lstClass.COUNT();
1183 m_hshClass.PUSH(pSearch);
1184 }
1185 }
1186 }
1187
1188 return pSearch;
1189}
1190
1191
1192BOOL Assembler::EmitClass(Class *pClass)
1193{
1194 LPCUTF8 szFullName;
1195 WCHAR* wzFullName=&wzUniBuf[0];
1196 HRESULT hr = E_FAIL;
1197 GUID guid;
1198 size_t L;
1199 mdToken tok;
1200
1201 if(pClass == NULL) return FALSE;
1202
1203 hr = CoCreateGuid(&guid);
1204 if (FAILED(hr))
1205 {
1206 printf("Unable to create GUID\n");
1207 m_State = STATE_FAIL;
1208 return FALSE;
1209 }
1210
1211 if(pClass->m_pEncloser)
1212 szFullName = strrchr(pClass->m_szFQN,NESTING_SEP) + 1;
1213 else
1214 szFullName = pClass->m_szFQN;
1215
1216 WszMultiByteToWideChar(g_uCodePage,0,szFullName,-1,wzFullName,dwUniBuf);
1217
1218 L = wcslen(wzFullName);
1219 if((L==0)||(wzFullName[L-1]==L'.')) // Missing class name!
1220 {
1221 wcscat_s(wzFullName,dwUniBuf,W("$UNNAMED_TYPE$"));
1222 }
1223
1224 pClass->m_Attr = CheckClassFlagsIfNested(pClass->m_pEncloser, pClass->m_Attr);
1225
1226 if (pClass->m_pEncloser)
1227 {
1228 hr = m_pEmitter->DefineNestedType( wzFullName,
1229 pClass->m_Attr, // attributes
1230 pClass->m_crExtends, // CR extends class
1231 pClass->m_crImplements,// implements
1232 pClass->m_pEncloser->m_cl, // Enclosing class.
1233 &tok);
1234 }
1235 else
1236 {
1237 hr = m_pEmitter->DefineTypeDef( wzFullName,
1238 pClass->m_Attr, // attributes
1239 pClass->m_crExtends, // CR extends class
1240 pClass->m_crImplements,// implements
1241 &tok);
1242 }
1243 _ASSERTE(tok == pClass->m_cl);
1244 if (FAILED(hr)) goto exit;
1245 if (pClass->m_NumTyPars)
1246 {
1247 ULONG i;
1248 mdToken* ptk;
1249 mdToken tk;
1250 for(i = 0; i < pClass->m_NumTyPars; i++)
1251 {
1252 //ptk = (pClass->m_TyParBounds[i] == NULL)? NULL : (mdToken*)(pClass->m_TyParBounds[i]->ptr());
1253 //if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyParAttrs[i],pClass->m_TyParNames[i],0,ptk,&tk)))
1254 ptk = (pClass->m_TyPars[i].Bounds() == NULL)? NULL : (mdToken*)(pClass->m_TyPars[i].Bounds()->ptr());
1255 if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyPars[i].Attrs(),pClass->m_TyPars[i].Name(),0,ptk,&tk)))
1256 report->error("Unable to define generic param'\n");
1257 else
1258 EmitCustomAttributes(tk, pClass->m_TyPars[i].CAList());
1259 }
1260 }
1261
1262
1263 EmitCustomAttributes(pClass->m_cl, &(pClass->m_CustDList));
1264 hr = S_OK;
1265
1266exit:
1267 return SUCCEEDED(hr);
1268}
1269
1270BOOL Assembler::DoGlobalFixups()
1271{
1272 GlobalFixup *pSearch;
1273
1274 for (int i=0; (pSearch = m_lstGlobalFixup.PEEK(i)); i++)
1275 {
1276 GlobalLabel * pLabel = FindGlobalLabel(pSearch->m_szLabel);
1277 if (pLabel == NULL)
1278 {
1279 report->error("Unable to find forward reference global label '%s'\n",
1280 pSearch->m_szLabel);
1281
1282 m_State = STATE_FAIL;
1283 return FALSE;
1284 }
1285 //BYTE * pReference = pSearch->m_pReference;
1286 //DWORD GlobalOffset = pLabel->m_GlobalOffset;
1287 //memcpy(pReference,&GlobalOffset,4);
1288 SET_UNALIGNED_VAL32(pSearch->m_pReference,pLabel->m_GlobalOffset);
1289 }
1290
1291 return TRUE;
1292}
1293
1294state_t Assembler::AddGlobalLabel(__in __nullterminated char *pszName, HCEESECTION section)
1295{
1296 if (FindGlobalLabel(pszName) != NULL)
1297 {
1298 report->error("Duplicate global label '%s'\n", pszName);
1299 m_State = STATE_FAIL;
1300 return m_State;
1301 }
1302
1303 ULONG GlobalOffset;
1304
1305 HRESULT hr;
1306 hr = m_pCeeFileGen->GetSectionDataLen(section, &GlobalOffset);
1307 _ASSERTE(SUCCEEDED(hr));
1308
1309 GlobalLabel *pNew = new GlobalLabel(pszName, GlobalOffset, section);
1310 if (pNew == 0)
1311 {
1312 report->error("Failed to allocate global label '%s'\n",pszName);
1313 m_State = STATE_FAIL;
1314 return m_State;
1315 }
1316
1317 m_lstGlobalLabel.PUSH(pNew);
1318 return m_State;
1319}
1320
1321void Assembler::AddLabel(DWORD CurPC, __in __nullterminated char *pszName)
1322{
1323 if (m_pCurMethod->FindLabel(pszName) != NULL)
1324 {
1325 report->error("Duplicate label: '%s'\n", pszName);
1326
1327 m_State = STATE_FAIL;
1328 }
1329 else
1330 {
1331 Label *pNew = new Label(pszName, CurPC);
1332
1333 if (pNew != NULL)
1334 //m_pCurMethod->m_lstLabel.PUSH(pNew);
1335 m_lstLabel.PUSH(pNew);
1336 else
1337 {
1338 report->error("Failed to allocate label '%s'\n",pszName);
1339 m_State = STATE_FAIL;
1340 }
1341 }
1342}
1343
1344void Assembler::DoDeferredILFixups(Method* pMethod)
1345{ // Now that we know where in the file the code bytes will wind up,
1346 // we can update the RVAs and offsets.
1347 ILFixup *pSearch;
1348 HRESULT hr;
1349 GlobalFixup *Fix = NULL;
1350 int i;
1351 for (i=0;(pSearch = pMethod->m_lstILFixup.PEEK(i));i++)
1352 {
1353 switch(pSearch->m_Kind)
1354 {
1355 case ilGlobal:
1356 Fix = pSearch->m_Fixup;
1357 _ASSERTE(Fix != NULL);
1358 Fix->m_pReference = pMethod->m_pCode+pSearch->m_OffsetInMethod;
1359 break;
1360
1361 case ilToken:
1362 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1363 pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1364 m_pILSection,
1365 srRelocMapToken);
1366 _ASSERTE(SUCCEEDED(hr));
1367 break;
1368
1369 case ilRVA:
1370 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1371 pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1372 m_pGlobalDataSection,
1373 srRelocAbsolute);
1374 _ASSERTE(SUCCEEDED(hr));
1375 break;
1376
1377 default:
1378 ;
1379 }
1380 }
1381}
1382/**************************************************************************/
1383BOOL Assembler::DoFixups(Method* pMethod)
1384{
1385 Fixup *pSearch;
1386
1387 for (int i=0; (pSearch = pMethod->m_lstFixup.PEEK(i)); i++)
1388 {
1389 Label * pLabel = pMethod->FindLabel(pSearch->m_szLabel);
1390 long offset;
1391
1392 if (pLabel == NULL)
1393 {
1394 report->error("Unable to find forward reference label '%s' called from PC=%d\n",
1395 pSearch->m_szLabel, pSearch->m_RelativeToPC);
1396
1397 //m_State = STATE_FAIL;
1398 return FALSE;
1399 }
1400
1401 offset = pLabel->m_PC - pSearch->m_RelativeToPC;
1402
1403 if (pSearch->m_FixupSize == 1)
1404 {
1405 if (offset > 127 || offset < -128)
1406 {
1407 report->error("Offset of forward reference label '%s' called from PC=%d is too large for 1 byte pcrel\n",
1408 pLabel->m_szName, pSearch->m_RelativeToPC);
1409
1410 //m_State = STATE_FAIL;
1411 return FALSE;
1412 }
1413
1414 *pSearch->m_pBytes = (BYTE) offset;
1415 }
1416 else if (pSearch->m_FixupSize == 4)
1417 {
1418 SET_UNALIGNED_VAL32(pSearch->m_pBytes,offset);
1419 }
1420 }
1421
1422 return TRUE;
1423}
1424
1425
1426OPCODE Assembler::DecodeOpcode(const BYTE *pCode, DWORD *pdwLen)
1427{
1428 OPCODE opcode;
1429
1430 *pdwLen = 1;
1431 opcode = OPCODE(pCode[0]);
1432 switch(opcode) {
1433 case CEE_PREFIX1:
1434 opcode = OPCODE(pCode[1] + 256);
1435 if (opcode < 0 || opcode >= CEE_COUNT)
1436 return CEE_COUNT;
1437 *pdwLen = 2;
1438 break;
1439
1440 case CEE_PREFIXREF:
1441 case CEE_PREFIX2:
1442 case CEE_PREFIX3:
1443 case CEE_PREFIX4:
1444 case CEE_PREFIX5:
1445 case CEE_PREFIX6:
1446 case CEE_PREFIX7:
1447 return CEE_COUNT;
1448 default:
1449 break;
1450 }
1451 return opcode;
1452}
1453
1454char* Assembler::ReflectionNotation(mdToken tk)
1455{
1456 char *sz = (char*)&wzUniBuf[dwUniBuf>>1], *pc;
1457 *sz=0;
1458 switch(TypeFromToken(tk))
1459 {
1460 case mdtTypeDef:
1461 {
1462 Class *pClass = m_lstClass.PEEK(RidFromToken(tk)-1);
1463 if(pClass)
1464 {
1465 strcpy_s(sz,dwUniBuf>>1,pClass->m_szFQN);
1466 pc = sz;
1467 while((pc = strchr(pc,NESTING_SEP)) != NULL)
1468 {
1469 *pc = '+';
1470 pc++;
1471 }
1472 }
1473 }
1474 break;
1475
1476 case mdtTypeRef:
1477 {
1478 ULONG N;
1479 mdToken tkResScope;
1480 if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,dwUniBuf>>1,&N)))
1481 {
1482 WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,dwUniBuf>>1,NULL,NULL);
1483 if(TypeFromToken(tkResScope)==mdtAssemblyRef)
1484 {
1485 AsmManAssembly *pAsmRef = m_pManifest->m_AsmRefLst.PEEK(RidFromToken(tkResScope)-1);
1486 if(pAsmRef)
1487 {
1488 pc = &sz[strlen(sz)];
1489 pc+=sprintf_s(pc,(dwUniBuf >> 1),", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName,
1490 pAsmRef->usVerMajor,pAsmRef->usVerMinor,pAsmRef->usBuild,pAsmRef->usRevision);
1491 ULONG L=0;
1492 if(pAsmRef->pLocale && (L=pAsmRef->pLocale->length()))
1493 {
1494 memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L);
1495 wzUniBuf[L>>1] = 0;
1496 WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,dwUniBuf>>1,NULL,NULL);
1497 }
1498 else pc+=sprintf_s(pc,(dwUniBuf >> 1),"neutral");
1499 pc = &sz[strlen(sz)];
1500 if(pAsmRef->pPublicKeyToken && (L=pAsmRef->pPublicKeyToken->length()))
1501 {
1502 pc+=sprintf_s(pc,(dwUniBuf >> 1),", Publickeytoken=");
1503 BYTE* pb = (BYTE*)(pAsmRef->pPublicKeyToken->ptr());
1504 for(N=0; N<L; N++,pb++) pc+=sprintf_s(pc,(dwUniBuf >> 1),"%2.2x",*pb);
1505 }
1506 }
1507 }
1508 }
1509 }
1510 break;
1511
1512 default:
1513 break;
1514 }
1515 return sz;
1516}
1517
1518/*
1519--------------------------------------------------------------------
1520mix -- mix 3 32-bit values reversibly.
1521For every delta with one or two bits set, and the deltas of all three
1522 high bits or all three low bits, whether the original value of a,b,c
1523 is almost all zero or is uniformly distributed,
1524* If mix() is run forward or backward, at least 32 bits in a,b,c
1525 have at least 1/4 probability of changing.
1526* If mix() is run forward, every bit of c will change between 1/3 and
1527 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
1528mix() was built out of 36 single-cycle latency instructions in a
1529 structure that could supported 2x parallelism, like so:
1530 a -= b;
1531 a -= c; x = (c>>13);
1532 b -= c; a ^= x;
1533 b -= a; x = (a<<8);
1534 c -= a; b ^= x;
1535 c -= b; x = (b>>13);
1536 ...
1537 Unfortunately, superscalar Pentiums and Sparcs can't take advantage
1538 of that parallelism. They've also turned some of those single-cycle
1539 latency instructions into multi-cycle latency instructions. Still,
1540 this is the fastest good hash I could find. There were about 2^^68
1541 to choose from. I only looked at a billion or so.
1542--------------------------------------------------------------------
1543*/
1544#define mix(a,b,c) \
1545{ \
1546 a -= b; a -= c; a ^= (c >> 13); \
1547 b -= c; b -= a; b ^= (a << 8); \
1548 c -= a; c -= b; c ^= (b >> 13); \
1549 a -= b; a -= c; a ^= (c >> 12); \
1550 b -= c; b -= a; b ^= (a << 16); \
1551 c -= a; c -= b; c ^= (b >> 5); \
1552 a -= b; a -= c; a ^= (c >> 3); \
1553 b -= c; b -= a; b ^= (a << 10); \
1554 c -= a; c -= b; c ^= (b >> 15); \
1555}
1556
1557/*
1558--------------------------------------------------------------------
1559hash() -- hash a variable-length key into a 32-bit value
1560 k : the key (the unaligned variable-length array of bytes)
1561 len : the length of the key, counting by bytes
1562 initval : can be any 4-byte value
1563Returns a 32-bit value. Every bit of the key affects every bit of
1564the return value. Every 1-bit and 2-bit delta achieves avalanche.
1565About 6*len+35 instructions.
1566
1567The best hash table sizes are powers of 2. There is no need to do
1568mod a prime (mod is sooo slow!). If you need less than 32 bits,
1569use a bitmask. For example, if you need only 10 bits, do
1570 h = (h & hashmask(10));
1571In which case, the hash table should have hashsize(10) elements.
1572
1573If you are hashing n strings (ub1 **)k, do it like this:
1574 for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
1575
1576By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
1577code any way you wish, private, educational, or commercial. It's free.
1578
1579See http://burtleburtle.net/bob/hash/evahash.html
1580Use for hash table lookup, or anything where one collision in 2^^32 is
1581acceptable. Do NOT use for cryptographic purposes.
1582--------------------------------------------------------------------
1583*/
1584
1585unsigned hash(
1586 __in_ecount(length) const BYTE *k, /* the key */
1587 unsigned length, /* the length of the key */
1588 unsigned initval) /* the previous hash, or an arbitrary value */
1589{
1590 register unsigned a,b,c,len;
1591
1592 /* Set up the internal state */
1593 len = length;
1594 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
1595 c = initval; /* the previous hash value */
1596
1597 /*---------------------------------------- handle most of the key */
1598 while (len >= 12)
1599 {
1600 a += (k[0] + ((unsigned)k[1] << 8) + ((unsigned)k[2] << 16) + ((unsigned)k[3] << 24));
1601 b += (k[4] + ((unsigned)k[5] << 8) + ((unsigned)k[6] << 16) + ((unsigned)k[7] << 24));
1602 c += (k[8] + ((unsigned)k[9] << 8) + ((unsigned)k[10] << 16) + ((unsigned)k[11] << 24));
1603 mix(a,b,c);
1604 k += 12; len -= 12;
1605 }
1606
1607 /*------------------------------------- handle the last 11 bytes */
1608 c += length;
1609 switch(len) /* all the case statements fall through */
1610 {
1611 case 11: c+=((unsigned)k[10] << 24);
1612 case 10: c+=((unsigned)k[9] << 16);
1613 case 9 : c+=((unsigned)k[8] << 8);
1614 /* the first byte of c is reserved for the length */
1615 case 8 : b+=((unsigned)k[7] << 24);
1616 case 7 : b+=((unsigned)k[6] << 16);
1617 case 6 : b+=((unsigned)k[5] << 8);
1618 case 5 : b+=k[4];
1619 case 4 : a+=((unsigned)k[3] << 24);
1620 case 3 : a+=((unsigned)k[2] << 16);
1621 case 2 : a+=((unsigned)k[1] << 8);
1622 case 1 : a+=k[0];
1623 /* case 0: nothing left to add */
1624 }
1625 mix(a,b,c);
1626 /*-------------------------------------------- report the result */
1627 return c;
1628}
1629
1630