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.
11 #include "assembler.h"
13 //#include "ceefilegenwriter.h"
14 #include "strongname.h"
17 #define REPT_STEP //printf("Step %d\n",++ist);
19 HRESULT Assembler::InitMetaDataForENC(__in __nullterminated WCHAR* wzOrigFileName)
23 if((wzOrigFileName==NULL)||(*wzOrigFileName == 0)||(m_pDisp==NULL)) return hr;
24 if (m_pSymWriter != NULL)
26 m_pSymWriter->Close();
27 m_pSymWriter->Release();
30 if (m_pImporter != NULL)
32 m_pImporter->Release();
35 if (m_pEmitter != NULL)
37 m_pEmitter->Release();
40 //WszSetEnvironmentVariable(L"COMP_ENC_OPENSCOPE", wzOrigFileName);
41 //hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit2,
42 // (IUnknown **)&m_pEmitter);
44 if((m_pbsMD==NULL)||(m_pbsMD->length()==0))
46 _ASSERTE(!"NO BASE METADATA!");
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(),
60 (IUnknown **)&m_pEmitter);
61 _ASSERTE(SUCCEEDED(hr));
65 m_pManifest->SetEmitter(m_pEmitter);
66 if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataImport2, (void**)&m_pImporter)))
69 //WszSetEnvironmentVariable(L"COMP_ENC_EMIT", wzOrigFileName);
70 if(!Init()) goto exit; // close and re-open CeeFileGen and CeeFile
77 /*********************************************************************************/
79 BOOL Assembler::EmitFieldsMethodsENC(Class* pClass)
83 // emit all field definition metadata tokens
84 if((pClass->m_FieldDList.COUNT()))
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
94 if(!OnErrGo) return FALSE;
101 if(m_fReportProgress) printf("Fields: %d;\t",n);
103 // Fields are emitted; emit the class layout
105 COR_FIELD_OFFSET *pOffsets = NULL;
106 ULONG ul = pClass->m_ulPack;
107 ULONG N = pClass->m_dwNumFieldsWithOffset;
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))
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);
121 pOffsets = new COR_FIELD_OFFSET[N+1];
123 FieldDescriptor *pFD;
124 for(i=0; (pFD = pClass->m_FieldDList.PEEK(i)); i++)
126 if(pFD->m_ulOffset != 0xFFFFFFFF)
128 pOffsets[j].ridOfField = RidFromToken(pFD->m_fdFieldTok);
129 pOffsets[j].ulOffset = pFD->m_ulOffset;
134 pOffsets[j].ridOfField = mdFieldDefNil;
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;
144 // emit all method definition metadata tokens
145 if((pClass->m_MethodList.COUNT()))
150 for(i=0, n=0; (pMethod = pClass->m_MethodList.PEEK(i));i++)
154 if(!EmitMethod(pMethod))
156 if(!OnErrGo) return FALSE;
159 pMethod->m_fNew = FALSE;
163 if(m_fReportProgress) printf("Methods: %d;\t",n);
165 if(m_fReportProgress) printf("\n");
169 BOOL Assembler::EmitEventsPropsENC(Class* pClass)
173 // emit all event definition metadata tokens
174 if((pClass->m_EventDList.COUNT()))
176 EventDescriptor* pED;
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
184 if(!OnErrGo) return FALSE;
191 if(m_fReportProgress) printf("Events: %d;\t",n);
193 // emit all property definition metadata tokens
194 if((pClass->m_PropDList.COUNT()))
199 for(j=0,n=0; (pPD = pClass->m_PropDList.PEEK(j)); j++)
205 if(!OnErrGo) return FALSE;
212 if(m_fReportProgress) printf("Props: %d;\t",n);
214 if(m_fReportProgress) printf("\n");
218 HRESULT Assembler::CreateDeltaFiles(__in __nullterminated WCHAR *pwzOutputFilename)
221 DWORD mresourceSize = 0;
222 BYTE* mresourceData = NULL;
225 if(m_fReportProgress) printf("Creating DMETA,DIL files\n");
228 printf("Error: Cannot create a PE file with no metadata\n");
235 if(m_pManifest->m_pAsmEmitter==NULL)
236 hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));
240 m_pManifest->EmitAssemblyRefs();
243 // Emit classes, class members and globals:
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>
253 if(m_fReportProgress)
254 printf("Class %d:\t%s\n",i,pSearch->m_szFQN);
256 if(pSearch->m_bIsMaster)
258 report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
259 bIsUndefClass = TRUE;
261 if(!EmitClass(pSearch))
263 if(!OnErrGo) return E_FAIL;
265 pSearch->m_fNew = FALSE;
268 if(bIsUndefClass && !OnErrGo) return E_FAIL;
270 if(m_fReportProgress) printf("\nEmitting fields and methods:\n");
271 for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
273 if(pSearch->m_fNewMembers)
275 if(m_fReportProgress)
277 if(i == 0) printf("Global \t");
278 else printf("Class %d\t",i);
280 if(!EmitFieldsMethodsENC(pSearch))
282 if(!OnErrGo) return E_FAIL;
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;
293 // Local member refs resolved, emit events, props and method impls
298 if(m_fReportProgress) printf("\nEmitting events and properties:\n");
299 for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
301 if(pSearch->m_fNewMembers)
303 if(m_fReportProgress)
305 if(i == 0) printf("Global \t");
306 else printf("Class %d\t",i);
308 if(!EmitEventsPropsENC(pSearch))
310 if(!OnErrGo) return E_FAIL;
312 pSearch->m_fNewMembers = FALSE;
316 if(m_MethodImplDList.COUNT())
318 if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
319 if(!EmitMethodImpls())
321 if(!OnErrGo) return E_FAIL;
325 // Emit the rest of the metadata
329 if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
331 ResolveLocalMemberRefs(); // in case CAs added some
332 EmitUnresolvedCustomAttributes();
335 hr = DoLocalMemberRefFixups();
336 if(FAILED(hr) &&(!OnErrGo)) goto exit;
338 // Local member refs resolved and fixed up in BinStr method bodies. Emit the bodies to a separate file.
339 pEnd = &pwzOutputFilename[wcslen(pwzOutputFilename)];
344 wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dil"));
345 if(_wfopen_s(&pF,pwzOutputFilename,W("wb"))==0)
349 for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
351 for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
353 if(pMethod->m_fNewBody)
355 L+= pMethod->m_pbsBody->length()+3;
360 bsOut.getBuff(L+sizeof(DWORD)); // to avoid reallocs
362 for (i=0; (pClass = m_lstClass.PEEK(i)); i++)
364 for(j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
366 if(pMethod->m_fNewBody)
368 if(!EmitMethodBody(pMethod,&bsOut))
370 report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
379 pMethod->m_fNewBody = FALSE;
383 *((DWORD*)(bsOut.ptr())) = bsOut.length() - sizeof(DWORD);
384 fwrite(bsOut.ptr(),bsOut.length(),1,pF);
388 report->msg("Error: failed to open file '%S'\n",pwzOutputFilename);
394 //if (DoGlobalFixups() == FALSE)
397 //if (FAILED(hr=m_pCeeFileGen->SetOutputFileName(m_pCeeFile, pwzOutputFilename))) goto exit;
399 // Emit the meta-data to a separate file
400 IMetaDataEmit2* pENCEmitter;
401 if(FAILED(hr = m_pEmitter->QueryInterface(IID_IMetaDataEmit2, (void**)&pENCEmitter)))
405 if (FAILED(hr=pENCEmitter->GetDeltaSaveSize(cssAccurate, &metaDataSize))) goto exit;
407 wcscat_s(pwzOutputFilename,MAX_SCOPE_LENGTH,W(".dmeta"));
408 pENCEmitter->SaveDelta(pwzOutputFilename,0); // second arg (dwFlags) is not used
410 pENCEmitter->Release();
412 // apply delta to create basis for the next ENC iteration
415 IMetaDataEmit2* pBaseMDEmit = NULL;
416 if(FAILED(hr = m_pDisp->OpenScopeOnMemory(m_pbsMD->ptr(),
420 (IUnknown **)&pBaseMDEmit))) goto exit;
422 if(FAILED(hr = pBaseMDEmit->ApplyEditAndContinue((IUnknown*)m_pImporter))) goto exit;
424 if((m_pbsMD = new BinStr()) != NULL)
427 hr = pBaseMDEmit->GetSaveSize(cssAccurate,&cb);
428 BYTE* pb = m_pbsMD->getBuff(cb);
429 hr = pBaseMDEmit->SaveToMemory(pb,cb);
431 pBaseMDEmit->Release();
435 // release all interfaces
436 if (m_pSymWriter != NULL)
438 m_pSymWriter->Close();
439 m_pSymWriter->Release();
442 if (m_pImporter != NULL)
444 m_pImporter->Release();
447 if (m_pEmitter != NULL)
449 m_pEmitter->Release();
457 // set managed resource entry, if any
458 if(m_pManifest && m_pManifest->m_dwMResSizeTotal)
460 mresourceSize = m_pManifest->m_dwMResSizeTotal;
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;
470 if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, 2, 10))) goto exit;
472 if (FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, 0x10000))) goto exit;
474 else if(m_dwSubsystem != (DWORD)-1)
476 if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, m_dwSubsystem, 4, 0))) goto exit;
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;
482 if(m_dwFileAlignment)
484 if(FAILED(hr=m_pCeeFileGen->SetFileAlignment(m_pCeeFile, m_dwFileAlignment))) goto exit;
488 if(FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, m_stBaseAddress))) goto exit;
492 //Compute all the RVAs
493 if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;
496 // Fix up any fields that have RVA associated with them
498 if (m_fHaveFieldsWithRvas) {
500 ULONG dataSectionRVA;
501 if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pGlobalDataSection, &dataSectionRVA))) goto exit;
504 if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pTLSSection, &tlsSectionRVA))) goto exit;
506 FieldDescriptor* pListFD;
508 for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
510 for(int j=0; (pListFD = pClass->m_FieldDList.PEEK(j)); j++)
512 if (pListFD->m_rvaLabel != 0)
515 if(*(pListFD->m_rvaLabel)=='@')
517 rva = (DWORD)atoi(pListFD->m_rvaLabel + 1);
521 GlobalLabel *pLabel = FindGlobalLabel(pListFD->m_rvaLabel);
524 report->msg("Error:Could not find label '%s' for the field '%s'\n", pListFD->m_rvaLabel, pListFD->m_szName);
529 rva = pLabel->m_GlobalOffset;
530 if (pLabel->m_Section == m_pTLSSection)
531 rva += tlsSectionRVA;
533 _ASSERTE(pLabel->m_Section == m_pGlobalDataSection);
534 rva += dataSectionRVA;
537 if (FAILED(m_pEmitter->SetFieldRVA(pListFD->m_fdFieldTok, rva))) goto exit;
541 if (FAILED(hr)) goto exit;
547 // actually output the resources
548 if(mresourceSize && mresourceData)
550 size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
551 BYTE *ptr = (BYTE*)mresourceData;
557 if(!m_pManifest->m_fMResNew[i]) continue;
558 m_pManifest->m_fMResNew[i] = FALSE;
560 WszWideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
561 L = m_pManifest->m_dwMResSize[i];
563 memcpy(ptr,&L,sizeof(DWORD));
564 ptr += sizeof(DWORD);
566 if(fopen_s(&pFile,sz,"rb")==0)
568 sizeread = fread((void *)ptr,1,L,pFile);
574 report->msg("Error: failed to open mgd resource file '%ls'\n",m_pManifest->m_wzMResName[i]);
579 report->msg("Error: failed to read expected %d bytes from mgd resource file '%ls'\n",L,m_pManifest->m_wzMResName[i]);
594 // Generate the file -- moved to main
595 //if (FAILED(hr=m_pCeeFileGen->GenerateCeeFile(m_pCeeFile))) goto exit;