Open sourcing ILASM
[platform/upstream/coreclr.git] / src / ilasm / writer.cpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 
4 //
5 //
6 // writer.cpp
7 //
8
9 #include "ilasmpch.h"
10
11 #include "assembler.h"
12
13 #include "ceefilegenwriter.h"
14 #include "strongname.h"
15 #include "LegacyActivationShim.h"
16
17 #ifndef _MSC_VER
18 //cloned definition from ntimage.h that is removed for non MSVC builds
19 typedef VOID
20 (NTAPI *PIMAGE_TLS_CALLBACK) (
21     PVOID DllHandle,
22     ULONG Reason,
23     PVOID Reserved
24     );
25 #endif //_MSC_VER
26
27
28 HRESULT Assembler::InitMetaData()
29 {
30     HRESULT             hr = E_FAIL;
31
32     if(m_fInitialisedMetaData) return S_OK;
33
34     if(bClock) bClock->cMDInitBegin = GetTickCount();
35
36     hr = LegacyActivationShim::ClrCoCreateInstance(
37         CLSID_CorMetaDataDispenser, 
38         NULL, 
39         CLSCTX_INPROC_SERVER, 
40         IID_IMetaDataDispenserEx, 
41         (void **)&m_pDisp);
42     if (FAILED(hr))
43         goto exit;
44
45     if(m_wzMetadataVersion)
46     {
47         VARIANT encOption;
48         BSTR    bstr;
49         V_VT(&encOption) = VT_BSTR;
50         V_BSTR(&encOption) = bstr = ::SysAllocString(m_wzMetadataVersion);
51         hr = m_pDisp->SetOption(MetaDataRuntimeVersion, &encOption);
52         ::SysFreeString(bstr);
53     }
54     hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit2,
55                         (IUnknown **)&m_pEmitter);
56     if (FAILED(hr))
57         goto exit;
58
59     m_pManifest->SetEmitter(m_pEmitter);
60     if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataImport2, (void**)&m_pImporter)))
61         goto exit;
62
63     hr = CoCreateInstance(CLSID_CorSymWriter_SxS,
64                            NULL,
65                            CLSCTX_INPROC_SERVER,
66                            IID_ISymUnmanagedWriter,
67                            (void **)&m_pSymWriter);
68     if(SUCCEEDED(hr))
69     {
70         if(m_pSymWriter) m_pSymWriter->Initialize((IUnknown*)m_pEmitter,
71                                                   m_wzOutputFileName,
72                                                   NULL,
73                                                   TRUE);
74     }
75     else
76     {
77         fprintf(stderr, "Error: QueryInterface(IID_ISymUnmanagedWriter) returns %X\n",hr);
78         m_pSymWriter = NULL;
79     }
80
81     //m_Parser = new AsmParse(m_pEmitter);
82     m_fInitialisedMetaData = TRUE;
83
84     hr = S_OK;
85
86 exit:
87     if(bClock) bClock->cMDInitEnd = GetTickCount();
88     return hr;
89 }
90 /*********************************************************************************/
91 /* if we have any Thread local store data, make the TLS directory record for it */
92
93 HRESULT Assembler::CreateTLSDirectory() {
94
95     ULONG tlsEnd;
96     HRESULT hr;
97     if (FAILED(hr=m_pCeeFileGen->GetSectionDataLen(m_pTLSSection, &tlsEnd))) return(hr);
98
99     if (tlsEnd == 0)        // No TLS data, we are done
100         return(S_OK);
101
102         // place to put the TLS directory
103     HCEESECTION tlsDirSec = m_pGlobalDataSection;
104
105     if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32)
106     {
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);
113
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];
118         *callBackChain = 0;
119     
120             // Find out where the tls directory will end up
121         ULONG tlsDirOffset;
122         if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsDirOffset))) return(hr);
123         tlsDirOffset -= (sizeofdir + sizeofptr);
124     
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);
128     
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);
132     
133             // Allocate space for the OS to put the TLS index for this PE file (needs to be Read/Write?)
134         DWORD* tlsIndex;
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
137     
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);
142     
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);
146     
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);
150         
151             // Set the other fields.
152         tlsDir->SizeOfZeroFill = 0;
153         tlsDir->Characteristics = 0;
154     
155         hr=m_pCeeFileGen->SetDirectoryEntry (m_pCeeFile, tlsDirSec, IMAGE_DIRECTORY_ENTRY_TLS,
156             sizeofdir, tlsDirOffset);
157
158         if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
159             COR_SET_32BIT_REQUIRED(m_dwComImageFlags);
160     }
161     else
162     {
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);
169
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];
174         *callBackChain = 0;
175     
176             // Find out where the tls directory will end up
177         ULONG tlsDirOffset;
178         if(FAILED(hr=m_pCeeFileGen->GetSectionDataLen(tlsDirSec, &tlsDirOffset))) return(hr);
179         tlsDirOffset -= (sizeofdir + sizeofptr);
180     
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);
184     
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);
188     
189             // Allocate space for the OS to put the TLS index for this PE file (needs to be Read/Write?)
190         DWORD* tlsIndex;
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
193     
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);
198     
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);
202     
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);
206         
207             // Set the other fields.
208         tlsDir->SizeOfZeroFill = 0;
209         tlsDir->Characteristics = 0;
210     
211         hr=m_pCeeFileGen->SetDirectoryEntry (m_pCeeFile, tlsDirSec, IMAGE_DIRECTORY_ENTRY_TLS,
212             sizeofdir, tlsDirOffset);
213     }
214
215     if(m_dwCeeFileFlags & ICEE_CREATE_FILE_STRIP_RELOCS)
216     {
217         report->error("Base relocations are emitted, while /STRIPRELOC option has been specified");
218     }
219     m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY;
220
221     return(hr);
222 }
223
224 HRESULT Assembler::CreateDebugDirectory()
225 {
226     HRESULT hr = S_OK;
227
228     // Only emit this if we're also emitting debug info.
229     if (!(m_fGeneratePDB && m_pSymWriter))
230         return S_OK;
231
232     IMAGE_DEBUG_DIRECTORY  debugDirIDD;
233     struct Param
234     {
235     DWORD                  debugDirDataSize;
236         BYTE              *debugDirData;
237     } param;
238     param.debugDirData = NULL;
239
240     // Get the debug info from the symbol writer.
241     if (FAILED(hr=m_pSymWriter->GetDebugInfo(NULL, 0, &param.debugDirDataSize, NULL)))
242         return hr;
243
244     // Will there even be any?
245     if (param.debugDirDataSize == 0)
246         return S_OK;
247
248     // Make some room for the data.
249     PAL_TRY(Param *, pParam, &param) {
250         pParam->debugDirData = new BYTE[pParam->debugDirDataSize];
251     } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
252         hr = E_FAIL;
253     } WIN_PAL_ENDTRY
254
255     if(FAILED(hr)) return hr;
256     // Actually get the data now.
257     if (FAILED(hr = m_pSymWriter->GetDebugInfo(&debugDirIDD,
258                                                param.debugDirDataSize,
259                                                NULL,
260                                                param.debugDirData)))
261         goto ErrExit;
262
263     // Grab the timestamp of the PE file.
264     DWORD fileTimeStamp;
265
266     if (FAILED(hr = m_pCeeFileGen->GetFileTimeStamp(m_pCeeFile,
267                                                     &fileTimeStamp)))
268         goto ErrExit;
269
270     // Fill in the directory entry.
271     debugDirIDD.TimeDateStamp = VAL32(fileTimeStamp);
272
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
276     // cs compiler).
277     HCEESECTION sec = m_pILSection;//m_pGlobalDataSection;
278     BYTE *de;
279
280     if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(sec,
281                                                    sizeof(debugDirIDD) +
282                                                    param.debugDirDataSize,
283                                                    4,
284                                                    (void**) &de)))
285         goto ErrExit;
286
287     // Where did we get that memory?
288     ULONG deOffset;
289     if (FAILED(hr = m_pCeeFileGen->GetSectionDataLen(sec,
290                                                      &deOffset)))
291         goto ErrExit;
292
293     deOffset -= (sizeof(debugDirIDD) + param.debugDirDataSize);
294
295     // Setup a reloc so that the address of the raw
296     // data is setup correctly.
297     debugDirIDD.PointerToRawData = VAL32(deOffset + sizeof(debugDirIDD));
298
299     if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(
300                                           sec,
301                                           deOffset +
302                                           offsetof(IMAGE_DEBUG_DIRECTORY,
303                                                    PointerToRawData),
304                                           sec, srRelocFilePos)))
305         goto ErrExit;
306
307     debugDirIDD.AddressOfRawData = VAL32(deOffset + sizeof(debugDirIDD));
308
309     if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(
310                                           sec,
311                                           deOffset +
312                                           offsetof(IMAGE_DEBUG_DIRECTORY,
313                                                    AddressOfRawData),
314                                           sec, srRelocAbsolute)))
315         goto ErrExit;
316     // Emit the directory entry.
317     if (FAILED(hr = m_pCeeFileGen->SetDirectoryEntry(m_pCeeFile,
318                                                      sec,
319                                                      IMAGE_DIRECTORY_ENTRY_DEBUG,
320                                                      sizeof(debugDirIDD),
321                                                      deOffset)))
322         goto ErrExit;
323
324     // Copy the debug directory into the section.
325     memcpy(de, &debugDirIDD, sizeof(debugDirIDD));
326     memcpy(de + sizeof(debugDirIDD), param.debugDirData,
327            param.debugDirDataSize);
328
329     if (param.debugDirData)
330     {
331         delete [] param.debugDirData;
332     }
333     return S_OK;
334
335 ErrExit:
336     if (param.debugDirData)
337     {
338         delete [] param.debugDirData;
339     }
340     return hr;
341 }
342 //#ifdef EXPORT_DIR_ENABLED
343 HRESULT Assembler::CreateExportDirectory()
344 {
345     HRESULT hr = S_OK;
346     DWORD   Nentries = m_EATList.COUNT();
347     if(Nentries == 0) return S_OK;
348
349     IMAGE_EXPORT_DIRECTORY  exportDirIDD;
350     DWORD                   exportDirDataSize;
351     BYTE                   *exportDirData;
352     EATEntry               *pEATE;
353     unsigned                i, L, ordBase = 0xFFFFFFFF, Ldllname;
354     // get the DLL name from output file name
355     char*                   pszDllName;
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;
364
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);
370
371     // Export address table
372     DWORD*  pEAT = (DWORD*)exportDirData;
373     // Name pointer table
374     DWORD*  pNPT = pEAT + Nentries;
375     // Ordinal table
376     WORD*   pOT = (WORD*)(pNPT + Nentries);
377     // Export name table
378     char*   pENT = (char*)(pOT + Nentries);
379     // DLL name
380     char*   pDLLName = pENT + L;
381
382     // sort the names/ordinals
383     char**  pAlias = new char*[Nentries];
384     for(i = 0; i < Nentries; i++)
385     {
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;
390     }
391     bool swapped = true;
392     unsigned j;
393     char*    pch;
394     while(swapped)
395     {
396         swapped = false;
397         for(i=1; i < Nentries; i++)
398         {
399             if(strcmp(pAlias[i-1],pAlias[i]) > 0)
400             {
401                 swapped = true;
402                 pch = pAlias[i-1];
403                 pAlias[i-1] = pAlias[i];
404                 pAlias[i] = pch;
405                 j = pOT[i-1];
406                 pOT[i-1] = pOT[i];
407                 pOT[i] = j;
408             }
409         }
410     }
411     // normalize ordinals
412     for(i = 0; i < Nentries; i++) pOT[i] -= ordBase;
413     // fill the export address table
414 #ifdef _PREFAST_
415 #pragma warning(push)
416 #pragma warning(disable:22008) // "Suppress PREfast warnings about integer overflow"
417 #endif
418     for(i = 0; i < Nentries; i++)
419     {
420         pEATE = m_EATList.PEEK(i);
421         pEAT[pEATE->dwOrdinal - ordBase] = pEATE->dwStubRVA;
422     }
423 #ifdef _PREFAST_
424 #pragma warning(pop)
425 #endif
426     // fill the export names table
427     unsigned l;
428     for(i = 0, j = 0; i < Nentries; i++)
429     {
430         pNPT[i] = j; // relative offset in the table
431         l = (unsigned)strlen(pAlias[i])+1;
432         memcpy(&pENT[j],pAlias[i],l);
433         j+=l;
434     }
435     _ASSERTE(j==L);
436     // fill the DLL name
437     memcpy(pDLLName,pszDllName,Ldllname);
438
439     // Data blob is ready pending Name Pointer Table values offsetting
440
441     memset(&exportDirIDD,0,sizeof(IMAGE_EXPORT_DIRECTORY));
442     // Grab the timestamp of the PE file.
443     DWORD fileTimeStamp;
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
455
456     // Grab memory in the section for our stuff.
457     HCEESECTION sec = m_pGlobalDataSection;
458     BYTE *de;
459     if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(sec,
460                                                    sizeof(IMAGE_EXPORT_DIRECTORY) + exportDirDataSize,
461                                                    4,
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;
466
467     deDataOffset -= exportDirDataSize;
468     deOffset = deDataOffset - sizeof(IMAGE_EXPORT_DIRECTORY);
469
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;
483
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++)
487     {
488         pNPT[i] += j;
489         if (FAILED(hr = m_pCeeFileGen->AddSectionReloc(sec,exportDirIDD.AddressOfNames+i*sizeof(DWORD),
490             sec, srRelocAbsolute))) return hr;
491     }
492
493
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;
497
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);
501     delete [] pAlias;
502     delete [] exportDirData;
503     return S_OK;
504 }
505
506 static const BYTE ExportStubAMD64Template[] = 
507 {
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]
512 };
513 static const BYTE ExportStubX86Template[] = 
514 {
515         // Jump through VTFixup table 
516         0xFF, 0x25,                             // jmp [following address]
517     0x00, 0x00, 0x00, 0x00  //address of VTFixup slot
518 };
519 static const WORD ExportStubARMTemplate[] = 
520 {
521         // Jump through VTFixup table
522     0xf8df, 0xf000,         // ldr pc, [pc, #0]
523     0x0000, 0x0000          //address of VTFixup slot
524 };
525
526 static const BYTE ExportStubIA64Template[] =
527 {
528     // ld8    r9  = [gp]    ;;
529     // ld8    r10 = [r9],8
530     // nop.i                ;;
531     // ld8    gp  = [r9]
532     // mov    b6  = r10
533     // br.cond.sptk.few  b6
534     //
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
541 };
542 DWORD   Assembler::EmitExportStub(DWORD dwVTFSlotRVA)
543 {
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;
548     DWORD PEFileOffset;
549     BYTE* outBuff;
550     DWORD*  pdwVTFSlotRVA;
551     if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_IA64)
552     {
553         STUB_TEMPLATE = (BYTE*)&ExportStubIA64Template[0];
554         EXPORT_STUB_SIZE = sizeof(ExportStubIA64Template);
555         OFFSET_OF_ADDR = 40;
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);
560     
561         // The offset where we start, (not where the alignment bytes start!)
562         if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) return 0;
563     
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
569     }
570     else
571     {
572         if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_AMD64)
573         {
574             STUB_TEMPLATE = (BYTE*)&ExportStubAMD64Template[0];
575             EXPORT_STUB_SIZE = sizeof(ExportStubAMD64Template);
576             OFFSET_OF_ADDR = 2;
577             STUB_ALIGNMENT = 4;
578         }
579         else if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
580         {
581             STUB_TEMPLATE = (BYTE*)&ExportStubX86Template[0];
582             EXPORT_STUB_SIZE = sizeof(ExportStubX86Template);
583             OFFSET_OF_ADDR = 2;
584         }
585         else if(m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM)
586         {
587             STUB_TEMPLATE = (BYTE*)&ExportStubARMTemplate[0];
588             EXPORT_STUB_SIZE = sizeof(ExportStubARMTemplate);
589             OFFSET_OF_ADDR = 4;
590             STUB_ALIGNMENT = 4;
591         }
592         else
593         {
594             report->error("Unmanaged exports are not implemented for unknown platform");
595             return NULL;
596         }
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))
600         {
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;
603             memset(outBuff,0,L);
604         }
605         
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);
610     
611         // The offset where we start, (not where the alignment bytes start!)
612         if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset))) return 0;
613     
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);
617     }
618     if(m_dwCeeFileFlags & ICEE_CREATE_FILE_STRIP_RELOCS)
619     {
620         report->error("Base relocations are emitted, while /STRIPRELOC option has been specified");
621     }
622     m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&PEFileOffset);
623     return PEFileOffset;
624 }
625 //#endif
626
627 HRESULT Assembler::GetCAName(mdToken tkCA, __out LPWSTR *ppszName)
628 {
629     HRESULT hr = S_OK;
630     DWORD cchName;
631     LPWSTR name;
632
633     *ppszName = NULL;
634
635     if (TypeFromToken(tkCA) == mdtMemberRef)
636     {
637         mdToken parent;
638         if (FAILED(hr = m_pImporter->GetMemberRefProps( tkCA, &parent, NULL, 0, NULL, NULL, NULL)))
639             return hr;
640         tkCA = parent;
641     }
642     else if (TypeFromToken(tkCA) == mdtMethodDef)
643     {
644         mdToken parent;
645         if (FAILED(hr = m_pImporter->GetMemberProps( tkCA, &parent, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)))
646             return hr;
647         tkCA = parent;
648     }
649
650     if (TypeFromToken(tkCA) == mdtTypeRef)
651     {
652         // A TypeRef
653         if (FAILED(hr = m_pImporter->GetTypeRefProps(tkCA, NULL, NULL, 0, &cchName)))
654             return hr;
655         if ((name = new WCHAR[cchName + 1]) == NULL)
656             return E_OUTOFMEMORY;
657         hr = m_pImporter->GetTypeRefProps(tkCA, NULL, name, cchName, &cchName);
658     }
659     else
660     {
661         hr = m_pImporter->GetTypeDefProps(tkCA, NULL, 0, &cchName, NULL, NULL);
662         if (hr != S_OK)
663             return hr;
664         if ((name = new WCHAR[cchName + 1]) == NULL)
665             return E_OUTOFMEMORY;
666         hr = m_pImporter->GetTypeDefProps(tkCA, name, cchName, &cchName, NULL, NULL);
667     }
668     if (SUCCEEDED(hr))
669         *ppszName = name;
670     else
671         delete [] name;
672     return hr;
673 }
674
675 BYTE HexToByte (CHAR wc)
676 {
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);
681 }
682
683 bool GetBytesFromHex (LPCSTR szPublicKeyHexString, ULONG cchPublicKeyHexString, BYTE** buffer, ULONG *cbBufferSize)
684 {
685     ULONG cchHex = cchPublicKeyHexString;
686     if (cchHex % 2 != 0)
687         return false;
688     *cbBufferSize = cchHex / 2;
689
690     *buffer = new BYTE[*cbBufferSize];
691     if (!*buffer)
692         return false;
693
694     for (ULONG i = 0; i < *cbBufferSize; i++)
695     {
696         BYTE msn = HexToByte(*szPublicKeyHexString);
697         BYTE lsn = HexToByte(*(szPublicKeyHexString + 1));
698         if (msn == 0xFF || lsn == 0xFF)
699         {
700             delete[] *buffer;
701             return false;
702         }
703
704         (*buffer)[i] = (BYTE) ( (msn << 4) | lsn );
705         szPublicKeyHexString += 2;
706     }
707
708     return true;
709 }
710
711 HRESULT Assembler::GetSignatureKey()
712 {
713     HRESULT     hr = S_OK;
714     ULONG        cbSize = 0;
715     void *            pvData = NULL;
716     LPWSTR      pName = NULL;
717     
718     CustomDescrList* pCDList = &m_pManifest->m_pAssembly->m_CustomDescrList;
719     
720     for (ULONG i = 0;i < pCDList->COUNT(); i++)
721     {
722         CustomDescr* pCD = pCDList->PEEK(i);
723
724         if(pCD->pBlob)
725         {
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);
730             
731             if (GetCAName(pCD->tkType, &pName) != S_OK)
732                 continue;
733
734             if (wcscmp(pName, L"System.Reflection.AssemblySignatureKeyAttribute") == 0)
735             {
736                     if (cbSize < sizeof(WORD) || GET_UNALIGNED_VAL16(pvData) != 1)
737                     {
738                         hr = E_FAIL;
739                         break;;
740                     }
741                     pvData = (unsigned char *)pvData  + sizeof(WORD);
742                     cbSize -= sizeof(WORD);
743                     
744                     // String is stored as compressed length, UTF8.
745                     if (*(const BYTE*)pvData != 0xFF)
746                     {
747                         PCCOR_SIGNATURE sig = (PCCOR_SIGNATURE)pvData;
748                         cbSize -= CorSigUncompressedDataSize(sig);
749                         DWORD len = CorSigUncompressData(sig);
750                         pvData = (void *)sig;
751                         if (cbSize < len)
752                         {
753                             hr = E_FAIL;
754                             break;
755                         }
756
757                         AsmManStrongName   *pSN = &m_pManifest->m_sStrongName;
758                         GetBytesFromHex((LPCSTR)pvData, len, &pSN->m_pbSignatureKey, &pSN->m_cbSignatureKey);
759                     }
760                     
761                     break;
762             }
763             
764             if (pName)
765             {
766                 delete pName;
767                 pName = NULL;
768             }
769         }
770     }
771
772     if (pName)
773         delete pName;
774     return hr;
775 }
776
777 HRESULT Assembler::AllocateStrongNameSignature()
778 {
779     HRESULT             hr = S_OK;
780     HCEESECTION         hSection;
781     DWORD               dwDataLength;
782     DWORD               dwDataOffset;
783     DWORD               dwDataRVA;
784     VOID               *pvBuffer;
785     AsmManStrongName   *pSN = &m_pManifest->m_sStrongName;
786
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()))
790     {
791         return hr;
792     }
793
794    // Determine size of signature blob.
795     if (pSN->m_pbSignatureKey != NULL)
796     {
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, 
801             &dwDataLength)))
802          {
803             return hr;
804         }
805     }
806     else if (FAILED(hr = LegacyActivationShim::StrongNameSignatureSize_HRESULT(
807             pSN->m_pbPublicKey, 
808             pSN->m_cbPublicKey, 
809             &dwDataLength)))
810     {
811         return hr;
812     }
813
814     // Grab memory in the section for our stuff.
815     if (FAILED(hr = m_pCeeFileGen->GetIlSection(m_pCeeFile,
816                                                 &hSection)))
817         return hr;
818
819     if (FAILED(hr = m_pCeeFileGen->GetSectionBlock(hSection,
820                                                    dwDataLength,
821                                                    4,
822                                                    &pvBuffer)))
823         return hr;
824
825     // Where did we get that memory?
826     if (FAILED(hr = m_pCeeFileGen->GetSectionDataLen(hSection,
827                                                      &dwDataOffset)))
828         return hr;
829
830     dwDataOffset -= dwDataLength;
831
832     // Convert to an RVA.
833     if (FAILED(hr = m_pCeeFileGen->GetMethodRVA(m_pCeeFile,
834                                                 dwDataOffset,
835                                                 &dwDataRVA)))
836         return hr;
837
838     // Emit the directory entry.
839     if (FAILED(hr = m_pCeeFileGen->SetStrongNameEntry(m_pCeeFile,
840                                                       dwDataLength,
841                                                       dwDataRVA)))
842         return hr;
843
844     return S_OK;
845 }
846
847 HRESULT Assembler::StrongNameSign()
848 {
849     LPWSTR              wszOutputFile;
850     HRESULT             hr = S_OK;
851     AsmManStrongName   *pSN = &m_pManifest->m_sStrongName;
852
853     // Determine what the ouput PE was called.
854     if (FAILED(hr = m_pCeeFileGen->GetOutputFileName(m_pCeeFile,
855                                                      &wszOutputFile)))
856         return hr;
857
858     // Update the output PE image with a strong name signature.
859     if (FAILED(hr = LegacyActivationShim::StrongNameSignatureGeneration_HRESULT(
860         wszOutputFile, 
861         pSN->m_wzKeyContainer, 
862         pSN->m_pbPrivateKey, 
863         pSN->m_cbPrivateKey, 
864         NULL, 
865         NULL)))
866     {
867         return hr;
868     }
869
870     return S_OK;
871 }
872
873 BOOL Assembler::EmitFieldsMethods(Class* pClass)
874 {
875     unsigned n;
876     BOOL ret = TRUE;
877     // emit all field definition metadata tokens
878     if((n = pClass->m_FieldDList.COUNT()))
879     {
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
883         {
884             if(!EmitField(pFD))
885             {
886                 if(!OnErrGo) return FALSE;
887                 ret = FALSE;
888             }
889             pFD->m_fNew = FALSE;
890         }
891     }
892     // Fields are emitted; emit the class layout
893     {
894         COR_FIELD_OFFSET *pOffsets = NULL;
895         ULONG ul = pClass->m_ulPack;
896         ULONG N = pClass->m_dwNumFieldsWithOffset;
897
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))
904         {
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);
908             if(N)
909             {
910                 pOffsets = new COR_FIELD_OFFSET[N+1];
911                 ULONG i,j=0;
912                 FieldDescriptor *pFD;
913                 for(i=0; (pFD = pClass->m_FieldDList.PEEK(i)); i++)
914                 {
915                     if(pFD->m_ulOffset != 0xFFFFFFFF)
916                     {
917                         pOffsets[j].ridOfField = RidFromToken(pFD->m_fdFieldTok);
918                         pOffsets[j].ulOffset = pFD->m_ulOffset;
919                         j++;
920                     }
921                 }
922                 _ASSERTE(j == N);
923                 pOffsets[j].ridOfField = mdFieldDefNil;
924             }
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;
931         }
932     }
933     // emit all method definition metadata tokens
934     if((n = pClass->m_MethodList.COUNT()))
935     {
936         Method* pMethod;
937
938         if(m_fReportProgress) printf("Methods: %d;\t",n);
939         for(int i=0; (pMethod = pClass->m_MethodList.PEEK(i));i++)
940         {
941             if(!EmitMethod(pMethod))
942             {
943                 if(!OnErrGo) return FALSE;
944                 ret = FALSE;
945             }
946             pMethod->m_fNew = FALSE;
947         }
948     }
949     if(m_fReportProgress) printf("\n");
950     return ret;
951 }
952
953 HRESULT Assembler::ResolveLocalMemberRefs()
954 {
955     unsigned ulTotal=0, ulDefs=0, ulRefs=0, ulUnres=0;
956     MemberRefDList* pList[2] = {&m_LocalMethodRefDList,&m_LocalFieldRefDList};
957
958     if(pList[0]->COUNT() + pList[1]->COUNT())
959     {
960         MemberRefDescriptor*    pMRD;
961         mdToken         tkMemberDef = 0;
962         int i,j,k;
963         Class   *pSearch;
964
965         if(m_fReportProgress) printf("Resolving local member refs: ");
966         for(k=0; k<2; k++)
967         {
968             for(i=0; (pMRD = pList[k]->PEEK(i)) != NULL; i++)
969             {
970                 if(pMRD->m_tkResolved) continue;
971
972                 tkMemberDef = 0;
973                 Method* pListMD;
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);
978                 CQuickBytes     qbSig;
979
980                 ulTotal++;
981
982                 pSearch = 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))
987                 {
988                     report->msg("Error: bad parent 0x%08X of local member ref '%s'\n",
989                         pMRD->m_tdClass,pMRD->m_szName);
990                 }
991                 if(pSearch)
992                 {
993                     // MemberRef may reference a method or a field
994                     if(k==0) //methods
995                     {
996                         if((*pMRD_pSig & IMAGE_CEE_CS_CALLCONV_MASK)==IMAGE_CEE_CS_CALLCONV_VARARG)
997                         {
998                             ULONG L;
999                             qbSig.Shrink(0);
1000                             _GetFixedSigOfVarArg(pMRD_pSig,pMRD_dwCSig,&qbSig,&L);
1001                             pMRD_pSig = (PCOR_SIGNATURE)(qbSig.Ptr());
1002                             pMRD_dwCSig = L;
1003                         }
1004                         for(j=0; (pListMD = pSearch->m_MethodList.PEEK(j)) != NULL; j++)
1005                         {
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;
1011                             ulDefs++;
1012                             break;
1013                         }
1014                         if(tkMemberDef && ((*pMRD_pSig & IMAGE_CEE_CS_CALLCONV_MASK)==IMAGE_CEE_CS_CALLCONV_VARARG))
1015                         {
1016                             WszMultiByteToWideChar(g_uCodePage,0,pMRD_szName,-1,wzUniBuf,dwUniBuf);
1017
1018                             if(IsMdPrivateScope(pListMD->m_Attr))
1019                             {
1020                                 WCHAR* p = wcsstr(wzUniBuf,L"$PST06");
1021                                 if(p) *p = 0;
1022                             }
1023
1024                             m_pEmitter->DefineMemberRef(tkMemberDef, wzUniBuf,
1025                                                              pMRD->m_pSigBinStr->ptr(),
1026                                                              pMRD->m_pSigBinStr->length(),
1027                                                              &tkMemberDef);
1028                             ulDefs--;
1029                             ulRefs++;
1030                         }
1031                     }
1032                     else   // fields
1033                     {
1034                         FieldDescriptor* pListFD;
1035                         for(j=0; (pListFD = pSearch->m_FieldDList.PEEK(j)) != NULL; j++)
1036                         {
1037                             if(pListFD->m_dwName != pMRD_dwName) continue;
1038                             if(strcmp(pListFD->m_szName,pMRD_szName)) continue;
1039                             if(pListFD->m_pbsSig)
1040                             {
1041                                 if(pListFD->m_pbsSig->length()  != pMRD_dwCSig)  continue;
1042                                 if(memcmp(pListFD->m_pbsSig->ptr(),pMRD_pSig,pMRD_dwCSig)) continue;
1043                             }
1044                             else if(pMRD_dwCSig) continue;
1045                             tkMemberDef = pListFD->m_fdFieldTok;
1046                             ulDefs++;
1047                             break;
1048                         }
1049                     }
1050                 }
1051                 if(tkMemberDef==0)
1052                 { // could not resolve ref to def, make new ref and leave it this way
1053                     if((pSearch = pMRD->m_pClass) != NULL)
1054                     {
1055                         mdToken tkRef = MakeTypeRef(1,pSearch->m_szFQN);
1056
1057                         if(RidFromToken(tkRef))
1058                         {
1059                             WszMultiByteToWideChar(g_uCodePage,0,pMRD_szName,-1,wzUniBuf,dwUniBuf);
1060
1061                             m_pEmitter->DefineMemberRef(tkRef, wzUniBuf, pMRD_pSig,
1062                                 pMRD_dwCSig, &tkMemberDef);
1063                             ulRefs++;
1064                         }
1065                         else
1066                         {
1067                             report->msg("Error: unresolved member ref '%s' of class 0x%08X\n",pMRD->m_szName,pMRD->m_tdClass);
1068                             ulUnres++;
1069                         }
1070                     }
1071                     else
1072                     {
1073                         report->msg("Error: unresolved global member ref '%s'\n",pMRD->m_szName);
1074                         ulUnres++;
1075                     }
1076                 }
1077                 pMRD->m_tkResolved = tkMemberDef;
1078             }
1079         }
1080         for(i=0; (pMRD = m_MethodSpecList.PEEK(i)) != NULL; i++)
1081         {
1082             if(pMRD->m_tkResolved) continue;
1083             tkMemberDef = pMRD->m_tdClass;
1084             if(TypeFromToken(tkMemberDef)==0x99000000)
1085             {
1086                 tkMemberDef = m_LocalMethodRefDList.PEEK(RidFromToken(tkMemberDef)-1)->m_tkResolved;
1087                 if((TypeFromToken(tkMemberDef)==mdtMethodDef)||(TypeFromToken(tkMemberDef)==mdtMemberRef))
1088                 {
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));
1092                     if(FAILED(hr))
1093                         report->error("Unable to define method instantiation");
1094                 }
1095             }
1096             if(RidFromToken(pMRD->m_tkResolved)) ulDefs++;
1097             else ulUnres++;
1098         }
1099         if(m_fReportProgress) printf("%d -> %d defs, %d refs, %d unresolved\n",ulTotal,ulDefs,ulRefs,ulUnres);
1100     }
1101     return (ulUnres ? E_FAIL : S_OK);
1102 }
1103
1104 HRESULT Assembler::DoLocalMemberRefFixups()
1105 {
1106     MemberRefDList* pList;
1107     unsigned    Nlmr = m_LocalMethodRefDList.COUNT() + m_LocalFieldRefDList.COUNT(),
1108                 Nlmrf = m_LocalMemberRefFixupList.COUNT();
1109     HRESULT     hr = S_OK;
1110     if(Nlmr)
1111     {
1112         MemberRefDescriptor* pMRD;
1113         LocalMemberRefFixup* pMRF;
1114         int i;
1115         for(i = 0; (pMRF = m_LocalMemberRefFixupList.PEEK(i)) != NULL; i++)
1116         {
1117             if(m_fENCMode && (!pMRF->m_fNew)) continue;
1118
1119             switch(TypeFromToken(pMRF->tk))
1120             {
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;
1125             }
1126             if(pList)
1127             {
1128                 if((pMRD = pList->PEEK(RidFromToken(pMRF->tk)-1)) != NULL)
1129                     SET_UNALIGNED_VAL32((void *)(pMRF->offset), pMRD->m_tkResolved);
1130                 else
1131                 {
1132                     report->msg("Error: bad local member ref token 0x%08X in LMR fixup\n",pMRF->tk);
1133                     hr = E_FAIL;
1134                 }
1135             }
1136             pMRF->m_fNew = FALSE;
1137         }
1138     }
1139     else if(Nlmrf)
1140     {
1141         report->msg("Error: %d local member ref fixups, no local member refs\n",Nlmrf);
1142         hr = E_FAIL;
1143     }
1144     return hr;
1145 }
1146 void Assembler::EmitUnresolvedCustomAttributes()
1147 {
1148     CustomDescr *pCD;
1149     while((pCD = m_CustomDescrList.POP()) != NULL)
1150     {
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));
1157     }
1158 }
1159
1160 BOOL Assembler::EmitEventsProps(Class* pClass)
1161 {
1162     unsigned n;
1163     BOOL ret = TRUE;
1164     // emit all event definition metadata tokens
1165     if((n = pClass->m_EventDList.COUNT()))
1166     {
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
1170         {
1171             if(!EmitEvent(pED))
1172             {
1173                 if(!OnErrGo) return FALSE;
1174                 ret = FALSE;
1175             }
1176             pED->m_fNew = FALSE;
1177         }
1178     }
1179     // emit all property definition metadata tokens
1180     if((n = pClass->m_PropDList.COUNT()))
1181     {
1182         if(m_fReportProgress) printf("Props: %d;\t",n);
1183         PropDescriptor* pPD;
1184
1185         for(int j=0; (pPD = pClass->m_PropDList.PEEK(j)); j++)
1186         {
1187             if(!EmitProp(pPD))
1188             {
1189                 if(!OnErrGo) return FALSE;
1190                 ret = FALSE;
1191             }
1192             pPD->m_fNew = FALSE;
1193         }
1194     }
1195     if(m_fReportProgress) printf("\n");
1196     return ret;
1197 }
1198
1199 #ifdef _PREFAST_
1200 #pragma warning(push)
1201 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1202 #endif
1203 HRESULT Assembler::CreatePEFile(__in __nullterminated WCHAR *pwzOutputFilename)
1204 {
1205     HRESULT             hr;
1206     DWORD               mresourceSize = 0;
1207     BYTE*               mresourceData = NULL;
1208     WCHAR*              wzScopeName = NULL;
1209
1210     if(bClock) bClock->cMDEmitBegin = GetTickCount();
1211     if(m_fReportProgress) printf("Creating PE file\n");
1212     if (!m_pEmitter)
1213     {
1214         printf("Error: Cannot create a PE file with no metadata\n");
1215         return E_FAIL;
1216     }
1217     if(!(m_fDLL || m_fEntryPointPresent))
1218     {
1219         printf("Error: No entry point declared for executable\n");
1220         if(!OnErrGo) return E_FAIL;
1221     }
1222
1223     if(bClock) bClock->cMDEmit1 = GetTickCount();
1224
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()))
1229             goto exit;
1230     if(bClock) bClock->cMDEmit2 = GetTickCount();
1231
1232     if(m_VTFList.COUNT()==0)
1233     {
1234         Method* pMD;
1235         Class* pClass;
1236         unsigned N=0, OrdBase=0xFFFFFFFF, i, j;
1237         for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
1238         {
1239             for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
1240             {
1241                 if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
1242                 {
1243                     N++;
1244                     if(pMD->m_dwExportOrdinal < OrdBase) OrdBase = pMD->m_dwExportOrdinal;
1245                 }
1246             }
1247         }
1248         if(N)
1249         {
1250             for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
1251             {
1252                 for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
1253                 {
1254                     if(pMD->m_wVTSlot >= 0x8000)
1255                     {
1256                         pMD->m_wVTSlot -= 0x8000 + OrdBase - 1;
1257                     }
1258                 }
1259             }
1260             SetDataSection();
1261             char* sz = new char[20];
1262             strcpy_s(sz,20,"VTF_EAT_internal");
1263             EmitDataLabel(sz);
1264             sz = new char[20];
1265             strcpy_s(sz,20,"VTF_EAT_internal");
1266             if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1267             {
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));
1272                 delete [] pdw;
1273             }
1274             else
1275             {
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));
1280                 delete [] pdw;
1281             }
1282         }
1283     }
1284     wzScopeName=&wzUniBuf[0];
1285     if(m_szScopeName[0]) // default: scope name = output file name
1286     {
1287         WszMultiByteToWideChar(g_uCodePage,0,m_szScopeName,-1,wzScopeName,MAX_SCOPE_LENGTH);
1288     }
1289     else
1290     {
1291         WCHAR* pwc;
1292         if ((pwc = wcsrchr(m_wzOutputFileName, '\\')) != NULL) pwc++;
1293         else if ((pwc = wcsrchr(m_wzOutputFileName, ':')) != NULL) pwc++;
1294         else pwc = m_wzOutputFileName;
1295
1296         wcsncpy_s(wzScopeName, MAX_SCOPE_LENGTH, pwc, _TRUNCATE);
1297     }
1298     hr = m_pEmitter->SetModuleProps(wzScopeName);
1299
1300     if (FAILED(hr))
1301         goto exit;
1302
1303     EmitImports();
1304     if(m_pManifest)
1305     {
1306         hr = S_OK;
1307         if(m_pManifest->m_pAsmEmitter==NULL)
1308             hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));
1309
1310         if(SUCCEEDED(hr))
1311         {
1312             m_pManifest->EmitAssemblyRefs();
1313         }
1314     }
1315     // Emit classes, class members and globals:
1316     {
1317         Class *pSearch;
1318         int i;
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>
1322         {
1323             if(m_fReportProgress)
1324                 printf("Class %d:\t%s\n",i,pSearch->m_szFQN);
1325
1326             if(pSearch->m_bIsMaster)
1327             {
1328                 report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
1329                 bIsUndefClass = TRUE;
1330             }
1331             if(!EmitClass(pSearch))
1332             {
1333                 if(!OnErrGo) return E_FAIL;
1334             }
1335             pSearch->m_fNew = FALSE;
1336         }
1337         if(bIsUndefClass && !OnErrGo) return E_FAIL;
1338
1339         if(m_fReportProgress)   printf("\nEmitting fields and methods:\n");
1340         for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
1341         {
1342             if(m_fReportProgress)
1343             {
1344                 if(i == 0)  printf("Global \t");
1345                 else        printf("Class %d\t",i);
1346             }
1347             if(!EmitFieldsMethods(pSearch))
1348             {
1349                 if(!OnErrGo) return E_FAIL;
1350             }
1351         }
1352     }
1353
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;
1359
1360     // Local member refs resolved, emit events, props and method impls
1361     {
1362         Class *pSearch;
1363         int i;
1364
1365         if(m_fReportProgress)   printf("\nEmitting events and properties:\n");
1366         for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
1367         {
1368             if(m_fReportProgress)
1369             {
1370                 if(i == 0)  printf("Global \t");
1371                 else        printf("Class %d\t",i);
1372             }
1373             if(!EmitEventsProps(pSearch))
1374             {
1375                 if(!OnErrGo) return E_FAIL;
1376             }
1377             pSearch->m_fNewMembers = FALSE;
1378         }
1379     }
1380     if(bClock) bClock->cMDEmit3 = GetTickCount();
1381     if(m_MethodImplDList.COUNT())
1382     {
1383         if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
1384         if(!EmitMethodImpls())
1385         {
1386             if(!OnErrGo) return E_FAIL;
1387         }
1388     }
1389     // Emit the rest of the metadata
1390     if(bClock) bClock->cMDEmit4 = GetTickCount();
1391     hr = S_OK;
1392     if(m_pManifest)
1393     {
1394         if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
1395     }
1396     ResolveLocalMemberRefs(); // in case CAs added some
1397     EmitUnresolvedCustomAttributes();
1398     // Emit typedefs as special TypeSpecs
1399     {
1400 #define ELEMENT_TYPE_TYPEDEF ELEMENT_TYPE_MAX+1
1401         TypeDefDescr* pTDD;
1402         unsigned __int8* pb;
1403         unsigned namesize;
1404         while((pTDD = m_TypeDefDList.POP()))
1405         {
1406             BinStr* pbs = new BinStr();
1407             if(pbs)
1408             {
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)
1416                 {
1417                     CustomDescr* pCA = pTDD->m_pCA;
1418                     pbs->appendInt32(pCA->tkType);
1419                     pbs->appendInt32(pCA->tkOwner);
1420                     if(pCA->pBlob) pbs->append(pCA->pBlob);
1421                 }
1422                 ResolveTypeSpec(pbs);
1423                 delete pbs;
1424             }
1425             delete pTDD;
1426         }
1427     }
1428     if(bClock) bClock->cMDEmitEnd = GetTickCount();
1429
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.
1433     {
1434         Class* pClass;
1435         Method* pMethod;
1436         for (int i=0; (pClass = m_lstClass.PEEK(i)); i++)
1437         {
1438             for(int j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
1439             {
1440                 if(!EmitMethodBody(pMethod,NULL))
1441                 {
1442                     report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
1443                     hr = E_FAIL;
1444                     if(!OnErrGo) goto exit;
1445                 }
1446                 pMethod->m_fNewBody = FALSE;
1447             }
1448         }
1449         //while(MethodBody* pMB = m_MethodBodyList.POP()) delete pMB;
1450     }
1451
1452     if (DoGlobalFixups() == FALSE)
1453         return E_FAIL;
1454
1455     if(m_wzResourceFile)
1456     {
1457         if (FAILED(hr=m_pCeeFileGen->SetResourceFileName(m_pCeeFile, m_wzResourceFile)))
1458         {
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);
1461         }
1462     }
1463
1464     if (FAILED(hr=CreateTLSDirectory())) goto exit;
1465
1466     if (FAILED(hr=CreateDebugDirectory())) goto exit;
1467
1468     if (FAILED(hr=m_pCeeFileGen->SetOutputFileName(m_pCeeFile, pwzOutputFilename))) goto exit;
1469
1470         // Reserve a buffer for the meta-data
1471     DWORD metaDataSize;
1472     if (FAILED(hr=m_pEmitter->GetSaveSize(cssAccurate, &metaDataSize))) goto exit;
1473     BYTE* metaData;
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)
1480     {
1481         mresourceSize = m_pManifest->m_dwMResSizeTotal;
1482
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;
1486     }
1487     if(m_VTFList.COUNT())
1488     {
1489         GlobalLabel *pGlobalLabel;
1490         VTFEntry*   pVTFEntry;
1491
1492         if(m_pVTable) delete m_pVTable; // can't have both; list takes precedence
1493         m_pVTable = new BinStr();
1494         hr = S_OK;
1495         for(WORD k=0; (pVTFEntry = m_VTFList.POP()); k++)
1496         {
1497             if((pGlobalLabel = FindGlobalLabel(pVTFEntry->m_szLabel)))
1498             {
1499                 Method* pMD;
1500                 Class* pClass;
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++)
1505                 {
1506                     for(WORD j = 0; (pMD = pClass->m_MethodList.PEEK(j)); j++)
1507                     {
1508                         if(pMD->m_wVTEntry == k+1)
1509                         {
1510                             char*   ptr;
1511                             if(SUCCEEDED(hr = m_pCeeFileGen->ComputeSectionPointer(m_pGlobalDataSection,pGlobalLabel->m_GlobalOffset,&ptr)))
1512                             {
1513                                 DWORD dwDelta;
1514                                 if((pVTFEntry->m_wType & COR_VTABLE_32BIT))
1515                                 {
1516                                     dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(DWORD);
1517                                     ptr += dwDelta;
1518                                     DWORD* mptr = (DWORD*)ptr;
1519                                     *mptr = (DWORD)(pMD->m_Tok);
1520                                 }
1521                                 else
1522                                 {
1523                                     dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(ULONGLONG);
1524                                     ptr += dwDelta;
1525                                     ULONGLONG* mptr = (ULONGLONG*)ptr;
1526                                     *mptr = (ULONGLONG)(pMD->m_Tok);
1527                                 }
1528                                 if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
1529                                 {
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);
1535                                 }
1536                             }
1537                             else
1538                                 report->msg("Error: Failed to get pointer to label '%s' inVTable fixup\n",pVTFEntry->m_szLabel);
1539                         }
1540                     }
1541                 }
1542             }
1543             else
1544             {
1545                 report->msg("Error: Unresolved label '%s' in VTable fixup\n",pVTFEntry->m_szLabel);
1546                 hr = E_FAIL;
1547             }
1548             delete pVTFEntry;
1549         }
1550         if(FAILED(hr)) goto exit;
1551     }
1552     if(m_pVTable)
1553     {
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)
1561         {
1562             m_pCeeFileGen->AddSectionReloc(m_pILSection,
1563                                             ulVTableOffset+(i*sizeof(DWORD)),
1564                                             m_pGlobalDataSection,
1565                                             srRelocAbsolute);
1566         }
1567     }
1568     if(m_EATList.COUNT())
1569     {
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);
1574     }
1575     if (m_fWindowsCE)
1576     {
1577         if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, 2, 10))) goto exit;
1578
1579         if (FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, 0x10000))) goto exit;
1580     }
1581     else
1582     {
1583         if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM || m_fAppContainer)
1584         {
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;
1588
1589         }
1590
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;
1595
1596         if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, m_dwSubsystem, m_wSSVersionMajor, m_wSSVersionMinor))) goto exit;
1597     }
1598
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;
1601
1602     if(m_dwFileAlignment)
1603     {
1604         if(FAILED(hr=m_pCeeFileGen->SetFileAlignment(m_pCeeFile, m_dwFileAlignment))) goto exit;
1605     }
1606     if(m_stBaseAddress)
1607     {
1608
1609         if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1610         {
1611             if(FAILED(hr=m_pCeeFileGen->SetImageBase64(m_pCeeFile, m_stBaseAddress))) goto exit;
1612         }
1613         else
1614         {
1615             if(FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, (size_t)m_stBaseAddress))) goto exit;
1616         }
1617     }
1618     if(m_stSizeOfStackReserve || m_fAppContainer || m_fHighEntropyVA)
1619     {
1620         PIMAGE_NT_HEADERS   pNT;
1621         PIMAGE_SECTION_HEADER   pSect;
1622         ULONG   ulNumSect;
1623         if(FAILED(hr=m_pCeeFileGen->GetHeaderInfo(m_pCeeFile,&pNT,&pSect,&ulNumSect))) goto exit;
1624         if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
1625         {
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;
1633         }
1634         else
1635         {
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;
1643         }
1644     }
1645         //Compute all the RVAs
1646     if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
1647
1648         // Fix up any fields that have RVA associated with them
1649     if (m_fHaveFieldsWithRvas) {
1650         hr = S_OK;
1651         ULONG dataSectionRVA;
1652         if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pGlobalDataSection, &dataSectionRVA))) goto exit;
1653
1654         ULONG tlsSectionRVA;
1655         if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pTLSSection, &tlsSectionRVA))) goto exit;
1656
1657         ULONG ilSectionRVA;
1658         if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pILSection, &ilSectionRVA))) goto exit;
1659
1660         FieldDescriptor* pListFD;
1661         Class* pClass;
1662         for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
1663         {
1664             for(int j=0; (pListFD = pClass->m_FieldDList.PEEK(j)); j++)
1665             {
1666                 if (pListFD->m_rvaLabel != 0)
1667                 {
1668                     DWORD rva;
1669                     if(*(pListFD->m_rvaLabel)=='@')
1670                     {
1671                         rva = (DWORD)atoi(pListFD->m_rvaLabel + 1);
1672                     }
1673                     else
1674                     {
1675                         GlobalLabel *pLabel = FindGlobalLabel(pListFD->m_rvaLabel);
1676                         if (pLabel == 0)
1677                         {
1678                             report->msg("Error:Could not find label '%s' for the field '%s'\n", pListFD->m_rvaLabel, pListFD->m_szName);
1679                             hr = E_FAIL;
1680                             continue;
1681                         }
1682
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;
1688                         else {
1689                             _ASSERTE(pLabel->m_Section == m_pGlobalDataSection);
1690                             rva += dataSectionRVA;
1691                         }
1692                     }
1693                     if (FAILED(m_pEmitter->SetFieldRVA(pListFD->m_fdFieldTok, rva))) goto exit;
1694                 }
1695             }
1696         }
1697         if (FAILED(hr)) goto exit;
1698     }
1699
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;
1703     
1704     if((m_wMSVmajor < 0xFF)&&(m_wMSVminor < 0xFF))
1705     {
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++)
1713         {
1714             if((strcmp(pStr->rcName,"#-")==0)||(strcmp(pStr->rcName,"#~")==0))
1715             {
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;
1720                 break;
1721             }
1722             pb = (BYTE*)pStr;
1723             pb += 2*sizeof(DWORD)+strlen(pStr->rcName)+1;
1724             pb = (BYTE*)(((size_t)pb + 3) & ~3);
1725             pStr = (PSTORAGESTREAM)pb;
1726         }
1727     }
1728
1729     if(m_fTolerateDupMethods) // means that there are /ENC files
1730     {
1731         if(m_pbsMD) delete m_pbsMD;
1732         m_pbsMD = new BinStr();
1733         memcpy(m_pbsMD->getBuff(metaDataSize),metaData,metaDataSize);
1734     }
1735     // actually output the resources
1736     if(mresourceSize && mresourceData)
1737     {
1738         size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
1739         BYTE    *ptr = (BYTE*)mresourceData;
1740         BOOL    mrfail = FALSE;
1741         FILE*   pFile = NULL;
1742         char sz[2048];
1743         for(i=0; i < N; i++)
1744         {
1745             m_pManifest->m_fMResNew[i] = FALSE;
1746             memset(sz,0,2048);
1747             WszWideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
1748             L = m_pManifest->m_dwMResSize[i];
1749             sizeread = 0;
1750             memcpy(ptr,&L,sizeof(DWORD));
1751             ptr += sizeof(DWORD);
1752             if(fopen_s(&pFile,sz,"rb") == 0)
1753             {
1754                 sizeread = fread((void *)ptr,1,L,pFile);
1755                 fclose(pFile);
1756                 ptr += sizeread;
1757             }
1758             else
1759             {
1760                 report->msg("Error: failed to open mgd resource file '%ls'\n",m_pManifest->m_wzMResName[i]);
1761                 mrfail = TRUE;
1762             }
1763             if(sizeread < L)
1764             {
1765                 report->msg("Error: failed to read expected %d bytes from mgd resource file '%ls'\n",L,m_pManifest->m_wzMResName[i]);
1766                 mrfail = TRUE;
1767                 L -= sizeread;
1768                 memset(ptr,0,L);
1769                 ptr += L;
1770             }
1771         }
1772         if(mrfail)
1773         {
1774             hr = E_FAIL;
1775             goto exit;
1776         }
1777     }
1778     /*
1779     if((m_wRTVmajor < 0xFFFF)&&(m_wRTVminor < 0xFFFF))
1780     {
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);
1785     }
1786     */
1787     // Generate the file -- moved to main
1788     //if (FAILED(hr=m_pCeeFileGen->GenerateCeeFile(m_pCeeFile))) goto exit;
1789
1790
1791     hr = S_OK;
1792
1793 exit:
1794     return hr;
1795 }
1796 #ifdef _PREFAST_
1797 #pragma warning(pop)
1798 #endif