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
16int ist=0;
17#define REPT_STEP //printf("Step %d\n",++ist);
18
19HRESULT 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
74exit:
75 return hr;
76}
77/*********************************************************************************/
78
79BOOL 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
169BOOL 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
218HRESULT 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 }
231REPT_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 }
287REPT_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 }
324REPT_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();
333REPT_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 }
392REPT_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
455REPT_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 }
466REPT_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 */
491REPT_STEP
492 //Compute all the RVAs
493 if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
494
495REPT_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 }
543REPT_STEP
544*/
545
546REPT_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 }
592REPT_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
600exit:
601 return hr;
602}
603