Merge pull request #24002 from sandreenko/fixDesktopFailure
[platform/upstream/coreclr.git] / src / ilasm / writer_enc.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // writer_ENC.cpp
6 //
7
8 //
9 #include "ilasmpch.h"
10
11 #include "assembler.h"
12
13 //#include "ceefilegenwriter.h"
14 #include "strongname.h"
15
16 int ist=0;
17 #define REPT_STEP   //printf("Step %d\n",++ist);
18
19 HRESULT Assembler::InitMetaDataForENC(__in __nullterminated WCHAR* wzOrigFileName)
20 {
21     HRESULT             hr = E_FAIL;
22
23     if((wzOrigFileName==NULL)||(*wzOrigFileName == 0)||(m_pDisp==NULL)) return hr;
24     if (m_pSymWriter != NULL)
25     {
26         m_pSymWriter->Close();
27         m_pSymWriter->Release();
28         m_pSymWriter = NULL;
29     }
30     if (m_pImporter != NULL)
31     {
32         m_pImporter->Release();
33         m_pImporter = NULL;
34     }
35     if (m_pEmitter != NULL)
36     {
37         m_pEmitter->Release();
38         m_pEmitter = NULL;
39     }
40     //WszSetEnvironmentVariable(L"COMP_ENC_OPENSCOPE", wzOrigFileName);
41     //hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit2,
42     //                    (IUnknown **)&m_pEmitter);
43
44     if((m_pbsMD==NULL)||(m_pbsMD->length()==0))
45     {
46         _ASSERTE(!"NO BASE METADATA!");
47         return E_FAIL;
48     }
49    
50     VARIANT encOption;
51     V_VT(&encOption) = VT_UI4;
52     V_UI4(&encOption) = MDUpdateENC;
53     m_pDisp->SetOption(MetaDataSetENC, &encOption);
54     V_UI4(&encOption) = MDErrorOutOfOrderDefault;
55     m_pDisp->SetOption(MetaDataErrorIfEmitOutOfOrder, &encOption);
56     hr = m_pDisp->OpenScopeOnMemory( m_pbsMD->ptr(), 
57                                      m_pbsMD->length(), 
58                                      ofWrite, 
59                                      IID_IMetaDataEmit2, 
60                                      (IUnknown **)&m_pEmitter);
61     _ASSERTE(SUCCEEDED(hr));
62     if (FAILED(hr))
63         goto exit;
64
65     m_pManifest->SetEmitter(m_pEmitter);
66     if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataImport2, (void**)&m_pImporter)))
67         goto exit;
68
69     //WszSetEnvironmentVariable(L"COMP_ENC_EMIT", wzOrigFileName);
70     if(!Init()) goto exit; // close and re-open CeeFileGen and CeeFile
71     hr = S_OK;
72
73
74 exit:
75     return hr;
76 }
77 /*********************************************************************************/
78
79 BOOL Assembler::EmitFieldsMethodsENC(Class* pClass)
80 {
81     unsigned n;
82     BOOL ret = TRUE;
83     // emit all field definition metadata tokens
84     if((pClass->m_FieldDList.COUNT()))
85     {
86         FieldDescriptor*    pFD;
87         int j;
88         for(j=0, n=0; (pFD = pClass->m_FieldDList.PEEK(j)); j++) // can't use POP here: we'll need field list for props
89         {
90             if(pFD->m_fNew)
91             {
92                 if(!EmitField(pFD))
93                 {
94                     if(!OnErrGo) return FALSE;
95                     ret = FALSE;
96                 }
97                 pFD->m_fNew = FALSE;
98                 n++;
99             }
100         }
101         if(m_fReportProgress) printf("Fields: %d;\t",n);
102     }
103     // Fields are emitted; emit the class layout
104     {
105         COR_FIELD_OFFSET *pOffsets = NULL;
106         ULONG ul = pClass->m_ulPack;
107         ULONG N = pClass->m_dwNumFieldsWithOffset;
108
109         EmitSecurityInfo(pClass->m_cl,
110                          pClass->m_pPermissions,
111                          pClass->m_pPermissionSets);
112         pClass->m_pPermissions = NULL;
113         pClass->m_pPermissionSets = NULL;
114         if((pClass->m_ulSize != 0xFFFFFFFF)||(ul != 0)||(N != 0))
115         {
116             if(IsTdAutoLayout(pClass->m_Attr)) report->warn("Layout specified for auto-layout class\n");
117             if((ul > 128)||((ul & (ul-1)) !=0 ))
118                 report->error("Invalid packing parameter (%d), must be 1,2,4,8...128\n",pClass->m_ulPack);
119             if(N)
120             {
121                 pOffsets = new COR_FIELD_OFFSET[N+1];
122                 ULONG i,j=0;
123                 FieldDescriptor *pFD;
124                 for(i=0; (pFD = pClass->m_FieldDList.PEEK(i)); i++)
125                 {
126                     if(pFD->m_ulOffset != 0xFFFFFFFF)
127                     {
128                         pOffsets[j].ridOfField = RidFromToken(pFD->m_fdFieldTok);
129                         pOffsets[j].ulOffset = pFD->m_ulOffset;
130                         j++;
131                     }
132                 }
133                 _ASSERTE(j == N);
134                 pOffsets[j].ridOfField = mdFieldDefNil;
135             }
136             m_pEmitter->SetClassLayout   (   
137                         pClass->m_cl,       // [IN] typedef 
138                         ul,                     // [IN] packing size specified as 1, 2, 4, 8, or 16 
139                         pOffsets,               // [IN] array of layout specification   
140                         pClass->m_ulSize); // [IN] size of the class   
141             if(pOffsets) delete [] pOffsets;
142         }
143     }
144     // emit all method definition metadata tokens
145     if((pClass->m_MethodList.COUNT()))
146     {
147         Method* pMethod;
148         int i;
149
150         for(i=0, n=0; (pMethod = pClass->m_MethodList.PEEK(i));i++)
151         {
152             if(pMethod->m_fNew)
153             {
154                 if(!EmitMethod(pMethod))
155                 {
156                     if(!OnErrGo) return FALSE;
157                     ret = FALSE;
158                 }
159                 pMethod->m_fNew = FALSE;
160                 n++;
161             }
162         }
163         if(m_fReportProgress) printf("Methods: %d;\t",n);
164     }
165     if(m_fReportProgress) printf("\n");
166     return ret;
167 }
168
169 BOOL Assembler::EmitEventsPropsENC(Class* pClass)
170 {
171     unsigned n;
172     BOOL ret = TRUE;
173     // emit all event definition metadata tokens
174     if((pClass->m_EventDList.COUNT()))
175     {
176         EventDescriptor* pED;
177         int j;
178         for(j=0,n=0; (pED = pClass->m_EventDList.PEEK(j)); j++) // can't use POP here: we'll need event list for props
179         {
180             if(pED->m_fNew)
181             {
182                 if(!EmitEvent(pED))
183                 {
184                     if(!OnErrGo) return FALSE;
185                     ret = FALSE;
186                 }
187                 pED->m_fNew = FALSE;
188                 n++;
189             }
190         }
191         if(m_fReportProgress) printf("Events: %d;\t",n);
192     }
193     // emit all property definition metadata tokens
194     if((pClass->m_PropDList.COUNT()))
195     {
196         PropDescriptor* pPD;
197         int j;
198
199         for(j=0,n=0; (pPD = pClass->m_PropDList.PEEK(j)); j++)
200         {
201             if(pPD->m_fNew)
202             {
203                 if(!EmitProp(pPD))
204                 {
205                     if(!OnErrGo) return FALSE;
206                     ret = FALSE;
207                 }
208                 pPD->m_fNew = FALSE;
209                 n++;
210             }
211         }
212         if(m_fReportProgress) printf("Props: %d;\t",n);
213     }
214     if(m_fReportProgress) printf("\n");
215     return ret;
216 }
217
218 HRESULT Assembler::CreateDeltaFiles(__in __nullterminated WCHAR *pwzOutputFilename)
219 {
220     HRESULT             hr;
221     DWORD               mresourceSize = 0;
222     BYTE*               mresourceData = NULL;
223     WCHAR*              pEnd = NULL;
224
225     if(m_fReportProgress) printf("Creating DMETA,DIL files\n");
226     if (!m_pEmitter)
227     {
228         printf("Error: Cannot create a PE file with no metadata\n");
229         return E_FAIL;
230     }
231 REPT_STEP
232     if(m_pManifest)
233     {
234         hr = S_OK;
235         if(m_pManifest->m_pAsmEmitter==NULL)
236             hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));
237
238         if(SUCCEEDED(hr))
239         {
240             m_pManifest->EmitAssemblyRefs();
241         }
242     }
243     // Emit classes, class members and globals:
244     {
245         Class *pSearch;
246         int i;
247         BOOL    bIsUndefClass = FALSE;
248         if(m_fReportProgress)   printf("\nEmitting classes:\n");
249         for (i=1; (pSearch = m_lstClass.PEEK(i)); i++)   // 0 is <Module>
250         {
251             if(pSearch->m_fNew)
252             {
253                 if(m_fReportProgress)
254                     printf("Class %d:\t%s\n",i,pSearch->m_szFQN);
255                 
256                 if(pSearch->m_bIsMaster)
257                 {
258                     report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
259                     bIsUndefClass = TRUE;
260                 }
261                 if(!EmitClass(pSearch))
262                 {
263                     if(!OnErrGo) return E_FAIL;
264                 }
265                 pSearch->m_fNew = FALSE;
266             }
267         }
268         if(bIsUndefClass && !OnErrGo) return E_FAIL;
269         
270         if(m_fReportProgress)   printf("\nEmitting fields and methods:\n");
271         for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
272         {
273             if(pSearch->m_fNewMembers)
274             {
275                 if(m_fReportProgress)
276                 {
277                     if(i == 0)  printf("Global \t");
278                     else        printf("Class %d\t",i);
279                 }
280                 if(!EmitFieldsMethodsENC(pSearch))
281                 {
282                     if(!OnErrGo) return E_FAIL;
283                 }
284             }
285         }
286     }
287 REPT_STEP
288
289     // All ref'ed items def'ed in this file are emitted, resolve member refs to member defs:
290     hr = ResolveLocalMemberRefs();
291     if(FAILED(hr) &&(!OnErrGo)) goto exit;
292
293     // Local member refs resolved, emit events, props and method impls
294     {
295         Class *pSearch;
296         int i;
297     
298         if(m_fReportProgress)   printf("\nEmitting events and properties:\n");
299         for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
300         {
301             if(pSearch->m_fNewMembers)
302             {
303                 if(m_fReportProgress)
304                 {
305                     if(i == 0)  printf("Global \t");
306                     else        printf("Class %d\t",i);
307                 }
308                 if(!EmitEventsPropsENC(pSearch))
309                 {
310                     if(!OnErrGo) return E_FAIL;
311                 }
312                 pSearch->m_fNewMembers = FALSE;
313             }
314         }
315     }
316     if(m_MethodImplDList.COUNT())
317     {
318         if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
319         if(!EmitMethodImpls())
320         {
321             if(!OnErrGo) return E_FAIL;
322         }
323     }
324 REPT_STEP
325     // Emit the rest of the metadata
326     hr = S_OK;
327     if(m_pManifest) 
328     {
329         if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
330     }
331     ResolveLocalMemberRefs(); // in case CAs added some
332     EmitUnresolvedCustomAttributes();
333 REPT_STEP
334
335     hr = DoLocalMemberRefFixups();
336     if(FAILED(hr) &&(!OnErrGo)) goto exit;
337
338     // Local member refs resolved and fixed up in BinStr method bodies. Emit the bodies to a separate file.
339     pEnd = &pwzOutputFilename[wcslen(pwzOutputFilename)];
340     {
341         Class* pClass;
342         Method* pMethod;
343         FILE* pF = NULL;
344         wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dil"));
345         if(_wfopen_s(&pF,pwzOutputFilename,W("wb"))==0)
346         {
347             int i,j,L=0,M=0;
348             BinStr bsOut;
349             for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
350             {
351                 for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
352                 {
353                     if(pMethod->m_fNewBody)
354                     {
355                         L+= pMethod->m_pbsBody->length()+3;
356                         M++;
357                     }
358                 }
359             }
360             bsOut.getBuff(L+sizeof(DWORD)); // to avoid reallocs
361             bsOut.remove(L);
362             for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
363             {
364                 for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
365                 {
366                     if(pMethod->m_fNewBody)
367                     {
368                         if(!EmitMethodBody(pMethod,&bsOut))
369                         {
370                             report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
371                             hr = E_FAIL;
372                             if(!OnErrGo)
373                             { 
374                                 fclose(pF);
375                                 *pEnd = 0;
376                                 goto exit;
377                             }
378                         }
379                         pMethod->m_fNewBody = FALSE;
380                     }
381                 }
382             }
383             *((DWORD*)(bsOut.ptr())) = bsOut.length() - sizeof(DWORD);
384             fwrite(bsOut.ptr(),bsOut.length(),1,pF);
385             fclose(pF);
386         }
387         else
388             report->msg("Error: failed to open file '%S'\n",pwzOutputFilename);
389
390         *pEnd = 0;
391     }
392 REPT_STEP
393     
394     //if (DoGlobalFixups() == FALSE)
395     //    return E_FAIL;
396     
397     //if (FAILED(hr=m_pCeeFileGen->SetOutputFileName(m_pCeeFile, pwzOutputFilename))) goto exit;
398
399     // Emit the meta-data to a separate file
400     IMetaDataEmit2* pENCEmitter;
401     if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataEmit2, (void**)&pENCEmitter)))
402         goto exit;
403
404     DWORD metaDataSize; 
405     if (FAILED(hr=pENCEmitter->GetDeltaSaveSize(cssAccurate, &metaDataSize))) goto exit;
406
407     wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dmeta"));
408     pENCEmitter->SaveDelta(pwzOutputFilename,0); // second arg (dwFlags) is not used
409     *pEnd = 0;
410     pENCEmitter->Release();
411
412     // apply delta to create basis for the next ENC iteration
413     if(m_pbsMD)
414     {
415         IMetaDataEmit2* pBaseMDEmit = NULL;
416         if(FAILED(hr = m_pDisp->OpenScopeOnMemory(m_pbsMD->ptr(),
417                                                   m_pbsMD->length(),
418                                                   ofWrite,
419                                                   IID_IMetaDataEmit2,
420                                     (IUnknown **)&pBaseMDEmit))) goto exit;
421     
422         if(FAILED(hr = pBaseMDEmit->ApplyEditAndContinue((IUnknown*)m_pImporter))) goto exit;
423         delete m_pbsMD;
424         if((m_pbsMD = new BinStr()) != NULL)
425         {
426             DWORD cb;
427             hr = pBaseMDEmit->GetSaveSize(cssAccurate,&cb);
428             BYTE* pb = m_pbsMD->getBuff(cb);
429             hr = pBaseMDEmit->SaveToMemory(pb,cb);
430         }
431         pBaseMDEmit->Release();
432     }
433
434
435     // release all interfaces
436     if (m_pSymWriter != NULL)
437     {
438         m_pSymWriter->Close();
439         m_pSymWriter->Release();
440         m_pSymWriter = NULL;
441     }
442     if (m_pImporter != NULL)
443     {
444         m_pImporter->Release();
445         m_pImporter = NULL;
446     }
447     if (m_pEmitter != NULL)
448     {
449         m_pEmitter->Release();
450         m_pEmitter = NULL;
451     }
452
453     return S_OK;
454
455 REPT_STEP
456     
457     // set managed resource entry, if any
458     if(m_pManifest && m_pManifest->m_dwMResSizeTotal)
459     {
460         mresourceSize = m_pManifest->m_dwMResSizeTotal;
461
462         if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, mresourceSize, 
463                                             sizeof(DWORD), (void**) &mresourceData))) goto exit; 
464         if (FAILED(hr=m_pCeeFileGen->SetManifestEntry(m_pCeeFile, mresourceSize, 0))) goto exit;
465     }
466 REPT_STEP
467     /*
468     if (m_fWindowsCE)
469     {
470         if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, 2, 10))) goto exit;
471
472         if (FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, 0x10000))) goto exit;
473     }
474     else if(m_dwSubsystem != (DWORD)-1)
475     {
476         if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, m_dwSubsystem, 4, 0))) goto exit;
477     }
478     
479     if (FAILED(hr=m_pCeeFileGen->ClearComImageFlags(m_pCeeFile, COMIMAGE_FLAGS_ILONLY))) goto exit;
480     if (FAILED(hr=m_pCeeFileGen->SetComImageFlags(m_pCeeFile, m_dwComImageFlags & ~COMIMAGE_FLAGS_STRONGNAMESIGNED))) goto exit;
481
482     if(m_dwFileAlignment)
483     {
484         if(FAILED(hr=m_pCeeFileGen->SetFileAlignment(m_pCeeFile, m_dwFileAlignment))) goto exit;
485     }
486     if(m_stBaseAddress)
487     {
488         if(FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, m_stBaseAddress))) goto exit;
489     }
490     */
491 REPT_STEP
492         //Compute all the RVAs
493     if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
494
495 REPT_STEP
496         // Fix up any fields that have RVA associated with them
497 /*
498     if (m_fHaveFieldsWithRvas) {
499         hr = S_OK;
500         ULONG dataSectionRVA;
501         if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pGlobalDataSection, &dataSectionRVA))) goto exit;
502         
503         ULONG tlsSectionRVA;
504         if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pTLSSection, &tlsSectionRVA))) goto exit;
505
506         FieldDescriptor* pListFD;
507         Class* pClass;
508         for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
509         {
510             for(int j=0; (pListFD = pClass->m_FieldDList.PEEK(j)); j++)
511             {
512                 if (pListFD->m_rvaLabel != 0) 
513                 {
514                     DWORD rva;
515                     if(*(pListFD->m_rvaLabel)=='@')
516                     {
517                         rva = (DWORD)atoi(pListFD->m_rvaLabel + 1);
518                     }
519                     else
520                     {
521                         GlobalLabel *pLabel = FindGlobalLabel(pListFD->m_rvaLabel);
522                         if (pLabel == 0)
523                         {
524                             report->msg("Error:Could not find label '%s' for the field '%s'\n", pListFD->m_rvaLabel, pListFD->m_szName);
525                             hr = E_FAIL;
526                             continue;
527                         }
528                     
529                         rva = pLabel->m_GlobalOffset;
530                         if (pLabel->m_Section == m_pTLSSection)
531                             rva += tlsSectionRVA;
532                         else {
533                             _ASSERTE(pLabel->m_Section == m_pGlobalDataSection);
534                             rva += dataSectionRVA;
535                         }
536                     }
537                     if (FAILED(m_pEmitter->SetFieldRVA(pListFD->m_fdFieldTok, rva))) goto exit;
538                 }
539             }
540         }
541         if (FAILED(hr)) goto exit;
542     }
543 REPT_STEP
544 */
545
546 REPT_STEP
547     // actually output the resources
548     if(mresourceSize && mresourceData)
549     {
550         size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
551         BYTE    *ptr = (BYTE*)mresourceData;
552         BOOL    mrfail = FALSE;
553         FILE*   pFile = NULL;
554         char sz[2048];
555         for(i=0; i < N; i++)
556         {
557             if(!m_pManifest->m_fMResNew[i]) continue;
558             m_pManifest->m_fMResNew[i] = FALSE;
559             memset(sz,0,2048);
560             WszWideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
561             L = m_pManifest->m_dwMResSize[i];
562             sizeread = 0;
563             memcpy(ptr,&L,sizeof(DWORD));
564             ptr += sizeof(DWORD);
565             pFile = NULL;
566             if(fopen_s(&pFile,sz,"rb")==0)
567             {
568                 sizeread = fread((void *)ptr,1,L,pFile);
569                 fclose(pFile);
570                 ptr += sizeread;
571             }
572             else
573             {
574                 report->msg("Error: failed to open mgd resource file '%ls'\n",m_pManifest->m_wzMResName[i]);
575                 mrfail = TRUE;
576             }
577             if(sizeread < L)
578             {
579                 report->msg("Error: failed to read expected %d bytes from mgd resource file '%ls'\n",L,m_pManifest->m_wzMResName[i]);
580                 mrfail = TRUE;
581                 L -= sizeread;
582                 memset(ptr,0,L);
583                 ptr += L;
584             }
585         }
586         if(mrfail) 
587         { 
588             hr = E_FAIL;
589             goto exit;
590         }
591     }
592 REPT_STEP
593
594     // Generate the file -- moved to main
595     //if (FAILED(hr=m_pCeeFileGen->GenerateCeeFile(m_pCeeFile))) goto exit;
596
597
598     hr = S_OK;
599
600 exit:
601     return hr;
602 }