2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "assembler.h"
13 #include "ceefilegenwriter.h"
14 #include "strongname.h"
15 #include "LegacyActivationShim.h"
18 //cloned definition from ntimage.h that is removed for non MSVC builds
20 (NTAPI *PIMAGE_TLS_CALLBACK) (
28 HRESULT Assembler::InitMetaData()
32 if(m_fInitialisedMetaData) return S_OK;
34 if(bClock) bClock->cMDInitBegin = GetTickCount();
36 hr = LegacyActivationShim::ClrCoCreateInstance(
37 CLSID_CorMetaDataDispenser,
40 IID_IMetaDataDispenserEx,
45 if(m_wzMetadataVersion)
49 V_VT(&encOption) = VT_BSTR;
50 V_BSTR(&encOption) = bstr = ::SysAllocString(m_wzMetadataVersion);
51 hr = m_pDisp->SetOption(MetaDataRuntimeVersion, &encOption);
52 ::SysFreeString(bstr);
54 hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit2,
55 (IUnknown **)&m_pEmitter);
59 m_pManifest->SetEmitter(m_pEmitter);
60 if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataImport2, (void**)&m_pImporter)))
63 hr = CoCreateInstance(CLSID_CorSymWriter_SxS,
66 IID_ISymUnmanagedWriter,
67 (void **)&m_pSymWriter);
70 if(m_pSymWriter) m_pSymWriter->Initialize((IUnknown*)m_pEmitter,
77 fprintf(stderr, "Error: QueryInterface(IID_ISymUnmanagedWriter) returns %X\n",hr);
81 //m_Parser = new AsmParse(m_pEmitter);
82 m_fInitialisedMetaData = TRUE;
87 if(bClock) bClock->cMDInitEnd = GetTickCount();
90 /*********************************************************************************/
91 /* if we have any Thread local store data, make the TLS directory record for it */
93 HRESULT Assembler::CreateTLSDirectory() {
97 if (FAILED(hr=m_pCeeFileGen->GetSectionDataLen(m_pTLSSection, &tlsEnd))) return(hr);
99 if (tlsEnd == 0) // No TLS data, we are done
102 // place to put the TLS directory
103 HCEESECTION tlsDirSec = m_pGlobalDataSection;
105 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32)
107 DWORD sizeofptr = (DWORD)sizeof(DWORD);
108 DWORD sizeofdir = (DWORD)sizeof(IMAGE_TLS_DIRECTORY32);
109 DWORD offsetofStartAddressOfRawData = (DWORD)offsetof(IMAGE_TLS_DIRECTORY32, StartAddressOfRawData);
110 DWORD offsetofEndAddressOfRawData = (DWORD)offsetof(IMAGE_TLS_DIRECTORY32, EndAddressOfRawData);
111 DWORD offsetofAddressOfIndex = (DWORD)offsetof(IMAGE_TLS_DIRECTORY32, AddressOfIndex);
112 DWORD offsetofAddressOfCallBacks = (DWORD)offsetof(IMAGE_TLS_DIRECTORY32, AddressOfCallBacks);
114 // Get memory for for the TLS directory block,as well as a spot for callback chain
115 IMAGE_TLS_DIRECTORY32* tlsDir;
116 if(FAILED(hr=m_pCeeFileGen->GetSectionBlock(tlsDirSec, sizeofdir + sizeofptr, sizeofptr, (void**) &tlsDir))) return(hr);
117 DWORD* callBackChain = (DWORD*) &tlsDir[1];
120 // Find out where the tls directory will end up
122 if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsDirOffset))) return(hr);
123 tlsDirOffset -= (sizeofdir + sizeofptr);
125 // Set the start of the TLS data (offset 0 of hte TLS section)
126 tlsDir->StartAddressOfRawData = 0;
127 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofStartAddressOfRawData, m_pTLSSection, srRelocHighLow))) return(hr);
129 // Set the end of the TLS data
130 tlsDir->EndAddressOfRawData = VALPTR(tlsEnd);
131 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofEndAddressOfRawData, m_pTLSSection, srRelocHighLow))) return(hr);
133 // Allocate space for the OS to put the TLS index for this PE file (needs to be Read/Write?)
135 if(FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pGlobalDataSection, sizeof(DWORD), sizeof(DWORD), (void**) &tlsIndex))) return(hr);
136 *tlsIndex = 0xCCCCCCCC; // Does't really matter, the OS will fill it in
138 // Find out where tlsIndex index is
139 ULONG tlsIndexOffset;
140 if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsIndexOffset))) return(hr);
141 tlsIndexOffset -= sizeof(DWORD);
143 // Set the address of the TLS index
144 tlsDir->AddressOfIndex = VALPTR(tlsIndexOffset);
145 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofAddressOfIndex, m_pGlobalDataSection, srRelocHighLow))) return(hr);
147 // Set addres of callbacks chain
148 tlsDir->AddressOfCallBacks = VALPTR((DWORD)(DWORD_PTR)(PIMAGE_TLS_CALLBACK*)(size_t)(tlsDirOffset + sizeofdir));
149 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofAddressOfCallBacks, tlsDirSec, srRelocHighLow))) return(hr);
151 // Set the other fields.
152 tlsDir->SizeOfZeroFill = 0;
153 tlsDir->Characteristics = 0;
155 hr=m_pCeeFileGen->SetDirectoryEntry (m_pCeeFile, tlsDirSec, IMAGE_DIRECTORY_ENTRY_TLS,
156 sizeofdir, tlsDirOffset);
158 if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
159 COR_SET_32BIT_REQUIRED(m_dwComImageFlags);
163 DWORD sizeofptr = (DWORD)sizeof(__int64);
164 DWORD sizeofdir = (DWORD)sizeof(IMAGE_TLS_DIRECTORY64);
165 DWORD offsetofStartAddressOfRawData = (DWORD)offsetof(IMAGE_TLS_DIRECTORY64, StartAddressOfRawData);
166 DWORD offsetofEndAddressOfRawData = (DWORD)offsetof(IMAGE_TLS_DIRECTORY64, EndAddressOfRawData);
167 DWORD offsetofAddressOfIndex = (DWORD)offsetof(IMAGE_TLS_DIRECTORY64, AddressOfIndex);
168 DWORD offsetofAddressOfCallBacks = (DWORD)offsetof(IMAGE_TLS_DIRECTORY64, AddressOfCallBacks);
170 // Get memory for for the TLS directory block,as well as a spot for callback chain
171 IMAGE_TLS_DIRECTORY64* tlsDir;
172 if(FAILED(hr=m_pCeeFileGen->GetSectionBlock(tlsDirSec, sizeofdir + sizeofptr, sizeofptr, (void**) &tlsDir))) return(hr);
173 __int64* callBackChain = (__int64*) &tlsDir[1];
176 // Find out where the tls directory will end up
178 if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsDirOffset))) return(hr);
179 tlsDirOffset -= (sizeofdir + sizeofptr);
181 // Set the start of the TLS data (offset 0 of hte TLS section)
182 tlsDir->StartAddressOfRawData = 0;
183 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofStartAddressOfRawData, m_pTLSSection, srRelocHighLow))) return(hr);
185 // Set the end of the TLS data
186 tlsDir->EndAddressOfRawData = VALPTR(tlsEnd);
187 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofEndAddressOfRawData, m_pTLSSection, srRelocHighLow))) return(hr);
189 // Allocate space for the OS to put the TLS index for this PE file (needs to be Read/Write?)
191 if(FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pGlobalDataSection, sizeof(DWORD), sizeof(DWORD), (void**) &tlsIndex))) return(hr);
192 *tlsIndex = 0xCCCCCCCC; // Does't really matter, the OS will fill it in
194 // Find out where tlsIndex index is
195 ULONG tlsIndexOffset;
196 if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsIndexOffset))) return(hr);
197 tlsIndexOffset -= sizeof(DWORD);
199 // Set the address of the TLS index
200 tlsDir->AddressOfIndex = VALPTR(tlsIndexOffset);
201 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofAddressOfIndex, m_pGlobalDataSection, srRelocHighLow))) return(hr);
203 // Set addres of callbacks chain
204 tlsDir->AddressOfCallBacks = VALPTR((DWORD)(DWORD_PTR)(PIMAGE_TLS_CALLBACK*)(size_t)(tlsDirOffset + sizeofdir));
205 if(FAILED(hr=m_pCeeFileGen->AddSectionReloc(tlsDirSec, tlsDirOffset + offsetofAddressOfCallBacks, tlsDirSec, srRelocHighLow))) return(hr);
207 // Set the other fields.
208 tlsDir->SizeOfZeroFill = 0;
209 tlsDir->Characteristics = 0;
211 hr=m_pCeeFileGen->SetDirectoryEntry (m_pCeeFile, tlsDirSec, IMAGE_DIRECTORY_ENTRY_TLS,
212 sizeofdir, tlsDirOffset);
215 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_STRIP_RELOCS)
217 report->error("Base relocations are emitted, while /STRIPRELOC option has been specified");
219 m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY;
224 HRESULT Assembler::CreateDebugDirectory()
228 // Only emit this if we're also emitting debug info.
229 if (!(m_fGeneratePDB && m_pSymWriter))
232 IMAGE_DEBUG_DIRECTORY debugDirIDD;
235 DWORD debugDirDataSize;
238 param.debugDirData = NULL;
240 // Get the debug info from the symbol writer.
241 if (FAILED(hr=m_pSymWriter->GetDebugInfo(NULL, 0, ¶m.debugDirDataSize, NULL)))
244 // Will there even be any?
245 if (param.debugDirDataSize == 0)
248 // Make some room for the data.
249 PAL_TRY(Param *, pParam, ¶m) {
250 pParam->debugDirData = new BYTE[pParam->debugDirDataSize];
251 } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
255 if(FAILED(hr)) return hr;
256 // Actually get the data now.
257 if (FAILED(hr = m_pSymWriter->GetDebugInfo(&debugDirIDD,
258 param.debugDirDataSize,
260 param.debugDirData)))
263 // Grab the timestamp of the PE file.
266 if (FAILED(hr = m_pCeeFileGen->GetFileTimeStamp(m_pCeeFile,
270 // Fill in the directory entry.
271 debugDirIDD.TimeDateStamp = VAL32(fileTimeStamp);
273 // Grab memory in the section for our stuff.
274 // Note that UpdateResource doesn't work correctly if the debug directory is
275 // in the data section. So instead we put it in the text section (same as
277 HCEESECTION sec = m_pILSection;//m_pGlobalDataSection;
280 if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(sec,
281 sizeof(debugDirIDD) +
282 param.debugDirDataSize,
287 // Where did we get that memory?
289 if (FAILED(hr = m_pCeeFileGen->GetSectionDataLen(sec,
293 deOffset -= (sizeof(debugDirIDD) + param.debugDirDataSize);
295 // Setup a reloc so that the address of the raw
296 // data is setup correctly.
297 debugDirIDD.PointerToRawData = VAL32(deOffset + sizeof(debugDirIDD));
299 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(
302 offsetof(IMAGE_DEBUG_DIRECTORY,
304 sec, srRelocFilePos)))
307 debugDirIDD.AddressOfRawData = VAL32(deOffset + sizeof(debugDirIDD));
309 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(
312 offsetof(IMAGE_DEBUG_DIRECTORY,
314 sec, srRelocAbsolute)))
316 // Emit the directory entry.
317 if (FAILED(hr = m_pCeeFileGen->SetDirectoryEntry(m_pCeeFile,
319 IMAGE_DIRECTORY_ENTRY_DEBUG,
324 // Copy the debug directory into the section.
325 memcpy(de, &debugDirIDD, sizeof(debugDirIDD));
326 memcpy(de + sizeof(debugDirIDD), param.debugDirData,
327 param.debugDirDataSize);
329 if (param.debugDirData)
331 delete [] param.debugDirData;
336 if (param.debugDirData)
338 delete [] param.debugDirData;
342 //#ifdef EXPORT_DIR_ENABLED
343 HRESULT Assembler::CreateExportDirectory()
346 DWORD Nentries = m_EATList.COUNT();
347 if(Nentries == 0) return S_OK;
349 IMAGE_EXPORT_DIRECTORY exportDirIDD;
350 DWORD exportDirDataSize;
353 unsigned i, L, ordBase = 0xFFFFFFFF, Ldllname;
354 // get the DLL name from output file name
356 Ldllname = (unsigned)wcslen(m_wzOutputFileName)*3+3;
357 char* szOutputFileName = new char[Ldllname];
358 memset(szOutputFileName,0,wcslen(m_wzOutputFileName)*3+3);
359 WszWideCharToMultiByte(CP_ACP,0,m_wzOutputFileName,-1,szOutputFileName,Ldllname,NULL,NULL);
360 pszDllName = strrchr(szOutputFileName,'\\');
361 if(pszDllName == NULL) pszDllName = strrchr(szOutputFileName,':');
362 if(pszDllName == NULL) pszDllName = szOutputFileName;
363 Ldllname = (unsigned)strlen(pszDllName)+1;
365 // Allocate buffer for tables
366 for(i = 0, L=0; i < Nentries; i++) L += 1+(unsigned)strlen(m_EATList.PEEK(i)->szAlias);
367 exportDirDataSize = Nentries*5*sizeof(WORD) + L + Ldllname;
368 exportDirData = new BYTE[exportDirDataSize];
369 memset(exportDirData,0,exportDirDataSize);
371 // Export address table
372 DWORD* pEAT = (DWORD*)exportDirData;
373 // Name pointer table
374 DWORD* pNPT = pEAT + Nentries;
376 WORD* pOT = (WORD*)(pNPT + Nentries);
378 char* pENT = (char*)(pOT + Nentries);
380 char* pDLLName = pENT + L;
382 // sort the names/ordinals
383 char** pAlias = new char*[Nentries];
384 for(i = 0; i < Nentries; i++)
386 pEATE = m_EATList.PEEK(i);
387 pOT[i] = (WORD)pEATE->dwOrdinal;
388 if(pOT[i] < ordBase) ordBase = pOT[i];
389 pAlias[i] = pEATE->szAlias;
397 for(i=1; i < Nentries; i++)
399 if(strcmp(pAlias[i-1],pAlias[i]) > 0)
403 pAlias[i-1] = pAlias[i];
411 // normalize ordinals
412 for(i = 0; i < Nentries; i++) pOT[i] -= ordBase;
413 // fill the export address table
415 #pragma warning(push)
416 #pragma warning(disable:22008) // "Suppress PREfast warnings about integer overflow"
418 for(i = 0; i < Nentries; i++)
420 pEATE = m_EATList.PEEK(i);
421 pEAT[pEATE->dwOrdinal - ordBase] = pEATE->dwStubRVA;
426 // fill the export names table
428 for(i = 0, j = 0; i < Nentries; i++)
430 pNPT[i] = j; // relative offset in the table
431 l = (unsigned)strlen(pAlias[i])+1;
432 memcpy(&pENT[j],pAlias[i],l);
437 memcpy(pDLLName,pszDllName,Ldllname);
439 // Data blob is ready pending Name Pointer Table values offsetting
441 memset(&exportDirIDD,0,sizeof(IMAGE_EXPORT_DIRECTORY));
442 // Grab the timestamp of the PE file.
444 if (FAILED(hr = m_pCeeFileGen->GetFileTimeStamp(m_pCeeFile,&fileTimeStamp))) return hr;
445 // Fill in the directory entry.
446 // Characteristics, MajorVersion and MinorVersion play no role and stay 0
447 exportDirIDD.TimeDateStamp = VAL32(fileTimeStamp);
448 exportDirIDD.Name = VAL32(exportDirDataSize - Ldllname); // to be offset later
449 exportDirIDD.Base = VAL32(ordBase);
450 exportDirIDD.NumberOfFunctions = VAL32(Nentries);
451 exportDirIDD.NumberOfNames = VAL32(Nentries);
452 exportDirIDD.AddressOfFunctions = 0; // to be offset later
453 exportDirIDD.AddressOfNames = VAL32(Nentries*sizeof(DWORD)); // to be offset later
454 exportDirIDD.AddressOfNameOrdinals = VAL32(Nentries*sizeof(DWORD)*2); // to be offset later
456 // Grab memory in the section for our stuff.
457 HCEESECTION sec = m_pGlobalDataSection;
459 if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(sec,
460 sizeof(IMAGE_EXPORT_DIRECTORY) + exportDirDataSize,
462 (void**) &de))) return hr;
463 // Where did we get that memory?
464 ULONG deOffset, deDataOffset;
465 if (FAILED(hr = m_pCeeFileGen->GetSectionDataLen(sec, &deDataOffset))) return hr;
467 deDataOffset -= exportDirDataSize;
468 deOffset = deDataOffset - sizeof(IMAGE_EXPORT_DIRECTORY);
470 // Add offsets and set up relocs for header entries
471 exportDirIDD.Name = VAL32(VAL32(exportDirIDD.Name) + deDataOffset);
472 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,deOffset + offsetof(IMAGE_EXPORT_DIRECTORY,Name),
473 sec, srRelocAbsolute))) return hr;
474 exportDirIDD.AddressOfFunctions = VAL32(VAL32(exportDirIDD.AddressOfFunctions) + deDataOffset);
475 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,deOffset + offsetof(IMAGE_EXPORT_DIRECTORY,AddressOfFunctions),
476 sec, srRelocAbsolute))) return hr;
477 exportDirIDD.AddressOfNames = VAL32(VAL32(exportDirIDD.AddressOfNames) + deDataOffset);
478 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,deOffset + offsetof(IMAGE_EXPORT_DIRECTORY,AddressOfNames),
479 sec, srRelocAbsolute))) return hr;
480 exportDirIDD.AddressOfNameOrdinals = VAL32(VAL32(exportDirIDD.AddressOfNameOrdinals) + deDataOffset);
481 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,deOffset + offsetof(IMAGE_EXPORT_DIRECTORY,AddressOfNameOrdinals),
482 sec, srRelocAbsolute))) return hr;
484 // Add offsets and set up relocs for Name Pointer Table
485 j = deDataOffset + Nentries*5*sizeof(WORD); // EA, NP and O Tables come first
486 for(i = 0; i < Nentries; i++)
489 if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,exportDirIDD.AddressOfNames+i*sizeof(DWORD),
490 sec, srRelocAbsolute))) return hr;
494 // Emit the directory entry.
495 if (FAILED(hr = m_pCeeFileGen->SetDirectoryEntry(m_pCeeFile, sec, IMAGE_DIRECTORY_ENTRY_EXPORT,
496 sizeof(IMAGE_EXPORT_DIRECTORY), deOffset))) return hr;
498 // Copy the debug directory into the section.
499 memcpy(de, &exportDirIDD, sizeof(IMAGE_EXPORT_DIRECTORY));
500 memcpy(de + sizeof(IMAGE_EXPORT_DIRECTORY), exportDirData, exportDirDataSize);
502 delete [] exportDirData;
506 static const BYTE ExportStubAMD64Template[] =
508 // Jump through VTFixup table
509 0x48, 0xA1, // rex.w rex.b mov rax,[following address]
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//address of VTFixup slot
511 0xFF, 0xE0 // jmp [rax]
513 static const BYTE ExportStubX86Template[] =
515 // Jump through VTFixup table
516 0xFF, 0x25, // jmp [following address]
517 0x00, 0x00, 0x00, 0x00 //address of VTFixup slot
519 static const WORD ExportStubARMTemplate[] =
521 // Jump through VTFixup table
522 0xf8df, 0xf000, // ldr pc, [pc, #0]
523 0x0000, 0x0000 //address of VTFixup slot
526 static const BYTE ExportStubIA64Template[] =
533 // br.cond.sptk.few b6
535 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40,
536 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
537 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50,
538 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00,
539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//address of the template
540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //address of VTFixup slot
542 DWORD Assembler::EmitExportStub(DWORD dwVTFSlotRVA)
544 DWORD EXPORT_STUB_SIZE = (DWORD)(sizeof(WORD)+sizeof(DWORD));
545 DWORD OFFSET_OF_ADDR = (DWORD)sizeof(WORD);
546 DWORD STUB_ALIGNMENT = 16;
547 BYTE* STUB_TEMPLATE = NULL;
550 DWORD* pdwVTFSlotRVA;
551 if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_IA64)
553 STUB_TEMPLATE = (BYTE*)&ExportStubIA64Template[0];
554 EXPORT_STUB_SIZE = sizeof(ExportStubIA64Template);
556 if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, EXPORT_STUB_SIZE, STUB_ALIGNMENT, (void **) &outBuff))) return 0;
557 memcpy(outBuff,STUB_TEMPLATE,EXPORT_STUB_SIZE);
558 pdwVTFSlotRVA = (DWORD*)(&outBuff[OFFSET_OF_ADDR]);
559 *pdwVTFSlotRVA = VAL32(dwVTFSlotRVA);
561 // The offset where we start, (not where the alignment bytes start!)
562 if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) return 0;
564 PEFileOffset -= EXPORT_STUB_SIZE;
565 *((DWORD*)(&outBuff[OFFSET_OF_ADDR - 8])) = PEFileOffset; // set PLabel
566 m_pCeeFileGen->AddSectionReloc(m_pILSection, PEFileOffset+OFFSET_OF_ADDR-8,m_pILSection, srRelocHighLow);
567 m_pCeeFileGen->AddSectionReloc(m_pILSection, PEFileOffset+OFFSET_OF_ADDR,m_pGlobalDataSection, srRelocHighLow);
568 PEFileOffset += OFFSET_OF_ADDR - 8; // entry point is PLabel, which points at the template
572 if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_AMD64)
574 STUB_TEMPLATE = (BYTE*)&ExportStubAMD64Template[0];
575 EXPORT_STUB_SIZE = sizeof(ExportStubAMD64Template);
579 else if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
581 STUB_TEMPLATE = (BYTE*)&ExportStubX86Template[0];
582 EXPORT_STUB_SIZE = sizeof(ExportStubX86Template);
585 else if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM)
587 STUB_TEMPLATE = (BYTE*)&ExportStubARMTemplate[0];
588 EXPORT_STUB_SIZE = sizeof(ExportStubARMTemplate);
594 report->error("Unmanaged exports are not implemented for unknown platform");
597 // Addr must be aligned, not the stub!
598 if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) return 0;
599 if((PEFileOffset + OFFSET_OF_ADDR)&(STUB_ALIGNMENT-1))
601 ULONG L = STUB_ALIGNMENT - ((PEFileOffset + OFFSET_OF_ADDR)&(STUB_ALIGNMENT-1));
602 if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, L, 1, (void **) &outBuff))) return 0;
606 if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, EXPORT_STUB_SIZE, 1, (void **) &outBuff))) return 0;
607 memcpy(outBuff,STUB_TEMPLATE,EXPORT_STUB_SIZE);
608 pdwVTFSlotRVA = (DWORD*)(&outBuff[OFFSET_OF_ADDR]);
609 *pdwVTFSlotRVA = VAL32(dwVTFSlotRVA);
611 // The offset where we start, (not where the alignment bytes start!)
612 if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) return 0;
614 PEFileOffset -= EXPORT_STUB_SIZE;
615 _ASSERTE(((PEFileOffset + OFFSET_OF_ADDR)&(STUB_ALIGNMENT-1))==0);
616 m_pCeeFileGen->AddSectionReloc(m_pILSection, PEFileOffset+OFFSET_OF_ADDR,m_pGlobalDataSection, srRelocHighLow);
618 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_STRIP_RELOCS)
620 report->error("Base relocations are emitted, while /STRIPRELOC option has been specified");
622 m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&PEFileOffset);
627 HRESULT Assembler::GetCAName(mdToken tkCA, __out LPWSTR *ppszName)
635 if (TypeFromToken(tkCA) == mdtMemberRef)
638 if (FAILED(hr = m_pImporter->GetMemberRefProps( tkCA, &parent, NULL, 0, NULL, NULL, NULL)))
642 else if (TypeFromToken(tkCA) == mdtMethodDef)
645 if (FAILED(hr = m_pImporter->GetMemberProps( tkCA, &parent, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)))
650 if (TypeFromToken(tkCA) == mdtTypeRef)
653 if (FAILED(hr = m_pImporter->GetTypeRefProps(tkCA, NULL, NULL, 0, &cchName)))
655 if ((name = new WCHAR[cchName + 1]) == NULL)
656 return E_OUTOFMEMORY;
657 hr = m_pImporter->GetTypeRefProps(tkCA, NULL, name, cchName, &cchName);
661 hr = m_pImporter->GetTypeDefProps(tkCA, NULL, 0, &cchName, NULL, NULL);
664 if ((name = new WCHAR[cchName + 1]) == NULL)
665 return E_OUTOFMEMORY;
666 hr = m_pImporter->GetTypeDefProps(tkCA, name, cchName, &cchName, NULL, NULL);
675 BYTE HexToByte (CHAR wc)
677 if (!iswxdigit(wc)) return (BYTE) 0xff;
678 if (iswdigit(wc)) return (BYTE) (wc - L'0');
679 if (iswupper(wc)) return (BYTE) (wc - L'A' + 10);
680 return (BYTE) (wc - L'a' + 10);
683 bool GetBytesFromHex (LPCSTR szPublicKeyHexString, ULONG cchPublicKeyHexString, BYTE** buffer, ULONG *cbBufferSize)
685 ULONG cchHex = cchPublicKeyHexString;
688 *cbBufferSize = cchHex / 2;
690 *buffer = new BYTE[*cbBufferSize];
694 for (ULONG i = 0; i < *cbBufferSize; i++)
696 BYTE msn = HexToByte(*szPublicKeyHexString);
697 BYTE lsn = HexToByte(*(szPublicKeyHexString + 1));
698 if (msn == 0xFF || lsn == 0xFF)
704 (*buffer)[i] = (BYTE) ( (msn << 4) | lsn );
705 szPublicKeyHexString += 2;
711 HRESULT Assembler::GetSignatureKey()
715 void * pvData = NULL;
718 CustomDescrList* pCDList = &m_pManifest->m_pAssembly->m_CustomDescrList;
720 for (ULONG i = 0;i < pCDList->COUNT(); i++)
722 CustomDescr* pCD = pCDList->PEEK(i);
726 pvData = (void *)(pCD->pBlob->ptr());
727 cbSize = pCD->pBlob->length();
728 pCD->tkOwner = m_pManifest->m_pAssembly->tkTok;
729 mdToken tkOwnerType, tkTypeType = TypeFromToken(pCD->tkType);
731 if (GetCAName(pCD->tkType, &pName) != S_OK)
734 if (wcscmp(pName, L"System.Reflection.AssemblySignatureKeyAttribute") == 0)
736 if (cbSize < sizeof(WORD) || GET_UNALIGNED_VAL16(pvData) != 1)
741 pvData = (unsigned char *)pvData + sizeof(WORD);
742 cbSize -= sizeof(WORD);
744 // String is stored as compressed length, UTF8.
745 if (*(const BYTE*)pvData != 0xFF)
747 PCCOR_SIGNATURE sig = (PCCOR_SIGNATURE)pvData;
748 cbSize -= CorSigUncompressedDataSize(sig);
749 DWORD len = CorSigUncompressData(sig);
750 pvData = (void *)sig;
757 AsmManStrongName *pSN = &m_pManifest->m_sStrongName;
758 GetBytesFromHex((LPCSTR)pvData, len, &pSN->m_pbSignatureKey, &pSN->m_cbSignatureKey);
777 HRESULT Assembler::AllocateStrongNameSignature()
780 HCEESECTION hSection;
785 AsmManStrongName *pSN = &m_pManifest->m_sStrongName;
787 // Pulls the AssemblySignatureKey attribute from m_CustomDescrList
788 // If present, populate the pSN->m_pbSignatureKey from the AssemblySignatureKeyAttribute blob
789 if (FAILED(hr = GetSignatureKey()))
794 // Determine size of signature blob.
795 if (pSN->m_pbSignatureKey != NULL)
797 // If m_pbSignatureKey present use it, else fall back to using identity key.
798 if (FAILED(hr = LegacyActivationShim::StrongNameSignatureSize_HRESULT(
799 pSN->m_pbSignatureKey,
800 pSN->m_cbSignatureKey,
806 else if (FAILED(hr = LegacyActivationShim::StrongNameSignatureSize_HRESULT(
814 // Grab memory in the section for our stuff.
815 if (FAILED(hr = m_pCeeFileGen->GetIlSection(m_pCeeFile,
819 if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(hSection,
825 // Where did we get that memory?
826 if (FAILED(hr = m_pCeeFileGen->GetSectionDataLen(hSection,
830 dwDataOffset -= dwDataLength;
832 // Convert to an RVA.
833 if (FAILED(hr = m_pCeeFileGen->GetMethodRVA(m_pCeeFile,
838 // Emit the directory entry.
839 if (FAILED(hr = m_pCeeFileGen->SetStrongNameEntry(m_pCeeFile,
847 HRESULT Assembler::StrongNameSign()
849 LPWSTR wszOutputFile;
851 AsmManStrongName *pSN = &m_pManifest->m_sStrongName;
853 // Determine what the ouput PE was called.
854 if (FAILED(hr = m_pCeeFileGen->GetOutputFileName(m_pCeeFile,
858 // Update the output PE image with a strong name signature.
859 if (FAILED(hr = LegacyActivationShim::StrongNameSignatureGeneration_HRESULT(
861 pSN->m_wzKeyContainer,
873 BOOL Assembler::EmitFieldsMethods(Class* pClass)
877 // emit all field definition metadata tokens
878 if((n = pClass->m_FieldDList.COUNT()))
880 FieldDescriptor* pFD;
881 if(m_fReportProgress) printf("Fields: %d;\t",n);
882 for(int j=0; (pFD = pClass->m_FieldDList.PEEK(j)); j++) // can't use POP here: we'll need field list for props
886 if(!OnErrGo) return FALSE;
892 // Fields are emitted; emit the class layout
894 COR_FIELD_OFFSET *pOffsets = NULL;
895 ULONG ul = pClass->m_ulPack;
896 ULONG N = pClass->m_dwNumFieldsWithOffset;
898 EmitSecurityInfo(pClass->m_cl,
899 pClass->m_pPermissions,
900 pClass->m_pPermissionSets);
901 pClass->m_pPermissions = NULL;
902 pClass->m_pPermissionSets = NULL;
903 if((pClass->m_ulSize != 0xFFFFFFFF)||(ul != 0)||(N != 0))
905 if(IsTdAutoLayout(pClass->m_Attr)) report->warn("Layout specified for auto-layout class\n");
906 if((ul > 128)||((ul & (ul-1)) !=0 ))
907 report->error("Invalid packing parameter (%d), must be 1,2,4,8...128\n",pClass->m_ulPack);
910 pOffsets = new COR_FIELD_OFFSET[N+1];
912 FieldDescriptor *pFD;
913 for(i=0; (pFD = pClass->m_FieldDList.PEEK(i)); i++)
915 if(pFD->m_ulOffset != 0xFFFFFFFF)
917 pOffsets[j].ridOfField = RidFromToken(pFD->m_fdFieldTok);
918 pOffsets[j].ulOffset = pFD->m_ulOffset;
923 pOffsets[j].ridOfField = mdFieldDefNil;
925 m_pEmitter->SetClassLayout (
926 pClass->m_cl, // [IN] typedef
927 ul, // [IN] packing size specified as 1, 2, 4, 8, or 16
928 pOffsets, // [IN] array of layout specification
929 pClass->m_ulSize); // [IN] size of the class
930 if(pOffsets) delete [] pOffsets;
933 // emit all method definition metadata tokens
934 if((n = pClass->m_MethodList.COUNT()))
938 if(m_fReportProgress) printf("Methods: %d;\t",n);
939 for(int i=0; (pMethod = pClass->m_MethodList.PEEK(i));i++)
941 if(!EmitMethod(pMethod))
943 if(!OnErrGo) return FALSE;
946 pMethod->m_fNew = FALSE;
949 if(m_fReportProgress) printf("\n");
953 HRESULT Assembler::ResolveLocalMemberRefs()
955 unsigned ulTotal=0, ulDefs=0, ulRefs=0, ulUnres=0;
956 MemberRefDList* pList[2] = {&m_LocalMethodRefDList,&m_LocalFieldRefDList};
958 if(pList[0]->COUNT() + pList[1]->COUNT())
960 MemberRefDescriptor* pMRD;
961 mdToken tkMemberDef = 0;
965 if(m_fReportProgress) printf("Resolving local member refs: ");
968 for(i=0; (pMRD = pList[k]->PEEK(i)) != NULL; i++)
970 if(pMRD->m_tkResolved) continue;
974 char* pMRD_szName = pMRD->m_szName;
975 DWORD pMRD_dwName = pMRD->m_dwName;
976 ULONG pMRD_dwCSig = (pMRD->m_pSigBinStr ? pMRD->m_pSigBinStr->length() : 0);
977 PCOR_SIGNATURE pMRD_pSig = (PCOR_SIGNATURE)(pMRD->m_pSigBinStr ? pMRD->m_pSigBinStr->ptr() : NULL);
983 if(pMRD->m_tdClass == mdTokenNil)
984 pSearch = m_lstClass.PEEK(0);
985 else if((TypeFromToken(pMRD->m_tdClass) != mdtTypeDef)
986 ||((pSearch = m_lstClass.PEEK(RidFromToken(pMRD->m_tdClass)-1)) == NULL))
988 report->msg("Error: bad parent 0x%08X of local member ref '%s'\n",
989 pMRD->m_tdClass,pMRD->m_szName);
993 // MemberRef may reference a method or a field
996 if((*pMRD_pSig & IMAGE_CEE_CS_CALLCONV_MASK)==IMAGE_CEE_CS_CALLCONV_VARARG)
1000 _GetFixedSigOfVarArg(pMRD_pSig,pMRD_dwCSig,&qbSig,&L);
1001 pMRD_pSig = (PCOR_SIGNATURE)(qbSig.Ptr());
1004 for(j=0; (pListMD = pSearch->m_MethodList.PEEK(j)) != NULL; j++)
1006 if(pListMD->m_dwName != pMRD_dwName) continue;
1007 if(strcmp(pListMD->m_szName,pMRD_szName)) continue;
1008 if(pListMD->m_dwMethodCSig != pMRD_dwCSig) continue;
1009 if(memcmp(pListMD->m_pMethodSig,pMRD_pSig,pMRD_dwCSig)) continue;
1010 tkMemberDef = pListMD->m_Tok;
1014 if(tkMemberDef && ((*pMRD_pSig & IMAGE_CEE_CS_CALLCONV_MASK)==IMAGE_CEE_CS_CALLCONV_VARARG))
1016 WszMultiByteToWideChar(g_uCodePage,0,pMRD_szName,-1,wzUniBuf,dwUniBuf);
1018 if(IsMdPrivateScope(pListMD->m_Attr))
1020 WCHAR* p = wcsstr(wzUniBuf,L"$PST06");
1024 m_pEmitter->DefineMemberRef(tkMemberDef, wzUniBuf,
1025 pMRD->m_pSigBinStr->ptr(),
1026 pMRD->m_pSigBinStr->length(),
1034 FieldDescriptor* pListFD;
1035 for(j=0; (pListFD = pSearch->m_FieldDList.PEEK(j)) != NULL; j++)
1037 if(pListFD->m_dwName != pMRD_dwName) continue;
1038 if(strcmp(pListFD->m_szName,pMRD_szName)) continue;
1039 if(pListFD->m_pbsSig)
1041 if(pListFD->m_pbsSig->length() != pMRD_dwCSig) continue;
1042 if(memcmp(pListFD->m_pbsSig->ptr(),pMRD_pSig,pMRD_dwCSig)) continue;
1044 else if(pMRD_dwCSig) continue;
1045 tkMemberDef = pListFD->m_fdFieldTok;
1052 { // could not resolve ref to def, make new ref and leave it this way
1053 if((pSearch = pMRD->m_pClass) != NULL)
1055 mdToken tkRef = MakeTypeRef(1,pSearch->m_szFQN);
1057 if(RidFromToken(tkRef))
1059 WszMultiByteToWideChar(g_uCodePage,0,pMRD_szName,-1,wzUniBuf,dwUniBuf);
1061 m_pEmitter->DefineMemberRef(tkRef, wzUniBuf, pMRD_pSig,
1062 pMRD_dwCSig, &tkMemberDef);
1067 report->msg("Error: unresolved member ref '%s' of class 0x%08X\n",pMRD->m_szName,pMRD->m_tdClass);
1073 report->msg("Error: unresolved global member ref '%s'\n",pMRD->m_szName);
1077 pMRD->m_tkResolved = tkMemberDef;
1080 for(i=0; (pMRD = m_MethodSpecList.PEEK(i)) != NULL; i++)
1082 if(pMRD->m_tkResolved) continue;
1083 tkMemberDef = pMRD->m_tdClass;
1084 if(TypeFromToken(tkMemberDef)==0x99000000)
1086 tkMemberDef = m_LocalMethodRefDList.PEEK(RidFromToken(tkMemberDef)-1)->m_tkResolved;
1087 if((TypeFromToken(tkMemberDef)==mdtMethodDef)||(TypeFromToken(tkMemberDef)==mdtMemberRef))
1089 ULONG pMRD_dwCSig = (pMRD->m_pSigBinStr ? pMRD->m_pSigBinStr->length() : 0);
1090 PCOR_SIGNATURE pMRD_pSig = (PCOR_SIGNATURE)(pMRD->m_pSigBinStr ? pMRD->m_pSigBinStr->ptr() : NULL);
1091 HRESULT hr = m_pEmitter->DefineMethodSpec(tkMemberDef, pMRD_pSig, pMRD_dwCSig, &(pMRD->m_tkResolved));
1093 report->error("Unable to define method instantiation");
1096 if(RidFromToken(pMRD->m_tkResolved)) ulDefs++;
1099 if(m_fReportProgress) printf("%d -> %d defs, %d refs, %d unresolved\n",ulTotal,ulDefs,ulRefs,ulUnres);
1101 return (ulUnres ? E_FAIL : S_OK);
1104 HRESULT Assembler::DoLocalMemberRefFixups()
1106 MemberRefDList* pList;
1107 unsigned Nlmr = m_LocalMethodRefDList.COUNT() + m_LocalFieldRefDList.COUNT(),
1108 Nlmrf = m_LocalMemberRefFixupList.COUNT();
1112 MemberRefDescriptor* pMRD;
1113 LocalMemberRefFixup* pMRF;
1115 for(i = 0; (pMRF = m_LocalMemberRefFixupList.PEEK(i)) != NULL; i++)
1117 if(m_fENCMode && (!pMRF->m_fNew)) continue;
1119 switch(TypeFromToken(pMRF->tk))
1121 case 0x99000000: pList = &m_LocalMethodRefDList; break;
1122 case 0x98000000: pList = &m_LocalFieldRefDList; break;
1123 case 0x9A000000: pList = &m_MethodSpecList; break;
1124 default: pList = NULL; break;
1128 if((pMRD = pList->PEEK(RidFromToken(pMRF->tk)-1)) != NULL)
1129 SET_UNALIGNED_VAL32((void *)(pMRF->offset), pMRD->m_tkResolved);
1132 report->msg("Error: bad local member ref token 0x%08X in LMR fixup\n",pMRF->tk);
1136 pMRF->m_fNew = FALSE;
1141 report->msg("Error: %d local member ref fixups, no local member refs\n",Nlmrf);
1146 void Assembler::EmitUnresolvedCustomAttributes()
1149 while((pCD = m_CustomDescrList.POP()) != NULL)
1151 pCD->tkType = ResolveLocalMemberRef(pCD->tkType);
1152 pCD->tkOwner = ResolveLocalMemberRef(pCD->tkOwner);
1153 // Look for the class'es interfaceimpl if this CA is one of those
1154 if (pCD->tkInterfacePair)
1155 pCD->tkOwner = GetInterfaceImpl(pCD->tkOwner, pCD->tkInterfacePair);
1156 DefineCV(new CustomDescr(pCD->tkOwner,pCD->tkType,pCD->pBlob));
1160 BOOL Assembler::EmitEventsProps(Class* pClass)
1164 // emit all event definition metadata tokens
1165 if((n = pClass->m_EventDList.COUNT()))
1167 if(m_fReportProgress) printf("Events: %d;\t",n);
1168 EventDescriptor* pED;
1169 for(int j=0; (pED = pClass->m_EventDList.PEEK(j)); j++) // can't use POP here: we'll need event list for props
1173 if(!OnErrGo) return FALSE;
1176 pED->m_fNew = FALSE;
1179 // emit all property definition metadata tokens
1180 if((n = pClass->m_PropDList.COUNT()))
1182 if(m_fReportProgress) printf("Props: %d;\t",n);
1183 PropDescriptor* pPD;
1185 for(int j=0; (pPD = pClass->m_PropDList.PEEK(j)); j++)
1189 if(!OnErrGo) return FALSE;
1192 pPD->m_fNew = FALSE;
1195 if(m_fReportProgress) printf("\n");
1200 #pragma warning(push)
1201 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1203 HRESULT Assembler::CreatePEFile(__in __nullterminated WCHAR *pwzOutputFilename)
1206 DWORD mresourceSize = 0;
1207 BYTE* mresourceData = NULL;
1208 WCHAR* wzScopeName = NULL;
1210 if(bClock) bClock->cMDEmitBegin = GetTickCount();
1211 if(m_fReportProgress) printf("Creating PE file\n");
1214 printf("Error: Cannot create a PE file with no metadata\n");
1217 if(!(m_fDLL || m_fEntryPointPresent))
1219 printf("Error: No entry point declared for executable\n");
1220 if(!OnErrGo) return E_FAIL;
1223 if(bClock) bClock->cMDEmit1 = GetTickCount();
1225 // Allocate space for a strong name signature if we're delay or full
1226 // signing the assembly.
1227 if (m_pManifest->m_sStrongName.m_pbPublicKey)
1228 if (FAILED(hr = AllocateStrongNameSignature()))
1230 if(bClock) bClock->cMDEmit2 = GetTickCount();
1232 if(m_VTFList.COUNT()==0)
1236 unsigned N=0, OrdBase=0xFFFFFFFF, i, j;
1237 for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
1239 for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
1241 if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
1244 if(pMD->m_dwExportOrdinal < OrdBase) OrdBase = pMD->m_dwExportOrdinal;
1250 for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
1252 for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
1254 if(pMD->m_wVTSlot >= 0x8000)
1256 pMD->m_wVTSlot -= 0x8000 + OrdBase - 1;
1261 char* sz = new char[20];
1262 strcpy_s(sz,20,"VTF_EAT_internal");
1265 strcpy_s(sz,20,"VTF_EAT_internal");
1266 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1268 ULONGLONG *pdw = new ULONGLONG[N];
1269 for(i=0; i<N; i++) pdw[i] = UI64(0xdeadbeefdeadbeef);
1270 EmitData(pdw,sizeof(ULONGLONG)*N);
1271 m_VTFList.PUSH(new VTFEntry((USHORT)N,COR_VTABLE_64BIT|COR_VTABLE_FROM_UNMANAGED,sz));
1276 unsigned *pdw = new unsigned[N];
1277 for(i=0; i<N; i++) pdw[i] = 0xdeadbeef;
1278 EmitData(pdw,sizeof(unsigned)*N);
1279 m_VTFList.PUSH(new VTFEntry((USHORT)N,COR_VTABLE_32BIT|COR_VTABLE_FROM_UNMANAGED,sz));
1284 wzScopeName=&wzUniBuf[0];
1285 if(m_szScopeName[0]) // default: scope name = output file name
1287 WszMultiByteToWideChar(g_uCodePage,0,m_szScopeName,-1,wzScopeName,MAX_SCOPE_LENGTH);
1292 if ((pwc = wcsrchr(m_wzOutputFileName, '\\')) != NULL) pwc++;
1293 else if ((pwc = wcsrchr(m_wzOutputFileName, ':')) != NULL) pwc++;
1294 else pwc = m_wzOutputFileName;
1296 wcsncpy_s(wzScopeName, MAX_SCOPE_LENGTH, pwc, _TRUNCATE);
1298 hr = m_pEmitter->SetModuleProps(wzScopeName);
1307 if(m_pManifest->m_pAsmEmitter==NULL)
1308 hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));
1312 m_pManifest->EmitAssemblyRefs();
1315 // Emit classes, class members and globals:
1319 BOOL bIsUndefClass = FALSE;
1320 if(m_fReportProgress) printf("\nEmitting classes:\n");
1321 for (i=1; (pSearch = m_lstClass.PEEK(i)); i++) // 0 is <Module>
1323 if(m_fReportProgress)
1324 printf("Class %d:\t%s\n",i,pSearch->m_szFQN);
1326 if(pSearch->m_bIsMaster)
1328 report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
1329 bIsUndefClass = TRUE;
1331 if(!EmitClass(pSearch))
1333 if(!OnErrGo) return E_FAIL;
1335 pSearch->m_fNew = FALSE;
1337 if(bIsUndefClass && !OnErrGo) return E_FAIL;
1339 if(m_fReportProgress) printf("\nEmitting fields and methods:\n");
1340 for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
1342 if(m_fReportProgress)
1344 if(i == 0) printf("Global \t");
1345 else printf("Class %d\t",i);
1347 if(!EmitFieldsMethods(pSearch))
1349 if(!OnErrGo) return E_FAIL;
1354 // All ref'ed items def'ed in this file are emitted, resolve member refs to member defs:
1355 if(bClock) bClock->cRef2DefBegin = GetTickCount();
1356 hr = ResolveLocalMemberRefs();
1357 if(bClock) bClock->cRef2DefEnd = GetTickCount();
1358 if(FAILED(hr) &&(!OnErrGo)) goto exit;
1360 // Local member refs resolved, emit events, props and method impls
1365 if(m_fReportProgress) printf("\nEmitting events and properties:\n");
1366 for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
1368 if(m_fReportProgress)
1370 if(i == 0) printf("Global \t");
1371 else printf("Class %d\t",i);
1373 if(!EmitEventsProps(pSearch))
1375 if(!OnErrGo) return E_FAIL;
1377 pSearch->m_fNewMembers = FALSE;
1380 if(bClock) bClock->cMDEmit3 = GetTickCount();
1381 if(m_MethodImplDList.COUNT())
1383 if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
1384 if(!EmitMethodImpls())
1386 if(!OnErrGo) return E_FAIL;
1389 // Emit the rest of the metadata
1390 if(bClock) bClock->cMDEmit4 = GetTickCount();
1394 if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
1396 ResolveLocalMemberRefs(); // in case CAs added some
1397 EmitUnresolvedCustomAttributes();
1398 // Emit typedefs as special TypeSpecs
1400 #define ELEMENT_TYPE_TYPEDEF ELEMENT_TYPE_MAX+1
1402 unsigned __int8* pb;
1404 while((pTDD = m_TypeDefDList.POP()))
1406 BinStr* pbs = new BinStr();
1409 namesize = 1 + (unsigned)strlen(pTDD->m_szName);
1410 pb = pbs->getBuff(namesize + 1 + sizeof(mdToken));
1411 *pb = ELEMENT_TYPE_TYPEDEF;
1412 memcpy(++pb,pTDD->m_szName,namesize);
1413 pTDD->m_tkTypeSpec = ResolveLocalMemberRef(pTDD->m_tkTypeSpec);
1414 memcpy(pb+namesize,&(pTDD->m_tkTypeSpec),sizeof(mdToken));
1415 if(TypeFromToken(pTDD->m_tkTypeSpec)==mdtCustomAttribute)
1417 CustomDescr* pCA = pTDD->m_pCA;
1418 pbs->appendInt32(pCA->tkType);
1419 pbs->appendInt32(pCA->tkOwner);
1420 if(pCA->pBlob) pbs->append(pCA->pBlob);
1422 ResolveTypeSpec(pbs);
1428 if(bClock) bClock->cMDEmitEnd = GetTickCount();
1430 hr = DoLocalMemberRefFixups();
1431 if(FAILED(hr) &&(!OnErrGo)) goto exit;
1432 // Local member refs resolved and fixed up in BinStr method bodies. Emit the bodies.
1436 for (int i=0; (pClass = m_lstClass.PEEK(i)); i++)
1438 for(int j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
1440 if(!EmitMethodBody(pMethod,NULL))
1442 report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
1444 if(!OnErrGo) goto exit;
1446 pMethod->m_fNewBody = FALSE;
1449 //while(MethodBody* pMB = m_MethodBodyList.POP()) delete pMB;
1452 if (DoGlobalFixups() == FALSE)
1455 if(m_wzResourceFile)
1457 if (FAILED(hr=m_pCeeFileGen->SetResourceFileName(m_pCeeFile, m_wzResourceFile)))
1459 report->msg("Warning: failed to set Win32 resource file name '%S', hr=0x%8.8X\n The Win32 resource is not emitted.\n",
1460 m_wzResourceFile, hr);
1464 if (FAILED(hr=CreateTLSDirectory())) goto exit;
1466 if (FAILED(hr=CreateDebugDirectory())) goto exit;
1468 if (FAILED(hr=m_pCeeFileGen->SetOutputFileName(m_pCeeFile, pwzOutputFilename))) goto exit;
1470 // Reserve a buffer for the meta-data
1472 if (FAILED(hr=m_pEmitter->GetSaveSize(cssAccurate, &metaDataSize))) goto exit;
1474 if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, metaDataSize, sizeof(DWORD), (void**) &metaData))) goto exit;
1475 ULONG metaDataOffset;
1476 if (FAILED(hr=m_pCeeFileGen->GetSectionDataLen(m_pILSection, &metaDataOffset))) goto exit;
1477 metaDataOffset -= metaDataSize;
1478 // set managed resource entry, if any
1479 if(m_pManifest && m_pManifest->m_dwMResSizeTotal)
1481 mresourceSize = m_pManifest->m_dwMResSizeTotal;
1483 if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, mresourceSize,
1484 sizeof(DWORD), (void**) &mresourceData))) goto exit;
1485 if (FAILED(hr=m_pCeeFileGen->SetManifestEntry(m_pCeeFile, mresourceSize, 0))) goto exit;
1487 if(m_VTFList.COUNT())
1489 GlobalLabel *pGlobalLabel;
1490 VTFEntry* pVTFEntry;
1492 if(m_pVTable) delete m_pVTable; // can't have both; list takes precedence
1493 m_pVTable = new BinStr();
1495 for(WORD k=0; (pVTFEntry = m_VTFList.POP()); k++)
1497 if((pGlobalLabel = FindGlobalLabel(pVTFEntry->m_szLabel)))
1501 m_pVTable->appendInt32(pGlobalLabel->m_GlobalOffset);
1502 m_pVTable->appendInt16(pVTFEntry->m_wCount);
1503 m_pVTable->appendInt16(pVTFEntry->m_wType);
1504 for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
1506 for(WORD j = 0; (pMD = pClass->m_MethodList.PEEK(j)); j++)
1508 if(pMD->m_wVTEntry == k+1)
1511 if(SUCCEEDED(hr = m_pCeeFileGen->ComputeSectionPointer(m_pGlobalDataSection,pGlobalLabel->m_GlobalOffset,&ptr)))
1514 if((pVTFEntry->m_wType & COR_VTABLE_32BIT))
1516 dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(DWORD);
1518 DWORD* mptr = (DWORD*)ptr;
1519 *mptr = (DWORD)(pMD->m_Tok);
1523 dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(ULONGLONG);
1525 ULONGLONG* mptr = (ULONGLONG*)ptr;
1526 *mptr = (ULONGLONG)(pMD->m_Tok);
1528 if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
1530 EATEntry* pEATE = new EATEntry;
1531 pEATE->dwOrdinal = pMD->m_dwExportOrdinal;
1532 pEATE->szAlias = pMD->m_szExportAlias ? pMD->m_szExportAlias : pMD->m_szName;
1533 pEATE->dwStubRVA = EmitExportStub(pGlobalLabel->m_GlobalOffset+dwDelta);
1534 m_EATList.PUSH(pEATE);
1538 report->msg("Error: Failed to get pointer to label '%s' inVTable fixup\n",pVTFEntry->m_szLabel);
1545 report->msg("Error: Unresolved label '%s' in VTable fixup\n",pVTFEntry->m_szLabel);
1550 if(FAILED(hr)) goto exit;
1554 ULONG i, N = m_pVTable->length()/sizeof(DWORD);
1555 ULONG ulVTableOffset;
1556 m_pCeeFileGen->GetSectionDataLen (m_pILSection, &ulVTableOffset);
1557 // SetVTableEntry will align VTable on DWORD
1558 ulVTableOffset = (ulVTableOffset + (ULONG)sizeof(DWORD) - 1) & ~((ULONG)sizeof(DWORD) - 1);
1559 if (FAILED(hr=m_pCeeFileGen->SetVTableEntry64(m_pCeeFile, m_pVTable->length(),(void*)(m_pVTable->ptr())))) goto exit; // @WARNING: casting down from pointer-size to DWORD
1560 for(i = 0; i < N; i+=2)
1562 m_pCeeFileGen->AddSectionReloc(m_pILSection,
1563 ulVTableOffset+(i*sizeof(DWORD)),
1564 m_pGlobalDataSection,
1568 if(m_EATList.COUNT())
1570 if(FAILED(CreateExportDirectory())) goto exit;
1571 m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY;
1572 if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
1573 COR_SET_32BIT_REQUIRED(m_dwComImageFlags);
1577 if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, 2, 10))) goto exit;
1579 if (FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, 0x10000))) goto exit;
1583 if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM || m_fAppContainer)
1585 // For AppContainer and ARM, you must have a minimum subsystem version of 6.02
1586 m_wSSVersionMajor = (m_wSSVersionMajor < 6) ? 6 : m_wSSVersionMajor;
1587 m_wSSVersionMinor = (m_wSSVersionMinor < 2 && m_wSSVersionMajor <= 6) ? 2 : m_wSSVersionMinor;
1591 // Default the subsystem, instead the user doesn't set it to GUI or CUI
1592 if (m_dwSubsystem == (DWORD)-1)
1593 // The default for ILAsm previously was CUI, so that should be the default behavior...
1594 m_dwSubsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1596 if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, m_dwSubsystem, m_wSSVersionMajor, m_wSSVersionMinor))) goto exit;
1599 if (FAILED(hr=m_pCeeFileGen->ClearComImageFlags(m_pCeeFile, COMIMAGE_FLAGS_ILONLY))) goto exit;
1600 if (FAILED(hr=m_pCeeFileGen->SetComImageFlags(m_pCeeFile, m_dwComImageFlags & ~COMIMAGE_FLAGS_STRONGNAMESIGNED))) goto exit;
1602 if(m_dwFileAlignment)
1604 if(FAILED(hr=m_pCeeFileGen->SetFileAlignment(m_pCeeFile, m_dwFileAlignment))) goto exit;
1609 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1611 if(FAILED(hr=m_pCeeFileGen->SetImageBase64(m_pCeeFile, m_stBaseAddress))) goto exit;
1615 if(FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, (size_t)m_stBaseAddress))) goto exit;
1618 if(m_stSizeOfStackReserve || m_fAppContainer || m_fHighEntropyVA)
1620 PIMAGE_NT_HEADERS pNT;
1621 PIMAGE_SECTION_HEADER pSect;
1623 if(FAILED(hr=m_pCeeFileGen->GetHeaderInfo(m_pCeeFile,&pNT,&pSect,&ulNumSect))) goto exit;
1624 if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1626 PIMAGE_OPTIONAL_HEADER64 pOpt = (PIMAGE_OPTIONAL_HEADER64)(&pNT->OptionalHeader);
1627 if (m_stSizeOfStackReserve)
1628 pOpt->SizeOfStackReserve = VAL64(m_stSizeOfStackReserve);
1629 if (m_fAppContainer)
1630 pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_APPCONTAINER;
1631 if (m_fHighEntropyVA)
1632 pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
1636 PIMAGE_OPTIONAL_HEADER32 pOpt = (PIMAGE_OPTIONAL_HEADER32)(&pNT->OptionalHeader);
1637 if (m_stSizeOfStackReserve)
1638 pOpt->SizeOfStackReserve = (DWORD)VAL32(m_stSizeOfStackReserve);
1639 if (m_fAppContainer)
1640 pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_APPCONTAINER;
1641 if (m_fHighEntropyVA)
1642 pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
1645 //Compute all the RVAs
1646 if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
1648 // Fix up any fields that have RVA associated with them
1649 if (m_fHaveFieldsWithRvas) {
1651 ULONG dataSectionRVA;
1652 if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pGlobalDataSection, &dataSectionRVA))) goto exit;
1654 ULONG tlsSectionRVA;
1655 if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pTLSSection, &tlsSectionRVA))) goto exit;
1658 if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pILSection, &ilSectionRVA))) goto exit;
1660 FieldDescriptor* pListFD;
1662 for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
1664 for(int j=0; (pListFD = pClass->m_FieldDList.PEEK(j)); j++)
1666 if (pListFD->m_rvaLabel != 0)
1669 if(*(pListFD->m_rvaLabel)=='@')
1671 rva = (DWORD)atoi(pListFD->m_rvaLabel + 1);
1675 GlobalLabel *pLabel = FindGlobalLabel(pListFD->m_rvaLabel);
1678 report->msg("Error:Could not find label '%s' for the field '%s'\n", pListFD->m_rvaLabel, pListFD->m_szName);
1683 rva = pLabel->m_GlobalOffset;
1684 if (pLabel->m_Section == m_pTLSSection)
1685 rva += tlsSectionRVA;
1686 else if (pLabel->m_Section == m_pILSection)
1687 rva += ilSectionRVA;
1689 _ASSERTE(pLabel->m_Section == m_pGlobalDataSection);
1690 rva += dataSectionRVA;
1693 if (FAILED(m_pEmitter->SetFieldRVA(pListFD->m_fdFieldTok, rva))) goto exit;
1697 if (FAILED(hr)) goto exit;
1700 if(bClock) bClock->cFilegenBegin = GetTickCount();
1701 // actually output the meta-data
1702 if (FAILED(hr=m_pCeeFileGen->EmitMetaDataAt(m_pCeeFile, m_pEmitter, m_pILSection, metaDataOffset, metaData, metaDataSize))) goto exit;
1704 if((m_wMSVmajor < 0xFF)&&(m_wMSVminor < 0xFF))
1706 STORAGESIGNATURE *pSSig = (STORAGESIGNATURE *)metaData;
1707 BYTE* pb = metaData;
1708 pb += 3*sizeof(DWORD)+2*sizeof(WORD)+VAL32(pSSig->iVersionString);
1709 pb = (BYTE*)(((size_t)pb + 3) & ~3);
1710 PSTORAGEHEADER pSHdr = (PSTORAGEHEADER)pb;
1711 PSTORAGESTREAM pStr = (PSTORAGESTREAM)(pSHdr+1);
1712 for(short iStr = 1; iStr <= VAL16(pSHdr->iStreams); iStr++)
1714 if((strcmp(pStr->rcName,"#-")==0)||(strcmp(pStr->rcName,"#~")==0))
1716 pb = metaData + VAL32(pStr->iOffset); // start of the stream header
1717 pb += sizeof(DWORD); // skip Reserved
1718 *pb = VAL16(m_wMSVmajor)&0xFF;
1719 *(pb+1) = VAL16(m_wMSVminor)&0xFF;
1723 pb += 2*sizeof(DWORD)+strlen(pStr->rcName)+1;
1724 pb = (BYTE*)(((size_t)pb + 3) & ~3);
1725 pStr = (PSTORAGESTREAM)pb;
1729 if(m_fTolerateDupMethods) // means that there are /ENC files
1731 if(m_pbsMD) delete m_pbsMD;
1732 m_pbsMD = new BinStr();
1733 memcpy(m_pbsMD->getBuff(metaDataSize),metaData,metaDataSize);
1735 // actually output the resources
1736 if(mresourceSize && mresourceData)
1738 size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
1739 BYTE *ptr = (BYTE*)mresourceData;
1740 BOOL mrfail = FALSE;
1743 for(i=0; i < N; i++)
1745 m_pManifest->m_fMResNew[i] = FALSE;
1747 WszWideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
1748 L = m_pManifest->m_dwMResSize[i];
1750 memcpy(ptr,&L,sizeof(DWORD));
1751 ptr += sizeof(DWORD);
1752 if(fopen_s(&pFile,sz,"rb") == 0)
1754 sizeread = fread((void *)ptr,1,L,pFile);
1760 report->msg("Error: failed to open mgd resource file '%ls'\n",m_pManifest->m_wzMResName[i]);
1765 report->msg("Error: failed to read expected %d bytes from mgd resource file '%ls'\n",L,m_pManifest->m_wzMResName[i]);
1779 if((m_wRTVmajor < 0xFFFF)&&(m_wRTVminor < 0xFFFF))
1781 IMAGE_COR20_HEADER* pCorH;
1782 if(FAILED(hr=m_pCeeFileGen->GetCorHeader(m_pCeeFile,&pCorH))) goto exit;
1783 pCorH->MajorRuntimeVersion = VAL16(m_wRTVmajor);
1784 pCorH->MinorRuntimeVersion = VAL16(m_wRTVminor);
1787 // Generate the file -- moved to main
1788 //if (FAILED(hr=m_pCeeFileGen->GenerateCeeFile(m_pCeeFile))) goto exit;
1797 #pragma warning(pop)