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// Derived class from CCeeGen which handles writing out
5// the exe. All references to PEWriter pulled out of CCeeGen,
6// and moved here
7//
8//
9
10#include "stdafx.h"
11
12#include <string.h>
13#include <limits.h>
14
15#include "corerror.h"
16#include "stubs.h"
17#include <posterror.h>
18#include <shlwapi.h>
19
20// Globals.
21HINSTANCE g_hThisInst; // This library.
22
23
24#ifdef EMIT_FIXUPS
25
26// Emitted PEFIXUP structure looks like this
27struct PEFIXUP
28{
29 WORD wType;
30 WORD wSpare;
31 DWORD rva;
32 DWORD rvaTarget;
33};
34
35// Following structure is used to store the reloc information which
36// will be used at UpdateFixups time to get the final data from the section
37// bytes to update the fixup information.
38//
39struct DBG_FIXUP
40{
41 WORD wType;
42 WORD wSpare;
43
44 union
45 {
46 DWORD rva;
47 unsigned offset;
48 };
49
50 union
51 {
52 DWORD rvaTarget;
53 CeeSection * sectionSource;
54 };
55};
56
57enum
58{
59 IMAGE_REL_I386_DIR24NB = 0x0081, // 24-bit base relative
60 IMAGE_REL_I386_FILEPOS = 0x0082, // 32-bit file relative
61 // all other relocation types are
62 // in winnt.h, for some reason
63 // this one is missing
64 IMAGE_REL_I386_DIR30NB = 0x0083, // 30-bit base relative
65};
66
67#endif // EMIT_FIXUPS
68
69// Get the Symbol entry given the head and a 0-based index
70inline IMAGE_SYMBOL* GetSymbolEntry(IMAGE_SYMBOL* pHead, SIZE_T idx)
71{
72 return (IMAGE_SYMBOL*) (((BYTE*) pHead) + IMAGE_SIZEOF_SYMBOL * idx);
73}
74
75#ifdef EnC_SUPPORTED
76#define ENC_DELTA_HACK
77#endif
78
79#ifdef ENC_DELTA_HACK
80 BOOL g_EnCMode = FALSE;
81#endif
82
83//*****************************************************************************
84// To get a new instance, call CreateNewInstance() or CreateNewInstanceEx() instead of new
85//*****************************************************************************
86
87HRESULT CeeFileGenWriter::CreateNewInstance(CCeeGen *pCeeFileGenFrom,
88 CeeFileGenWriter* & pGenWriter,
89 DWORD createFlags)
90{
91 return CreateNewInstanceEx(pCeeFileGenFrom, pGenWriter, createFlags);
92}
93
94//
95// Seed file is used as the base file. The new file data will be "appended" to the seed file
96//
97
98HRESULT CeeFileGenWriter::CreateNewInstanceEx(CCeeGen *pCeeFileGenFrom,
99 CeeFileGenWriter* & pGenWriter,
100 DWORD createFlags,
101 LPCWSTR seedFileName)
102{
103 HRESULT hr = S_OK;
104 ULONG preallocatedOffset = 0;
105 NewHolder<PEWriter> pPEWriter(NULL);
106 NewHolder<CeeFileGenWriter> pPrivateGenWriter;
107 CeeSection *corHeaderSection = NULL;
108
109 pPrivateGenWriter = new (nothrow) CeeFileGenWriter;
110 if (pPrivateGenWriter == NULL)
111 IfFailGo(E_OUTOFMEMORY);
112
113 pPEWriter = new (nothrow) PEWriter;
114 if (pPEWriter == NULL)
115 IfFailGo(E_OUTOFMEMORY);
116
117 //workaround
118 //What's really the correct thing to be doing here?
119 //HRESULT hr = pPEWriter->Init(pCeeFileGenFrom ? pCeeFileGenFrom->getPESectionMan() : NULL);
120 hr = pPEWriter->Init(NULL, createFlags, seedFileName);
121 IfFailGo(hr);
122
123 //Create the general PEWriter.
124 pPrivateGenWriter->m_peSectionMan = pPEWriter;
125 hr = pPrivateGenWriter->Init(); // base class member to finish init
126 IfFailGo(hr);
127
128 if (!seedFileName) // Use base file's preferred base (if present)
129 {
130 if (pPEWriter->isPE32())
131 {
132 pPrivateGenWriter->setImageBase((DWORD) CEE_IMAGE_BASE_32); // use same default as linker
133 }
134 else
135 {
136 pPrivateGenWriter->setImageBase64((ULONGLONG) CEE_IMAGE_BASE_64); // use same default as linker
137 }
138 }
139
140 pPrivateGenWriter->setSubsystem(IMAGE_SUBSYSTEM_WINDOWS_CUI, CEE_IMAGE_SUBSYSTEM_MAJOR_VERSION, CEE_IMAGE_SUBSYSTEM_MINOR_VERSION);
141
142 if (pPEWriter->createCorMainStub())
143 {
144 hr = pPrivateGenWriter->allocateIAT(); // so the IAT goes out first
145 IfFailGo(hr);
146 }
147
148 hr = pPrivateGenWriter->allocateCorHeader(); // get COR header near front
149 IfFailGo(hr);
150
151#if 0 // Need to add this if we want to propagate the old COM+ header
152 if (seedFileName)
153 {
154 memcpy(m_corHeader, baseFileDecoder->ntHeaders32()->corHeader, sizeof(IMAGE_COR20_HEADER));
155 }
156#endif
157
158 //If we were passed a CCeeGen at the beginning, copy it's data now.
159 if (pCeeFileGenFrom) {
160 pCeeFileGenFrom->cloneInstance((CCeeGen*)pPrivateGenWriter);
161 }
162
163 hr = pPrivateGenWriter->getSectionCreate(".text0", sdExecute, &corHeaderSection);
164 IfFailGo(hr);
165 preallocatedOffset = corHeaderSection->dataLen();
166
167
168 // set il RVA to be after the preallocated sections
169 pPEWriter->setIlRva(preallocatedOffset);
170
171#ifdef EMIT_FIXUPS
172 if (createFlags & ICEE_CREATE_FILE_EMIT_FIXUPS)
173 {
174 pPrivateGenWriter->setEmitFixups();
175 }
176#endif
177
178 pPEWriter.SuppressRelease();
179 pPrivateGenWriter.SuppressRelease();
180 pGenWriter = pPrivateGenWriter;
181
182ErrExit:
183 return hr;
184} // HRESULT CeeFileGenWriter::CreateNewInstance()
185
186CeeFileGenWriter::CeeFileGenWriter() // ctor is protected
187{
188 m_outputFileName = NULL;
189 m_resourceFileName = NULL;
190 m_dllSwitch = false;
191 m_objSwitch = false;
192 m_libraryName = NULL;
193 m_libraryGuid = GUID_NULL;
194
195 m_entryPoint = 0;
196 m_comImageFlags = COMIMAGE_FLAGS_ILONLY; // ceegen PEs don't have native code
197 m_iatOffset = 0;
198 m_dllCount = 0;
199
200 m_dwMacroDefinitionSize = 0;
201 m_dwMacroDefinitionRVA = NULL;
202
203 m_dwManifestSize = 0;
204 m_dwManifestRVA = NULL;
205
206 m_dwStrongNameSize = 0;
207 m_dwStrongNameRVA = NULL;
208
209 m_dwVTableSize = 0;
210 m_dwVTableRVA = NULL;
211
212 m_iDataDlls = NULL;
213
214 m_linked = false;
215 m_fixed = false;
216
217#ifdef EMIT_FIXUPS
218
219 m_fEmitFixups = false;
220 m_fFixupsUpdated = false;
221 m_sectionFixups = NULL;
222 m_pDebugDir = NULL;
223
224#endif
225
226#ifdef ENC_DELTA_HACK
227 // for EnC we want the RVA to be right at the front of the IL stream
228 PathString szFileName;
229 DWORD len = WszGetEnvironmentVariable(W("COMP_ENC_EMIT"), szFileName);
230 if (len > 0)
231 g_EnCMode = TRUE;
232#endif
233
234} // CeeFileGenWriter::CeeFileGenWriter()
235
236//*****************************************************************************
237// Cleanup
238//*****************************************************************************
239HRESULT CeeFileGenWriter::Cleanup() // virtual
240{
241 ((PEWriter *)m_peSectionMan)->Cleanup(); // call derived cleanup
242 delete m_peSectionMan;
243 m_peSectionMan = NULL; // so base class won't delete
244
245 delete[] m_outputFileName;
246 delete[] m_resourceFileName;
247
248 if (m_iDataDlls) {
249 for (int i=0; i < m_dllCount; i++) {
250 if (m_iDataDlls[i].m_methodName)
251 delete[] m_iDataDlls[i].m_methodName;
252 }
253 delete[] m_iDataDlls;
254 }
255
256 return CCeeGen::Cleanup();
257} // HRESULT CeeFileGenWriter::Cleanup()
258
259HRESULT CeeFileGenWriter::EmitMacroDefinitions(void *pData, DWORD cData)
260{
261 // OBSOLETE
262 m_dwMacroDefinitionSize = 0;
263
264 return S_OK;
265} // HRESULT CeeFileGenWriter::EmitMacroDefinitions()
266
267HRESULT CeeFileGenWriter::link()
268{
269 HRESULT hr = checkForErrors();
270 if (! SUCCEEDED(hr))
271 return hr;
272
273#ifdef EMIT_FIXUPS
274
275 // The fixups describe each relocation. Each fixup contains the relocation's
276 // type, source RVA, and target RVA. Since the reloc target can be filled
277 // in after the relocation creation, the fixup target RVA discovery needs to
278 // be deferred.
279 // At this point all bytes should be filled in, ensuring that the final
280 // target information is available.
281 // UpdateFixups is called at this point to discover the final relocation target info.
282 //
283 hr = UpdateFixups();
284 if (! SUCCEEDED(hr))
285 return hr;
286
287#endif
288
289 // Don't set this if SetManifestEntry was not called - zapper sets the
290 // resource directory explicitly
291 if (m_dwManifestSize != 0)
292 {
293 m_corHeader->Resources.VirtualAddress = VAL32(m_dwManifestRVA);
294 m_corHeader->Resources.Size = VAL32(m_dwManifestSize);
295 }
296
297 if (m_dwStrongNameSize != 0)
298 {
299 m_corHeader->StrongNameSignature.VirtualAddress = VAL32(m_dwStrongNameRVA);
300 m_corHeader->StrongNameSignature.Size = VAL32(m_dwStrongNameSize);
301 }
302
303 if (m_dwVTableSize != 0)
304 {
305 m_corHeader->VTableFixups.VirtualAddress = VAL32(m_dwVTableRVA);
306 m_corHeader->VTableFixups.Size = VAL32(m_dwVTableSize);
307 }
308
309 unsigned characteristicsMask = IMAGE_FILE_EXECUTABLE_IMAGE;
310
311 if (getPEWriter().isPE32())
312 characteristicsMask |= IMAGE_FILE_32BIT_MACHINE;
313 if (!getPEWriter().isPE32())
314 characteristicsMask |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
315
316 getPEWriter().setCharacteristics(characteristicsMask);
317
318 m_corHeader->cb = VAL32(sizeof(IMAGE_COR20_HEADER));
319 m_corHeader->MajorRuntimeVersion = VAL16(COR_VERSION_MAJOR);
320 m_corHeader->MinorRuntimeVersion = VAL16(COR_VERSION_MINOR);
321 if (m_dllSwitch)
322 getPEWriter().setCharacteristics(IMAGE_FILE_DLL);
323 if (m_objSwitch)
324 getPEWriter().clearCharacteristics(IMAGE_FILE_DLL | IMAGE_FILE_EXECUTABLE_IMAGE);
325 m_corHeader->Flags = VAL32(m_comImageFlags);
326 IMAGE_COR20_HEADER_FIELD(*m_corHeader, EntryPointToken) = VAL32(m_entryPoint);
327 _ASSERTE(TypeFromToken(m_entryPoint) == mdtMethodDef || m_entryPoint == mdTokenNil ||
328 TypeFromToken(m_entryPoint) == mdtFile);
329 setDirectoryEntry(getCorHeaderSection(), IMAGE_DIRECTORY_ENTRY_COMHEADER, sizeof(IMAGE_COR20_HEADER), m_corHeaderOffset);
330
331 if ((m_comImageFlags & COMIMAGE_FLAGS_IL_LIBRARY) == 0
332 && !m_linked && !m_objSwitch)
333 {
334 hr = emitExeMain();
335 if (FAILED(hr))
336 return hr;
337#ifndef FEATURE_PAL
338 hr = emitResourceSection();
339 if (FAILED(hr))
340 return hr;
341#endif
342 }
343
344 m_linked = true;
345
346 IfFailRet(getPEWriter().link());
347
348 return S_OK;
349} // HRESULT CeeFileGenWriter::link()
350
351
352HRESULT CeeFileGenWriter::fixup()
353{
354 HRESULT hr;
355
356 m_fixed = true;
357
358 if (!m_linked)
359 IfFailRet(link());
360
361 CeeGenTokenMapper *pMapper = getTokenMapper();
362
363 // Apply token remaps if there are any.
364 if (! m_fTokenMapSupported && pMapper != NULL) {
365 IMetaDataImport *pImport;
366 hr = pMapper->GetMetaData(&pImport);
367 _ASSERTE(SUCCEEDED(hr));
368 hr = MapTokens(pMapper, pImport);
369 pImport->Release();
370
371 }
372
373 // remap the entry point if entry point token has been moved
374 if (pMapper != NULL && !m_objSwitch)
375 {
376 mdToken tk = m_entryPoint;
377 pMapper->HasTokenMoved(tk, tk);
378 IMAGE_COR20_HEADER_FIELD(*m_corHeader, EntryPointToken) = VAL32(tk);
379 }
380
381 IfFailRet(getPEWriter().fixup(pMapper));
382
383 return S_OK;
384} // HRESULT CeeFileGenWriter::fixup()
385
386HRESULT CeeFileGenWriter::generateImage(void **ppImage)
387{
388 HRESULT hr = S_OK;
389 LPCWSTR outputFileName = NULL;
390
391#ifndef FEATURE_PAL
392 HANDLE hThreadToken = NULL;
393 // Impersonation is only supported on Win2k and above.
394 if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE, TRUE, &hThreadToken))
395 {
396 if (GetLastError() != ERROR_NO_TOKEN)
397 {
398 _ASSERTE(!"Failed to get thread token!");
399 return HRESULT_FROM_GetLastError();
400 }
401 }
402
403 if (hThreadToken != NULL)
404 {
405 if (!RevertToSelf())
406 {
407 _ASSERTE(!"Failed to revert impersonation!");
408 CloseHandle(hThreadToken);
409 return HRESULT_FROM_GetLastError();
410 }
411 }
412#endif // !FEATURE_PAL
413
414#ifdef ENC_DELTA_HACK
415 // fixups break because we've set the base RVA to 0 for the delta stream
416 if (! g_EnCMode)
417#endif
418 if (!m_fixed)
419 IfFailGo(fixup());
420
421 outputFileName = m_outputFileName;
422
423 if (! outputFileName && ppImage == NULL) {
424 if (m_comImageFlags & COMIMAGE_FLAGS_IL_LIBRARY)
425 outputFileName = W("output.ill");
426 else if (m_dllSwitch)
427 outputFileName = W("output.dll");
428 else if (m_objSwitch)
429 outputFileName = W("output.exe");
430 else
431 outputFileName = W("output.obj");
432 }
433
434 // output file name and ppImage are mutually exclusive
435 _ASSERTE((NULL == outputFileName && ppImage != NULL) || (outputFileName != NULL && NULL == ppImage));
436
437 if (outputFileName != NULL)
438 IfFailGo(getPEWriter().write(outputFileName));
439 else
440 IfFailGo(getPEWriter().write(ppImage));
441
442ErrExit:
443#ifndef FEATURE_PAL
444 if (hThreadToken != NULL)
445 {
446 BOOL success = SetThreadToken(NULL, hThreadToken);
447 CloseHandle(hThreadToken);
448
449 if (!success)
450 {
451 _ASSERTE(!"Failed to reimpersonate!");
452 hr = HRESULT_FROM_GetLastError();
453 }
454 }
455#endif // !FEATURE_PAL
456 return hr;
457} // HRESULT CeeFileGenWriter::generateImage()
458
459HRESULT CeeFileGenWriter::setOutputFileName(__in LPWSTR fileName)
460{
461 if (m_outputFileName)
462 delete[] m_outputFileName;
463 size_t len = wcslen(fileName) + 1;
464 m_outputFileName = (LPWSTR)new (nothrow) WCHAR[len];
465 TESTANDRETURN(m_outputFileName!=NULL, E_OUTOFMEMORY);
466 wcscpy_s(m_outputFileName, len, fileName);
467 return S_OK;
468} // HRESULT CeeFileGenWriter::setOutputFileName()
469
470HRESULT CeeFileGenWriter::setResourceFileName(__in LPWSTR fileName)
471{
472 if (m_resourceFileName)
473 delete[] m_resourceFileName;
474 size_t len = wcslen(fileName) + 1;
475 m_resourceFileName = (LPWSTR)new (nothrow) WCHAR[len];
476 TESTANDRETURN(m_resourceFileName!=NULL, E_OUTOFMEMORY);
477 wcscpy_s(m_resourceFileName, len, fileName);
478 return S_OK;
479} // HRESULT CeeFileGenWriter::setResourceFileName()
480
481HRESULT CeeFileGenWriter::setLibraryName(__in LPWSTR libraryName)
482{
483 if (m_libraryName)
484 delete[] m_libraryName;
485 size_t len = wcslen(libraryName) + 1;
486 m_libraryName = (LPWSTR)new (nothrow) WCHAR[len];
487 TESTANDRETURN(m_libraryName != NULL, E_OUTOFMEMORY);
488 wcscpy_s(m_libraryName, len, libraryName);
489 return S_OK;
490} // HRESULT CeeFileGenWriter::setLibraryName()
491
492HRESULT CeeFileGenWriter::setLibraryGuid(__in LPWSTR libraryGuid)
493{
494 return IIDFromString(libraryGuid, &m_libraryGuid);
495} // HRESULT CeeFileGenWriter::setLibraryGuid()
496
497HRESULT CeeFileGenWriter::emitLibraryName(IMetaDataEmit *emitter)
498{
499 HRESULT hr;
500 IfFailRet(emitter->SetModuleProps(m_libraryName));
501
502 // Set the GUID as a custom attribute, if it is not NULL_GUID.
503 if (m_libraryGuid != GUID_NULL)
504 {
505 static COR_SIGNATURE _SIG[] = INTEROP_GUID_SIG;
506 mdTypeRef tr;
507 mdMemberRef mr;
508 WCHAR wzGuid[40];
509 BYTE rgCA[50];
510 IfFailRet(emitter->DefineTypeRefByName(mdTypeRefNil, INTEROP_GUID_TYPE_W, &tr));
511 IfFailRet(emitter->DefineMemberRef(tr, W(".ctor"), _SIG, sizeof(_SIG), &mr));
512 StringFromGUID2(m_libraryGuid, wzGuid, lengthof(wzGuid));
513 memset(rgCA, 0, sizeof(rgCA));
514 // Tag is 0x0001
515 rgCA[0] = 1;
516 // Length of GUID string is 36 characters.
517 rgCA[2] = 0x24;
518 // Convert 36 characters, skipping opening {, into 3rd byte of buffer.
519 WszWideCharToMultiByte(CP_ACP,0, wzGuid+1,36, reinterpret_cast<char*>(&rgCA[3]),36, 0,0);
520 hr = emitter->DefineCustomAttribute(1,mr,rgCA,41,0);
521 }
522 return (hr);
523} // HRESULT CeeFileGenWriter::emitLibraryName()
524
525HRESULT CeeFileGenWriter::setImageBase(size_t imageBase)
526{
527 _ASSERTE(getPEWriter().isPE32());
528 getPEWriter().setImageBase32((DWORD)imageBase);
529 return S_OK;
530} // HRESULT CeeFileGenWriter::setImageBase()
531
532HRESULT CeeFileGenWriter::setImageBase64(ULONGLONG imageBase)
533{
534 _ASSERTE(!getPEWriter().isPE32());
535 getPEWriter().setImageBase64(imageBase);
536 return S_OK;
537} // HRESULT CeeFileGenWriter::setImageBase64()
538
539HRESULT CeeFileGenWriter::setFileAlignment(ULONG fileAlignment)
540{
541 getPEWriter().setFileAlignment(fileAlignment);
542 return S_OK;
543} // HRESULT CeeFileGenWriter::setFileAlignment()
544
545HRESULT CeeFileGenWriter::setSubsystem(DWORD subsystem, DWORD major, DWORD minor)
546{
547 getPEWriter().setSubsystem(subsystem, major, minor);
548 return S_OK;
549} // HRESULT CeeFileGenWriter::setSubsystem()
550
551HRESULT CeeFileGenWriter::checkForErrors()
552{
553 if (TypeFromToken(m_entryPoint) == mdtMethodDef) {
554 if (m_dllSwitch) {
555 //current spec would need to check the binary sig of the entry point method
556 }
557 return S_OK;
558 }
559 return S_OK;
560} // HRESULT CeeFileGenWriter::checkForErrors()
561
562HRESULT CeeFileGenWriter::getMethodRVA(ULONG codeOffset, ULONG *codeRVA)
563{
564 _ASSERTE(codeRVA);
565#ifdef ENC_DELTA_HACK
566 // for EnC we want the RVA to be right be relative to the front of the delta IL stream rather
567 // than take into account the .text section and the cor header as we would for a real PE file
568 if (g_EnCMode)
569 *codeRVA = codeOffset;
570 else
571#endif
572 *codeRVA = getPEWriter().getIlRva() + codeOffset;
573 return S_OK;
574} // HRESULT CeeFileGenWriter::getMethodRVA()
575
576HRESULT CeeFileGenWriter::setDirectoryEntry(CeeSection &section, ULONG entry, ULONG size, ULONG offset)
577{
578 return getPEWriter().setDirectoryEntry((PEWriterSection*)(&section.getImpl()), entry, size, offset);
579} // HRESULT CeeFileGenWriter::setDirectoryEntry()
580
581HRESULT CeeFileGenWriter::getFileTimeStamp(DWORD *pTimeStamp)
582{
583 return getPEWriter().getFileTimeStamp(pTimeStamp);
584} // HRESULT CeeFileGenWriter::getFileTimeStamp()
585
586HRESULT CeeFileGenWriter::setAddrReloc(UCHAR *instrAddr, DWORD value)
587{
588 *(DWORD *)instrAddr = VAL32(value);
589 return S_OK;
590} // HRESULT CeeFileGenWriter::setAddrReloc()
591
592HRESULT CeeFileGenWriter::addAddrReloc(CeeSection &thisSection, UCHAR *instrAddr, DWORD offset, CeeSection *targetSection)
593{
594 if (!targetSection) {
595 thisSection.addBaseReloc(offset, srRelocHighLow);
596 } else {
597 thisSection.addSectReloc(offset, *targetSection, srRelocHighLow);
598 }
599 return S_OK;
600} // HRESULT CeeFileGenWriter::addAddrReloc()
601
602// create CorExeMain and import directory into .text and the .iat into .data
603//
604// The structure of the import directory information is as follows, but it is not contiguous in
605// section. All the r/o data goes into the .text section and the iat array (which the loader
606// updates with the imported addresses) goes into the .data section because WINCE needs it to be writable.
607//
608// struct IData {
609// // one for each DLL, terminating in NULL
610// IMAGE_IMPORT_DESCRIPTOR iid[];
611// // import lookup table: a set of entries for the methods of each DLL,
612// // terminating each set with NULL
613// IMAGE_THUNK_DATA32/64 ilt[];
614// // hint/name table: an set of entries for each method of each DLL wiht
615// // no terminating entry
616// struct {
617// WORD Hint;
618// // null terminated string
619// BYTE Name[];
620// } ibn; // Hint/name table
621// // import address table: a set of entries for the methods of each DLL,
622// // terminating each set with NULL
623// IMAGE_THUNK_DATA32/64 iat[];
624// // one for each DLL, null terminated strings
625// BYTE DllName[];
626// };
627//
628
629// IAT must be first in its section, so have code here to allocate it up front
630// prior to knowing other info such as if dll or not. This won't work if have > 1
631// function imported, but we'll burn that bridge when we get to it.
632HRESULT CeeFileGenWriter::allocateIAT()
633{
634 m_dllCount = 1;
635 m_iDataDlls = new (nothrow) IDataDllInfo[m_dllCount];
636 if (m_iDataDlls == NULL) {
637 return E_OUTOFMEMORY;
638 }
639 memset(m_iDataDlls, '\0', m_dllCount * sizeof(IDataDllInfo));
640 m_iDataDlls[0].m_name = "mscoree.dll";
641 m_iDataDlls[0].m_numMethods = 1;
642 m_iDataDlls[0].m_methodName = new (nothrow) const char*[m_iDataDlls[0].m_numMethods];
643 if (! m_iDataDlls[0].m_methodName) {
644 return E_OUTOFMEMORY;
645 }
646 m_iDataDlls[0].m_methodName[0] = NULL;
647
648 int iDataSizeIAT = 0;
649
650 for (int i=0; i < m_dllCount; i++) {
651 m_iDataDlls[i].m_iatOffset = iDataSizeIAT;
652 iDataSizeIAT += (m_iDataDlls[i].m_numMethods + 1)
653 * (getPEWriter().isPE32() ? sizeof(IMAGE_THUNK_DATA32)
654 : sizeof(IMAGE_THUNK_DATA64));
655 }
656
657 HRESULT hr = getSectionCreate(".text0", sdExecute, &m_iDataSectionIAT);
658 TESTANDRETURNHR(hr);
659 m_iDataOffsetIAT = m_iDataSectionIAT->dataLen();
660 _ASSERTE(m_iDataOffsetIAT == 0);
661 m_iDataIAT = m_iDataSectionIAT->getBlock(iDataSizeIAT);
662 if (! m_iDataIAT) {
663 return E_OUTOFMEMORY;
664 }
665 memset(m_iDataIAT, '\0', iDataSizeIAT);
666
667 // Don't set the IAT directory entry yet, since we may not actually end up doing
668 // an emitExeMain.
669
670 return S_OK;
671} // HRESULT CeeFileGenWriter::allocateIAT()
672
673HRESULT CeeFileGenWriter::emitExeMain()
674{
675 if (m_dllCount == 0)
676 return S_OK;
677
678 // Note: code later on in this method assumes that mscoree.dll is at
679 // index m_iDataDlls[0], with CorDllMain or CorExeMain at method[0]
680
681 _ASSERTE(getPEWriter().createCorMainStub());
682
683 if (m_dllSwitch) {
684 m_iDataDlls[0].m_methodName[0] = "_CorDllMain";
685 } else {
686 m_iDataDlls[0].m_methodName[0] = "_CorExeMain";
687 }
688
689 // IMAGE_IMPORT_DESCRIPTOR on PE/PE+ must be 4-byte or 8-byte aligned
690 int align = (getPEWriter().isPE32()) ? 4 : 8;
691 int curOffset = getTextSection().dataLen();
692
693 int diff = ((curOffset + align -1) & ~(align-1)) - curOffset;
694 if (diff)
695 {
696 char* pDiff = getTextSection().getBlock(diff);
697 if (NULL==pDiff) return E_OUTOFMEMORY;
698 memset(pDiff,0,diff);
699 }
700
701 int iDataSizeRO = (m_dllCount + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
702 CeeSection &iDataSectionRO = getTextSection();
703 int iDataOffsetRO = iDataSectionRO.dataLen();
704 int iDataSizeIAT = 0;
705 int i;
706 for (i=0; i < m_dllCount; i++) {
707 m_iDataDlls[i].m_iltOffset = iDataSizeRO + iDataSizeIAT;
708 iDataSizeIAT += (m_iDataDlls[i].m_numMethods + 1)
709 * (getPEWriter().isPE32() ? sizeof(IMAGE_THUNK_DATA32)
710 : sizeof(IMAGE_THUNK_DATA64));
711 }
712
713 iDataSizeRO += iDataSizeIAT;
714
715 for (i=0; i < m_dllCount; i++) {
716 int delta = (iDataSizeRO + iDataOffsetRO) % 16;
717 // make sure is on a 16-byte offset
718 if (delta != 0)
719 iDataSizeRO += (16 - delta);
720 _ASSERTE((iDataSizeRO + iDataOffsetRO) % 16 == 0);
721 m_iDataDlls[i].m_ibnOffset = iDataSizeRO;
722 for (int j=0; j < m_iDataDlls[i].m_numMethods; j++) {
723 int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
724 iDataSizeRO += sizeof(WORD) + nameLen + nameLen%2;
725 }
726 }
727 for (i=0; i < m_dllCount; i++) {
728 m_iDataDlls[i].m_nameOffset = iDataSizeRO;
729 iDataSizeRO += (int)(strlen(m_iDataDlls[i].m_name) + 2);
730 }
731
732 char *iDataRO = iDataSectionRO.getBlock(iDataSizeRO);
733
734 if (!iDataRO) return E_OUTOFMEMORY;
735
736 memset(iDataRO, '\0', iDataSizeRO);
737
738 setDirectoryEntry(iDataSectionRO, IMAGE_DIRECTORY_ENTRY_IMPORT, iDataSizeRO, iDataOffsetRO);
739
740 IMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)iDataRO;
741 for (i=0; i < m_dllCount; i++) {
742
743 // fill in the import descriptors for each DLL
744 IMAGE_IMPORT_DESC_FIELD(iid[i], OriginalFirstThunk) = VAL32((ULONG)(m_iDataDlls[i].m_iltOffset + iDataOffsetRO));
745 iid[i].Name = VAL32(m_iDataDlls[i].m_nameOffset + iDataOffsetRO);
746 iid[i].FirstThunk = VAL32((ULONG)(m_iDataDlls[i].m_iatOffset + m_iDataOffsetIAT));
747
748 iDataSectionRO.addSectReloc(
749 (unsigned)(iDataOffsetRO + (char *)(&IMAGE_IMPORT_DESC_FIELD(iid[i], OriginalFirstThunk)) - iDataRO), iDataSectionRO, srRelocAbsolute);
750 iDataSectionRO.addSectReloc(
751 (unsigned)(iDataOffsetRO + (char *)(&iid[i].Name) - iDataRO), iDataSectionRO, srRelocAbsolute);
752 iDataSectionRO.addSectReloc(
753 (unsigned)(iDataOffsetRO + (char *)(&iid[i].FirstThunk) - iDataRO), *m_iDataSectionIAT, srRelocAbsolute);
754
755 if (getPEWriter().isPE32())
756 {
757 // now fill in the import lookup table for each DLL
758 IMAGE_THUNK_DATA32 *ilt = (IMAGE_THUNK_DATA32*) (iDataRO + m_iDataDlls[i].m_iltOffset);
759 IMAGE_THUNK_DATA32 *iat = (IMAGE_THUNK_DATA32*) (m_iDataIAT + m_iDataDlls[i].m_iatOffset);
760
761 int ibnOffset = m_iDataDlls[i].m_ibnOffset;
762 for (int j=0; j < m_iDataDlls[i].m_numMethods; j++)
763 {
764 ilt[j].u1.AddressOfData = VAL32((ULONG)(ibnOffset + iDataOffsetRO));
765 iat[j].u1.AddressOfData = VAL32((ULONG)(ibnOffset + iDataOffsetRO));
766
767 iDataSectionRO.addSectReloc( (unsigned)(iDataOffsetRO + (char *)(&ilt[j].u1.AddressOfData) - iDataRO),
768 iDataSectionRO, srRelocAbsolute);
769 m_iDataSectionIAT->addSectReloc( (unsigned)(m_iDataOffsetIAT + (char *)(&iat[j].u1.AddressOfData) - m_iDataIAT),
770 iDataSectionRO, srRelocAbsolute);
771 int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
772 memcpy(iDataRO + ibnOffset + offsetof(IMAGE_IMPORT_BY_NAME, Name),
773 m_iDataDlls[i].m_methodName[j], nameLen);
774 ibnOffset += sizeof(WORD) + nameLen + nameLen%2;
775 }
776 }
777 else
778 {
779 // now fill in the import lookup table for each DLL
780 IMAGE_THUNK_DATA64 *ilt = (IMAGE_THUNK_DATA64*) (iDataRO + m_iDataDlls[i].m_iltOffset);
781 IMAGE_THUNK_DATA64 *iat = (IMAGE_THUNK_DATA64*) (m_iDataIAT + m_iDataDlls[i].m_iatOffset);
782
783 int ibnOffset = m_iDataDlls[i].m_ibnOffset;
784 for (int j=0; j < m_iDataDlls[i].m_numMethods; j++)
785 {
786 ilt[j].u1.AddressOfData = VAL64((ULONG)(ibnOffset + iDataOffsetRO));
787 iat[j].u1.AddressOfData = VAL64((ULONG)(ibnOffset + iDataOffsetRO));
788
789 iDataSectionRO.addSectReloc( (unsigned)(iDataOffsetRO + (char *)(&ilt[j].u1.AddressOfData) - iDataRO),
790 iDataSectionRO, srRelocAbsolute);
791 m_iDataSectionIAT->addSectReloc( (unsigned)(m_iDataOffsetIAT + (char *)(&iat[j].u1.AddressOfData) - m_iDataIAT),
792 iDataSectionRO, srRelocAbsolute);
793 int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
794 memcpy(iDataRO + ibnOffset + offsetof(IMAGE_IMPORT_BY_NAME, Name),
795 m_iDataDlls[i].m_methodName[j], nameLen);
796 ibnOffset += sizeof(WORD) + nameLen + nameLen%2;
797 }
798 }
799
800 // now fill in the import lookup table for each DLL
801 strcpy_s(iDataRO + m_iDataDlls[i].m_nameOffset,
802 iDataSizeRO - m_iDataDlls[i].m_nameOffset,
803 m_iDataDlls[i].m_name);
804
805 } // end of for loop i < m_dllCount
806
807
808 if (getPEWriter().isI386())
809 {
810 // Put the entry point code into the PE file
811 unsigned entryPointOffset = getTextSection().dataLen();
812 int iatOffset = (int) (entryPointOffset + (m_dllSwitch ? CorDllMainX86IATOffset : CorExeMainX86IATOffset));
813 align = 4; // x86 fixups must be 4-byte aligned
814
815 // The IAT offset must be aligned because fixup is applied to it.
816 diff = ((iatOffset + align -1) & ~(align-1)) - iatOffset;
817 if (diff)
818 {
819 char* pDiff = getTextSection().getBlock(diff);
820 if(NULL==pDiff) return E_OUTOFMEMORY;
821 memset(pDiff,0,diff);
822 entryPointOffset += diff;
823 }
824 _ASSERTE((getTextSection().dataLen() + (m_dllSwitch ? CorDllMainX86IATOffset : CorExeMainX86IATOffset)) % align == 0);
825
826 getPEWriter().setEntryPointTextOffset(entryPointOffset);
827 if (m_dllSwitch)
828 {
829 UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainX86Template));
830 if(dllMainBuf==NULL) return E_OUTOFMEMORY;
831 memcpy(dllMainBuf, DllMainX86Template, sizeof(DllMainX86Template));
832 //mscoree.dll
833 setAddrReloc(dllMainBuf+CorDllMainX86IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
834 addAddrReloc(getTextSection(), dllMainBuf, entryPointOffset+CorDllMainX86IATOffset, m_iDataSectionIAT);
835 }
836 else
837 {
838 UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainX86Template));
839 if(exeMainBuf==NULL) return E_OUTOFMEMORY;
840 memcpy(exeMainBuf, ExeMainX86Template, sizeof(ExeMainX86Template));
841 //mscoree.dll
842 setAddrReloc(exeMainBuf+CorExeMainX86IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
843 addAddrReloc(getTextSection(), exeMainBuf, entryPointOffset+CorExeMainX86IATOffset, m_iDataSectionIAT);
844 }
845 }
846 else if (getPEWriter().isAMD64())
847 {
848 // Put the entry point code into the PE file
849 unsigned entryPointOffset = getTextSection().dataLen();
850 int iatOffset = (int) (entryPointOffset + (m_dllSwitch ? CorDllMainAMD64IATOffset : CorExeMainAMD64IATOffset));
851 align = 16; // AMD64 fixups must be 8-byte aligned
852
853 // The IAT offset must be aligned because fixup is applied to it.
854 diff = ((iatOffset + align -1) & ~(align-1)) - iatOffset;
855 if (diff)
856 {
857 char* pDiff = getTextSection().getBlock(diff);
858 if(NULL==pDiff) return E_OUTOFMEMORY;
859 memset(pDiff,0,diff);
860 entryPointOffset += diff;
861 }
862 _ASSERTE((getTextSection().dataLen() + (m_dllSwitch ? CorDllMainAMD64IATOffset : CorExeMainAMD64IATOffset)) % align == 0);
863
864 getPEWriter().setEntryPointTextOffset(entryPointOffset);
865 if (m_dllSwitch)
866 {
867 UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainAMD64Template));
868 if(dllMainBuf==NULL) return E_OUTOFMEMORY;
869 memcpy(dllMainBuf, DllMainAMD64Template, sizeof(DllMainAMD64Template));
870 //mscoree.dll
871 setAddrReloc(dllMainBuf+CorDllMainAMD64IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
872 addAddrReloc(getTextSection(), dllMainBuf, entryPointOffset+CorDllMainAMD64IATOffset, m_iDataSectionIAT);
873 }
874 else
875 {
876 UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainAMD64Template));
877 if(exeMainBuf==NULL) return E_OUTOFMEMORY;
878 memcpy(exeMainBuf, ExeMainAMD64Template, sizeof(ExeMainAMD64Template));
879 //mscoree.dll
880 setAddrReloc(exeMainBuf+CorExeMainAMD64IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
881 addAddrReloc(getTextSection(), exeMainBuf, entryPointOffset+CorExeMainAMD64IATOffset, m_iDataSectionIAT);
882 }
883 }
884 else if (getPEWriter().isIA64())
885 {
886 // Must have a PE+ PE64 file
887 //_ASSERTE(!getPEWriter().isPE32());
888
889 // Put the entry point code into the PE+ file
890 curOffset = getTextSection().dataLen();
891 align = 16; // instructions on ia64 must be 16-byte aligned
892
893 // The entry point address be aligned
894 diff = ((curOffset + align -1) & ~(align-1)) - curOffset;
895 if (diff)
896 {
897 char* pDiff = getTextSection().getBlock(diff);
898 if(NULL==pDiff) return E_OUTOFMEMORY;
899 memset(pDiff,0,diff);
900 }
901
902 unsigned entryPointOffset = getTextSection().dataLen();
903
904 if (m_dllSwitch)
905 {
906 UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainIA64Template));
907 if (dllMainBuf==NULL) return E_OUTOFMEMORY;
908 memcpy(dllMainBuf, DllMainIA64Template, sizeof(DllMainIA64Template));
909 }
910 else
911 {
912 UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainIA64Template));
913 if (exeMainBuf==NULL) return E_OUTOFMEMORY;
914 memcpy(exeMainBuf, ExeMainIA64Template, sizeof(ExeMainIA64Template));
915 }
916
917 // Put the entry point function pointer into the PE file
918 unsigned entryPlabelOffset = getTextSection().dataLen();
919 getPEWriter().setEntryPointTextOffset(entryPlabelOffset);
920
921 UCHAR * entryPtr = (UCHAR*)getTextSection().getBlock(sizeof(ULONGLONG));
922 UCHAR * gpPtr = (UCHAR*)getTextSection().getBlock(sizeof(ULONGLONG));
923
924 memset(entryPtr,0,sizeof(ULONGLONG));
925 memset(gpPtr,0,sizeof(ULONGLONG));
926
927 setAddrReloc(entryPtr, entryPointOffset);
928 addAddrReloc(getTextSection(), entryPtr, entryPlabelOffset, &getTextSection());
929
930 setAddrReloc(gpPtr, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
931 addAddrReloc(getTextSection(), gpPtr, entryPlabelOffset+8, m_iDataSectionIAT);
932 }
933 else
934 {
935 _ASSERTE(!"Unknown target machine");
936 }
937
938 // Now set our IAT entry since we're using the IAT
939 setDirectoryEntry(*m_iDataSectionIAT, IMAGE_DIRECTORY_ENTRY_IAT, iDataSizeIAT, m_iDataOffsetIAT);
940
941 return S_OK;
942} // HRESULT CeeFileGenWriter::emitExeMain()
943
944
945HRESULT GetClrSystemDirectory(SString& pbuffer)
946{
947 HRESULT hr = S_OK;
948
949
950 PathString pPath;
951 DWORD dwPath;
952
953 _ASSERTE (g_hThisInst);
954
955 dwPath = WszGetModuleFileName(g_hThisInst, pPath);
956 if(dwPath == 0)
957 {
958 hr = HRESULT_FROM_GetLastErrorNA();
959 return (hr);
960 }
961
962 return CopySystemDirectory(pPath, pbuffer);
963}
964
965#ifndef FEATURE_PAL
966BOOL RunProcess(LPCWSTR tempResObj, LPCWSTR pszFilename, DWORD* pdwExitCode, PEWriter &pewriter)
967{
968 BOOL fSuccess = FALSE;
969
970 PROCESS_INFORMATION pi;
971
972 PathString wszSystemDir;
973 if (FAILED(GetClrSystemDirectory(wszSystemDir)))
974 return FALSE;
975
976 const WCHAR* wzMachine;
977 if(pewriter.isIA64())
978 wzMachine = L"IA64";
979 else if(pewriter.isAMD64())
980 wzMachine = L"AMD64";
981 else if(pewriter.isARM())
982 wzMachine = L"ARM";
983 else
984 wzMachine = L"IX86";
985
986 // Res file, so convert it
987 StackSString ssCmdLine;
988
989 LPWSTR ext = PathFindExtension(pszFilename);
990 if(*ext == NULL)
991 {
992 ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s.\"",
993 wszSystemDir.GetUnicode(),
994 wzMachine,
995 tempResObj,
996 pszFilename);
997 }
998 else
999 {
1000 ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s\"",
1001 wszSystemDir.GetUnicode(),
1002 wzMachine,
1003 tempResObj,
1004 pszFilename);
1005 }
1006
1007 STARTUPINFOW start;
1008 ZeroMemory(&start, sizeof(start));
1009 start.cb = sizeof(start);
1010 start.dwFlags = STARTF_USESHOWWINDOW;
1011 start.wShowWindow = SW_HIDE;
1012
1013 fSuccess = WszCreateProcess(
1014 NULL,
1015 ssCmdLine.GetUnicode(),
1016 NULL,
1017 NULL,
1018 true,
1019 0,
1020 0,
1021 NULL,
1022 &start,
1023 &pi);
1024
1025 // If process runs, wait for it to finish
1026 if (fSuccess) {
1027 WaitForSingleObject(pi.hProcess, INFINITE);
1028
1029 GetExitCodeProcess(pi.hProcess, pdwExitCode);
1030
1031 CloseHandle(pi.hProcess);
1032
1033 CloseHandle(pi.hThread);
1034 }
1035 return fSuccess;
1036} // BOOL RunProcess()
1037
1038// Ensure that pszFilename is an object file (not just a binary resource)
1039// If we convert, then return obj filename in pszTempFilename
1040HRESULT ConvertResource(const WCHAR * pszFilename, __in_ecount(cchTempFilename) WCHAR *pszTempFilename, size_t cchTempFilename, PEWriter &pewriter)
1041{
1042 HANDLE hFile = WszCreateFile(pszFilename, GENERIC_READ,
1043 FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1044
1045// failure
1046 if (!hFile || (hFile == INVALID_HANDLE_VALUE))
1047 {
1048 //dbprintf("Can't find resource files:%S\n", pszFilename);
1049 return HRESULT_FROM_GetLastError();
1050 }
1051
1052// Read first 4 bytes. If they're all 0, we have a win32 .res file which must be
1053// converted. (So call CvtRes.exe). Else it's an obj file.
1054
1055 DWORD dwCount = -1;
1056 DWORD dwData = -1;
1057
1058 BOOL fRet = ReadFile(hFile,
1059 &dwData,
1060 4,
1061 &dwCount,
1062 NULL
1063 );
1064
1065 CloseHandle(hFile);
1066
1067 if (!fRet) {
1068 //dbprintf("Invalid resource file:%S\n", pszFilename);
1069 return HRESULT_FROM_GetLastError();
1070 }
1071
1072 if (dwData != 0)
1073 {
1074 return S_OK;
1075 }
1076
1077 PathString tempResObj;
1078 PathString tempResPath;
1079
1080 // Create the temp file where the temp path is at rather than where the application is at.
1081 if (!WszGetTempPath( tempResPath))
1082 {
1083 return HRESULT_FROM_GetLastError();
1084 }
1085
1086 if (!WszGetTempFileName(tempResPath, L"RES", 0, tempResObj))
1087 {
1088 //dbprintf("GetTempFileName failed\n");
1089 return HRESULT_FROM_GetLastError();
1090 }
1091
1092 DWORD dwExitCode;
1093 fRet = RunProcess(tempResObj, pszFilename, &dwExitCode, pewriter);
1094
1095 if (!fRet)
1096 { // Couldn't run cvtres.exe
1097 return PostError(CEE_E_CVTRES_NOT_FOUND);
1098 }
1099 else if (dwExitCode != 0)
1100 { // CvtRes.exe ran, but failed
1101 return HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1102 }
1103 else
1104 { // Conversion succesful, so return filename.
1105 wcscpy_s(pszTempFilename, cchTempFilename, tempResObj);
1106 }
1107
1108 return S_OK;
1109} // HRESULT ConvertResource()
1110
1111
1112
1113// This function reads a resource file and emits it into the generated PE file.
1114// 1. We can only link resources in obj format. Must convert from .res to .obj
1115// with CvtRes.exe.
1116// 2. Must touch up all COFF relocs from .rsrc$01 (resource header) to .rsrc$02
1117// (resource raw data)
1118HRESULT CeeFileGenWriter::emitResourceSection()
1119{
1120 if (m_resourceFileName == NULL)
1121 return S_OK;
1122
1123 // Make sure szResFileName is an obj, not just a .res; change name if we convert
1124 WCHAR szTempFileName[MAX_PATH+1];
1125 szTempFileName[0] = L'\0';
1126 HRESULT hr = ConvertResource(m_resourceFileName, szTempFileName,
1127 MAX_PATH+1, getPEWriter());
1128 if (FAILED(hr)) return hr;
1129
1130 // Filename may change (if we convert .res to .obj), so have floating pointer
1131 const WCHAR* szResFileName;
1132 if (*szTempFileName)
1133 szResFileName = szTempFileName;
1134 else
1135 szResFileName = m_resourceFileName;
1136
1137 _ASSERTE(szResFileName);
1138
1139 // read the resource file and spit it out in the .rsrc section
1140
1141 HANDLE hFile = INVALID_HANDLE_VALUE;
1142 HANDLE hMap = NULL;
1143 IMAGE_FILE_HEADER *hMod = NULL;
1144
1145 hr = S_OK;
1146
1147 struct Param
1148 {
1149 HANDLE hFile;
1150 HANDLE hMap;
1151 IMAGE_FILE_HEADER *hMod;
1152 const WCHAR* szResFileName;
1153 CeeFileGenWriter *genWriter;
1154 HRESULT hr;
1155 } param;
1156
1157 param.hFile = hFile;
1158 param.hMap = hMap;
1159 param.hMod = hMod;
1160 param.szResFileName = szResFileName;
1161 param.genWriter = this;
1162 param.hr = S_OK;
1163
1164 PAL_TRY(Param *, pParam, &param)
1165 {
1166 SIZE_T cbFileSize;
1167 const BYTE *pbStartOfMappedMem;
1168 IMAGE_SECTION_HEADER *rsrc[2] = { NULL, NULL };
1169 S_SIZE_T cbTotalSizeOfRawData;
1170
1171 char *data = NULL;
1172 SIZE_T cReloc = 0;
1173 IMAGE_RELOCATION *pReloc = NULL;
1174 SIZE_T cSymbol = 0;
1175 IMAGE_SYMBOL *pSymbolTable = NULL;
1176
1177 // create a mapped view of the .res file
1178 pParam->hFile = WszCreateFile(pParam->szResFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1179 if (pParam->hFile == INVALID_HANDLE_VALUE)
1180 {
1181 //dbprintf("Resource file %S not found\n", szResFileName);
1182 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1183 goto lDone;
1184 }
1185
1186 // Grab the file size for verification checks.
1187 {
1188 DWORD dwFileSizeHigh;
1189 DWORD dwFileSize = SafeGetFileSize(pParam->hFile, &dwFileSizeHigh);
1190 if (dwFileSize == (DWORD)(-1))
1191 {
1192 pParam->hr = HRESULT_FROM_GetLastError();
1193 goto lDone;
1194 }
1195
1196 // Since we intend to memory map this file, the size of the file can not need 64 bits to represent!
1197 if (dwFileSizeHigh != 0)
1198 {
1199 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1200 goto lDone;
1201 }
1202
1203 cbFileSize = static_cast<SIZE_T>(dwFileSize);
1204 }
1205
1206 pParam->hMap = WszCreateFileMapping(pParam->hFile, 0, PAGE_READONLY, 0, 0, NULL);
1207
1208 if (pParam->hMap == NULL)
1209 {
1210 //dbprintf("Invalid .res file: %S\n", szResFileName);
1211 pParam->hr = HRESULT_FROM_GetLastError();
1212 goto lDone;
1213 }
1214
1215 pbStartOfMappedMem = reinterpret_cast<const BYTE *>(MapViewOfFile(pParam->hMap, FILE_MAP_READ, 0, 0, 0));
1216
1217 // test failure conditions
1218 if (pbStartOfMappedMem == NULL)
1219 {
1220 //dbprintf("Invalid .res file: %S:Can't get header\n", szResFileName);
1221 pParam->hr = HRESULT_FROM_GetLastError();
1222 goto lDone;
1223 }
1224
1225 // Check that the file contains an IMAGE_FILE_HEADER structure.
1226 if (IMAGE_SIZEOF_FILE_HEADER > cbFileSize)
1227 {
1228 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1229 goto lDone;
1230 }
1231
1232 pParam->hMod = (IMAGE_FILE_HEADER*)pbStartOfMappedMem;
1233
1234 if (VAL16(pParam->hMod->SizeOfOptionalHeader) != 0)
1235 {
1236 //dbprintf("Invalid .res file: %S:Illegal optional header\n", szResFileName);
1237 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); // GetLastError() = 0 since API worked.
1238 goto lDone;
1239 }
1240
1241 // Scan all section headers and grab .rsrc$01 and .rsrc$02
1242 {
1243 // First section is directly after header
1244 SIZE_T cSections = static_cast<SIZE_T>(VAL16(pParam->hMod->NumberOfSections));
1245 SIZE_T cbStartOfSections = IMAGE_SIZEOF_FILE_HEADER;
1246 S_SIZE_T cbEndOfSections(S_SIZE_T(cbStartOfSections) +
1247 (S_SIZE_T(cSections) * S_SIZE_T(IMAGE_SIZEOF_SECTION_HEADER)));
1248
1249 // Check that all sections are within the bounds of the mapped file.
1250 if (cbEndOfSections.IsOverflow() ||
1251 cbEndOfSections.Value() > cbFileSize)
1252 {
1253 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1254 goto lDone;
1255 }
1256
1257 {
1258 IMAGE_SECTION_HEADER *pSection =
1259 (IMAGE_SECTION_HEADER *)(pbStartOfMappedMem + cbStartOfSections);
1260 IMAGE_SECTION_HEADER *pSectionEnd = pSection + cSections;
1261
1262 for (; pSection < pSectionEnd; pSection++)
1263 {
1264 if (strcmp(".rsrc$01", (char *)pSection->Name) == 0)
1265 {
1266 rsrc[0] = pSection;
1267 }
1268 else if (strcmp(".rsrc$02", (char *)pSection->Name) == 0)
1269 {
1270 rsrc[1] = pSection;
1271 }
1272 }
1273 }
1274 }
1275
1276 // If we don't have both resources, fail.
1277 if (!rsrc[0] || !rsrc[1])
1278 {
1279 //dbprintf("Invalid .res file: %S: Missing sections .rsrc$01 or .rsrc$02\n", szResFileName);
1280 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1281 goto lDone;
1282 }
1283
1284 // Verify the resource data starts and sizes
1285 {
1286 cbTotalSizeOfRawData = S_SIZE_T(0);
1287
1288 for (int i = 0; i < 2; i++)
1289 {
1290 S_SIZE_T cbStartOfResourceData(static_cast<SIZE_T>(VAL32(rsrc[i]->PointerToRawData)));
1291 S_SIZE_T cbSizeOfResourceData(static_cast<SIZE_T>(VAL32(rsrc[i]->SizeOfRawData)));
1292 S_SIZE_T cbEndOfResourceData(cbStartOfResourceData + cbSizeOfResourceData);
1293
1294 if (cbEndOfResourceData.IsOverflow() ||
1295 cbEndOfResourceData.Value() > cbFileSize)
1296 {
1297 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1298 goto lDone;
1299 }
1300
1301 cbTotalSizeOfRawData += cbSizeOfResourceData;
1302 }
1303
1304 // Check that the total raw data doesn't overflow.
1305 if (cbTotalSizeOfRawData.IsOverflow() ||
1306 cbTotalSizeOfRawData.Value() > cbFileSize)
1307 {
1308 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1309 goto lDone;
1310 }
1311 }
1312
1313 PESection *rsrcSection;
1314 pParam->hr = pParam->genWriter->getPEWriter().getSectionCreate(".rsrc", sdReadOnly, &rsrcSection);
1315 if (FAILED(pParam->hr)) goto lDone;
1316
1317 rsrcSection->directoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
1318 data = rsrcSection->getBlock(static_cast<unsigned>(cbTotalSizeOfRawData.Value()), 8);
1319 if(data == NULL)
1320 {
1321 pParam->hr = E_OUTOFMEMORY;
1322 goto lDone;
1323 }
1324
1325 // Copy resource header
1326 memcpy(data, (char *)pParam->hMod + VAL32(rsrc[0]->PointerToRawData), VAL32(rsrc[0]->SizeOfRawData));
1327
1328 // Map all the relocs in .rsrc$01 using the reloc and symbol tables in the COFF object.,
1329 cReloc = 0; // Total number of relocs
1330 pReloc = NULL; // Reloc table start
1331
1332 cSymbol = 0; // Total number of symbols
1333 pSymbolTable = NULL; // Symbol table start
1334
1335 {
1336 // Check that the relocations and symbols lie within the resource
1337 cReloc = VAL16(rsrc[0]->NumberOfRelocations);
1338 SIZE_T cbStartOfRelocations = static_cast<SIZE_T>(VAL32(rsrc[0]->PointerToRelocations));
1339 S_SIZE_T cbEndOfRelocations(S_SIZE_T(cbStartOfRelocations) +
1340 (S_SIZE_T(cReloc) * S_SIZE_T(sizeof(IMAGE_RELOCATION))));
1341
1342
1343 // Verify the number of symbols fit into the resource.
1344 cSymbol = static_cast<SIZE_T>(VAL32(pParam->hMod->NumberOfSymbols));
1345 SIZE_T cbStartOfSymbolTable = static_cast<SIZE_T>(VAL32(pParam->hMod->PointerToSymbolTable));
1346 S_SIZE_T cbEndOfSymbolTable(S_SIZE_T(cbStartOfSymbolTable) +
1347 (S_SIZE_T(cSymbol) * S_SIZE_T(IMAGE_SIZEOF_SYMBOL)));
1348
1349 if (cbEndOfRelocations.IsOverflow() ||
1350 cbEndOfRelocations.Value() > cbFileSize ||
1351 cbEndOfSymbolTable.IsOverflow() ||
1352 cbEndOfSymbolTable.Value() > cbFileSize)
1353 {
1354 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1355 goto lDone;
1356 }
1357
1358 pReloc = (IMAGE_RELOCATION *)(pbStartOfMappedMem + cbStartOfRelocations);
1359 pSymbolTable = (IMAGE_SYMBOL *)(pbStartOfMappedMem + cbStartOfSymbolTable);
1360 }
1361
1362 _ASSERTE(pReloc != NULL && pSymbolTable != NULL);
1363
1364 for(SIZE_T iReloc = 0; iReloc < cReloc; iReloc++, pReloc++)
1365 {
1366 // Ensure this is a valid reloc
1367 {
1368 S_SIZE_T cbRelocEnd = S_SIZE_T(VAL32(pReloc->VirtualAddress)) + S_SIZE_T(sizeof(DWORD));
1369 if (cbRelocEnd.IsOverflow() ||
1370 cbRelocEnd.Value() > static_cast<SIZE_T>(VAL32(rsrc[0]->SizeOfRawData)))
1371 {
1372 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1373 goto lDone;
1374 }
1375 }
1376
1377 // index into symbol table, provides address into $02
1378 DWORD iSymbol = VAL32(pReloc->SymbolTableIndex);
1379
1380 // Make sure the index is in range
1381 if (iSymbol >= cSymbol)
1382 {
1383 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1384 goto lDone;
1385 }
1386
1387 IMAGE_SYMBOL* pSymbolEntry = GetSymbolEntry(pSymbolTable, iSymbol);
1388
1389 // Ensure the symbol entry is valid for a resource.
1390 if ((pSymbolEntry->StorageClass != IMAGE_SYM_CLASS_STATIC) ||
1391 (VAL16(pSymbolEntry->Type) != IMAGE_SYM_TYPE_NULL) ||
1392 (VAL16(pSymbolEntry->SectionNumber) != 3)) // 3rd section is .rsrc$02
1393 {
1394 //dbprintf("Invalid .res file: %S:Illegal symbol entry\n", szResFileName);
1395 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1396 goto lDone;
1397 }
1398
1399 // Ensure that RVA is valid address (inside rsrc[1])
1400 if (VAL32(pSymbolEntry->Value) >= VAL32(rsrc[1]->SizeOfRawData))
1401 {
1402 //dbprintf("Invalid .res file: %S:Illegal rva into .rsrc$02\n", szResFileName);
1403 pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1404 goto lDone;
1405 }
1406
1407 DWORD dwOffsetInRsrc2 = VAL32(pSymbolEntry->Value) + VAL32(rsrc[0]->SizeOfRawData);
1408
1409 // Create reloc
1410 *(DWORD*)(data + VAL32(pReloc->VirtualAddress)) = VAL32(dwOffsetInRsrc2);
1411 rsrcSection->addSectReloc(pReloc->VirtualAddress, rsrcSection, srRelocAbsolute);
1412 }
1413
1414 // Copy $02 (resource raw) data
1415 memcpy(data+VAL32(rsrc[0]->SizeOfRawData),
1416 (char *)pParam->hMod + VAL32(rsrc[1]->PointerToRawData),
1417 VAL32(rsrc[1]->SizeOfRawData));
1418
1419lDone: ;
1420 }
1421 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1422 {
1423 //dbprintf("Exception occured manipulating .res file %S\n", szResFileName);
1424 param.hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
1425 }
1426 PAL_ENDTRY
1427
1428 hMod = param.hMod;
1429 hFile = param.hFile;
1430 szResFileName = param.szResFileName;
1431 hr = param.hr;
1432
1433 if (hMod != NULL)
1434 UnmapViewOfFile(hMod);
1435 if (hMap != NULL)
1436 CloseHandle(hMap);
1437 if (hFile != INVALID_HANDLE_VALUE)
1438 CloseHandle(hFile);
1439 if (szResFileName == szTempFileName)
1440 // delete temporary file if we created one
1441 WszDeleteFile(szResFileName);
1442
1443 return hr;
1444} // HRESULT CeeFileGenWriter::emitResourceSection()
1445#endif // !FEATURE_PAL
1446
1447HRESULT CeeFileGenWriter::setManifestEntry(ULONG size, ULONG offset)
1448{
1449 if (offset)
1450 m_dwManifestRVA = offset;
1451 else {
1452 CeeSection TextSection = getTextSection();
1453 getMethodRVA(TextSection.dataLen() - size, &m_dwManifestRVA);
1454 }
1455
1456 m_dwManifestSize = size;
1457 return S_OK;
1458} // HRESULT CeeFileGenWriter::setManifestEntry()
1459
1460HRESULT CeeFileGenWriter::setStrongNameEntry(ULONG size, ULONG offset)
1461{
1462 m_dwStrongNameRVA = offset;
1463 m_dwStrongNameSize = size;
1464 return S_OK;
1465} // HRESULT CeeFileGenWriter::setStrongNameEntry()
1466
1467HRESULT CeeFileGenWriter::setVTableEntry64(ULONG size, void* ptr)
1468{
1469 if (ptr && size)
1470 {
1471 void * pv;
1472 CeeSection TextSection = getTextSection();
1473 // make it DWORD-aligned
1474 ULONG L = TextSection.dataLen();
1475 if((L &= ((ULONG)sizeof(DWORD)-1)))
1476 {
1477 L = (ULONG)sizeof(DWORD) - L;
1478 if((pv = TextSection.getBlock(L)))
1479 memset(pv,0,L);
1480 else
1481 return E_OUTOFMEMORY;
1482 }
1483 getMethodRVA(TextSection.dataLen(), &m_dwVTableRVA);
1484 if((pv = TextSection.getBlock(size)))
1485 {
1486 memcpy(pv,ptr,size);
1487 }
1488 else
1489 return E_OUTOFMEMORY;
1490 m_dwVTableSize = size;
1491 }
1492
1493 return S_OK;
1494} // HRESULT CeeFileGenWriter::setVTableEntry()
1495
1496HRESULT CeeFileGenWriter::setVTableEntry(ULONG size, ULONG offset)
1497{
1498 return setVTableEntry64(size,(void*)(ULONG_PTR)offset);
1499} // HRESULT CeeFileGenWriter::setVTableEntry()
1500
1501HRESULT CeeFileGenWriter::setEnCRvaBase(ULONG dataBase, ULONG rdataBase)
1502{
1503 setEnCMode();
1504 getPEWriter().setEnCRvaBase(dataBase, rdataBase);
1505 return S_OK;
1506} // HRESULT CeeFileGenWriter::setEnCRvaBase()
1507
1508HRESULT CeeFileGenWriter::computeSectionOffset(CeeSection &section, __in char *ptr,
1509 unsigned *offset)
1510{
1511 *offset = section.computeOffset(ptr);
1512
1513 return S_OK;
1514} // HRESULT CeeFileGenWriter::computeSectionOffset()
1515
1516HRESULT CeeFileGenWriter::computeOffset(__in char *ptr,
1517 CeeSection **pSection, unsigned *offset)
1518{
1519 TESTANDRETURNPOINTER(pSection);
1520
1521 CeeSection **s = m_sections;
1522 CeeSection **sEnd = s + m_numSections;
1523 while (s < sEnd)
1524 {
1525 if ((*s)->containsPointer(ptr))
1526 {
1527 *pSection = *s;
1528 *offset = (*s)->computeOffset(ptr);
1529
1530 return S_OK;
1531 }
1532 s++;
1533 }
1534
1535 return E_FAIL;
1536} // HRESULT CeeFileGenWriter::computeOffset()
1537
1538HRESULT CeeFileGenWriter::getCorHeader(IMAGE_COR20_HEADER **ppHeader)
1539{
1540 *ppHeader = m_corHeader;
1541 return S_OK;
1542} // HRESULT CeeFileGenWriter::getCorHeader()
1543
1544
1545#ifdef EMIT_FIXUPS
1546
1547HRESULT CeeFileGenWriter::InitFixupSection()
1548{
1549 if (!m_fEmitFixups)
1550 {
1551 return(E_UNEXPECTED);
1552 }
1553
1554 HRESULT hr;
1555
1556 hr = getSectionCreate(".fixups",
1557 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
1558 &m_sectionFixups);
1559 if (SUCCEEDED(hr))
1560 {
1561 size_t cbDebugDir = sizeof(IMAGE_DEBUG_DIRECTORY);
1562 hr = GetSectionBlock(m_sectionFixups, (ULONG) cbDebugDir, 32, (void **) &m_pDebugDir);
1563 if (SUCCEEDED(hr))
1564 {
1565 memset(m_pDebugDir, 0, cbDebugDir);
1566 m_pDebugDir->Type = IMAGE_DEBUG_TYPE_FIXUP;
1567 m_fFixupsUpdated = false;
1568
1569 return(S_OK);
1570 }
1571 }
1572
1573 m_pDebugDir = NULL;
1574 m_sectionFixups = NULL;
1575 m_fEmitFixups = false;
1576
1577 return(E_FAIL);
1578
1579} // HRESULT CeeFileGenWriter::InitFixupSection()
1580
1581HRESULT CeeFileGenWriter::addFixup(CeeSection& sectionSource, unsigned offset, CeeSectionRelocType relocType, CeeSection * psectionTarget, CeeSectionRelocExtra *extra)
1582{
1583 if (!m_fEmitFixups)
1584 {
1585 return(S_OK);
1586 }
1587
1588 _ASSERTE(sizeof(DBG_FIXUP) == sizeof(PEFIXUP));
1589 _ASSERTE(m_fFixupsUpdated == false);
1590
1591 DBG_FIXUP * pfixup;
1592
1593 if (m_sectionFixups == NULL)
1594 {
1595 HRESULT hr = InitFixupSection();
1596 if (FAILED(hr))
1597 {
1598 return(hr);
1599 }
1600
1601 // The fixup section begins with a IMAGE_DEBUG_DIRECTORY containing a
1602 // IMAGE_DEBUG_TYPE_FIXUP directory entry, which describes the array
1603 // of fixups which follows it.
1604
1605 // The very first item of this array is aligned on a 32 bit boundary.
1606 // All other fixup entries follow unaligned.
1607 pfixup = (DBG_FIXUP *) m_sectionFixups->getBlock(sizeof(DBG_FIXUP), 32);
1608 TESTANDRETURN(pfixup != NULL, E_OUTOFMEMORY);
1609
1610 // Initialize the IMAGE_DEBUG_TYPE_FIXUP entry relocations
1611#ifdef _WIN64
1612 _ASSERTE(!"Base relocs are not yet implemented for 64-bit");
1613 m_pDebugDir->AddressOfRawData = 0; // @ToDo: srRelocAbsolutePtr can't take a 64-bit address
1614#else
1615 m_pDebugDir->AddressOfRawData = (size_t) pfixup;
1616 m_sectionFixups->addSectReloc(offsetof(IMAGE_DEBUG_DIRECTORY, AddressOfRawData), *m_sectionFixups, srRelocAbsolutePtr);
1617#endif
1618
1619 m_pDebugDir->PointerToRawData = m_sectionFixups->computeOffset((char *) pfixup);
1620
1621 m_sectionFixups->addSectReloc(offsetof(IMAGE_DEBUG_DIRECTORY, PointerToRawData), *m_sectionFixups, srRelocFilePos);
1622
1623 unsigned offsetDir = m_sectionFixups->computeOffset((char *) m_pDebugDir);
1624 setDirectoryEntry(*m_sectionFixups, IMAGE_DIRECTORY_ENTRY_DEBUG, sizeof(IMAGE_DEBUG_DIRECTORY), offsetDir);
1625
1626#ifdef TEST_EMIT_FIXUPS
1627 TestEmitFixups();
1628#endif
1629 }
1630 else
1631 {
1632 pfixup = (DBG_FIXUP *) m_sectionFixups->getBlock(sizeof(DBG_FIXUP), 1);
1633 TESTANDRETURN(pfixup != NULL, E_OUTOFMEMORY);
1634 }
1635
1636 // Save off the relocation information for use later. The relocation's
1637 // target information can be filled in later.
1638 // The relocation target info is not always immediately available, so it needs
1639 // to be extracted later, during the link phase. For now the relocation info
1640 // is stored so the target can be extracted at link time in the UpdateFixups
1641 // function.
1642 //
1643 unsigned offsetFixup = m_sectionFixups->computeOffset((char *) pfixup);
1644 pfixup->wSpare = 0;
1645 pfixup->wType = relocType;
1646 _ASSERTE(pfixup->wType == relocType);
1647 pfixup->offset = offset;
1648 pfixup->sectionSource = &sectionSource;
1649
1650 m_pDebugDir->SizeOfData += sizeof(DBG_FIXUP);
1651
1652 // Add a relocation for the fixup's source RVA field, (no fixup on this reloc)
1653 m_sectionFixups->addSectReloc(offsetFixup + offsetof(DBG_FIXUP, rva), sectionSource, srRelocAbsolutePtr);
1654
1655 // Add a relocation for the fixup's target RVA field. Correct target extracted
1656 // later in UpdateFixups, (no fixup on this reloc)
1657 CeeSectionRelocType tgtRelocType;
1658
1659 switch (relocType)
1660 {
1661 case srRelocMapToken:
1662 // not an RVA
1663 tgtRelocType = srRelocMapToken;
1664 break;
1665
1666 case srRelocFilePos:
1667 tgtRelocType = srRelocFilePos;
1668 break;
1669
1670 case srRelocHighAdj:
1671 tgtRelocType = srRelocHighAdj;
1672 break;
1673
1674 default:
1675 tgtRelocType = (relocType & srRelocPtr) ? srRelocAbsolutePtr : srRelocAbsolute;
1676 break;
1677 }
1678
1679 if (psectionTarget != NULL)
1680 {
1681 m_sectionFixups->addSectReloc(offsetFixup + offsetof(DBG_FIXUP, rvaTarget), *psectionTarget, tgtRelocType, extra);
1682 }
1683 else
1684 {
1685 m_sectionFixups->addBaseReloc(offsetFixup + offsetof(DBG_FIXUP, rvaTarget), tgtRelocType, extra);
1686 }
1687
1688 return(S_OK);
1689} // HRESULT CeeFileGenWriter::addFixup()
1690
1691HRESULT CeeFileGenWriter::UpdateFixups()
1692{
1693 // This method extracts the correct relocation target. See addFixup method.
1694
1695 if (!m_fEmitFixups || m_fFixupsUpdated)
1696 {
1697 return(S_OK);
1698 }
1699 m_fFixupsUpdated = true; // prevent UpdateFixups from being called again.
1700
1701 size_t cfixups = m_pDebugDir->SizeOfData / sizeof(DBG_FIXUP);
1702 _ASSERT(m_pDebugDir->SizeOfData % sizeof(DBG_FIXUP) == 0);
1703 unsigned ibFixup = m_pDebugDir->PointerToRawData;
1704
1705 for (size_t idx = 0; idx < cfixups; idx++, ibFixup += sizeof(DBG_FIXUP))
1706 {
1707 DBG_FIXUP * pfixup = (DBG_FIXUP *) m_sectionFixups->computePointer(ibFixup);
1708 CeeSection * sectionSource = pfixup->sectionSource;
1709 CeeSectionRelocType relocType = (CeeSectionRelocType) pfixup->wType;
1710 unsigned offset = pfixup->offset;
1711
1712 // Get current data for replacing fixup contents
1713 const DWORD * pdw = (DWORD *) sectionSource->computePointer(offset);
1714 pfixup->rva = (DWORD) (UINT_PTR) pdw;
1715 pfixup->rvaTarget = *pdw;
1716
1717 switch (relocType)
1718 {
1719#ifdef _X86_
1720 case srRelocAbsolute:
1721 // Emitted bytes: RVA, offset relative to image base
1722 // reloc src contains target offset relative to target section
1723 if ((*pdw & 0xFF000000) == 0)
1724 {
1725 pfixup->wType = IMAGE_REL_I386_DIR32NB;
1726 }
1727 else
1728 {
1729 // MethodDesc::Fixup function creates a 24 bit RVA, where the
1730 // high byte of the DWORD stores the flag value: METHOD_NEEDS_PRESTUB_RUN_FLAG.
1731 // work around it by converting the type to 24 bits here
1732 pfixup->wType = IMAGE_REL_I386_DIR24NB;
1733 pfixup->rvaTarget = *pdw & 0x00FFFFFF;
1734 }
1735 break;
1736
1737 case srRelocAbsolutePtr:
1738 // Emitted bytes: RVA, offset relative to image base
1739 // reloc src contains target pointer
1740 pfixup->wType = IMAGE_REL_I386_DIR32NB;
1741 break;
1742
1743 case srRelocHighLow:
1744 // Emitted bytes: full address of target
1745 // reloc src contains target offset relative to target section
1746 pfixup->wType = IMAGE_REL_I386_DIR32;
1747 break;
1748
1749 case srRelocHighLowPtr:
1750 // Emitted bytes: full address of target
1751 // reloc src contains target pointer
1752 pfixup->wType = IMAGE_REL_I386_DIR32;
1753 break;
1754
1755 case srRelocRelative:
1756 // Emitted bytes: value of reloc tgt - (reloc source + sizeof(DWORD))
1757 // reloc src contains offset relative to target section, minus sizeof(DWORD)
1758 // the reloc type for pFixup->rvaTarget is srRelocAbsolute
1759 // so contents of pFixup->rvaTarget need to be offset Target + sizeof(DWORD)
1760 // which is offset Target == Source contents + sizeof(DWORD) == *pdw + sizeof(DWORD)
1761 pfixup->wType = IMAGE_REL_I386_REL32;
1762 pfixup->rvaTarget = *pdw + sizeof(DWORD);
1763 break;
1764
1765 case srRelocRelativePtr:
1766 // Emitted bytes: value of reloc tgt - (reloc source + sizeof(DWORD))
1767 // reloc src contains disp, disp = pTarget - (pSource + sizeof(DWORD))
1768 // the reloc type for pFixup->rvaTarget is srRelocAbsolutePtr
1769 // so contents of pFixup->rvaTarget need to be pTarget
1770 // which is pTarget == pSource + sizeof(DWORD) + disp == pdw + 4 + *pdw
1771 pfixup->wType = IMAGE_REL_I386_REL32;
1772 pfixup->rvaTarget = (int) (INT_PTR) pdw + sizeof(DWORD) + (int) *pdw;
1773 break;
1774
1775 case srRelocMapToken:
1776 // Emitted bytes: contents of reloc source unchanged.
1777 // reloc src contains token value
1778 pfixup->wType = IMAGE_REL_I386_TOKEN;
1779 break;
1780
1781#elif defined(_AMD64_)
1782 /*
1783 //
1784 // X86-64 relocations
1785 //
1786 IMAGE_REL_AMD64_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
1787 IMAGE_REL_AMD64_ADDR64 0x0001 // 64-bit address (VA).
1788 IMAGE_REL_AMD64_ADDR32 0x0002 // 32-bit address (VA).
1789 IMAGE_REL_AMD64_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
1790 IMAGE_REL_AMD64_REL32 0x0004 // 32-bit relative address from byte following reloc
1791 IMAGE_REL_AMD64_REL32_1 0x0005 // 32-bit relative address from byte distance 1 from reloc
1792 IMAGE_REL_AMD64_REL32_2 0x0006 // 32-bit relative address from byte distance 2 from reloc
1793 IMAGE_REL_AMD64_REL32_3 0x0007 // 32-bit relative address from byte distance 3 from reloc
1794 IMAGE_REL_AMD64_REL32_4 0x0008 // 32-bit relative address from byte distance 4 from reloc
1795 IMAGE_REL_AMD64_REL32_5 0x0009 // 32-bit relative address from byte distance 5 from reloc
1796 IMAGE_REL_AMD64_SECTION 0x000A // Section index
1797 IMAGE_REL_AMD64_SECREL 0x000B // 32 bit offset from base of section containing target
1798 IMAGE_REL_AMD64_SECREL7 0x000C // 7 bit unsigned offset from base of section containing target
1799 IMAGE_REL_AMD64_TOKEN 0x000D // 32 bit metadata token
1800 IMAGE_REL_AMD64_SREL32 0x000E // 32 bit signed span-dependent value emitted into object
1801 IMAGE_REL_AMD64_PAIR 0x000F
1802 IMAGE_REL_AMD64_SSPAN32 0x0010 // 32 bit signed span-dependent value applied at link time
1803 */
1804 case srRelocAbsolute:
1805 // Emitted bytes: RVA, offset relative to image base
1806 pfixup->wType = IMAGE_REL_AMD64_ADDR32NB;
1807 break;
1808
1809 case srRelocAbsolutePtr:
1810 // Emitted bytes: RVA, offset relative to image base
1811 // reloc src contains target pointer
1812 pfixup->wType = IMAGE_REL_AMD64_ADDR32NB;
1813 break;
1814
1815 case srRelocDir64Ptr:
1816 // Emitted bytes: full address of target
1817 // reloc src contains target pointer
1818 pfixup->wType = IMAGE_REL_IA64_DIR64;
1819 break;
1820
1821 case srRelocMapToken:
1822 // Emitted bytes: contents of reloc source unchanged.
1823 // reloc src contains token value
1824 pfixup->wType = IMAGE_REL_AMD64_TOKEN;
1825 break;
1826#endif
1827 case srRelocFilePos:
1828 // Emitted bytes: offset relative to start of file, differs from RVA.
1829 pfixup->wType = IMAGE_REL_I386_FILEPOS;
1830 break;
1831
1832 case srRelocAbsoluteTagged:
1833 pfixup->wType = IMAGE_REL_I386_DIR30NB;
1834 pfixup->rvaTarget = (*pdw & ~0x80000001) >> 1;
1835 break;
1836
1837 case srRelocHighAdj:
1838 // Emitted bytes: 2 part relocation, with high part adjusted by constant.
1839 pfixup->wType = IMAGE_REL_BASED_HIGHADJ;
1840 break;
1841
1842 default:
1843 _ASSERTE(!"Unknown relocation type");
1844 return(E_UNEXPECTED);
1845 break;
1846 }
1847 }
1848
1849 return(S_OK);
1850
1851} // HRESULT CeeFileGenWriter::UpdateFixups()
1852
1853
1854HRESULT CeeFileGenWriter::setEmitFixups()
1855{
1856 m_fEmitFixups = true;
1857 return(S_OK);
1858
1859} // HRESULT CeeFileGenWriter::setEmitFixups()
1860
1861#ifdef TEST_EMIT_FIXUPS
1862
1863HRESULT CeeFileGenWriter::TestEmitFixups()
1864{
1865 HRESULT hr;
1866 // Test fixups
1867
1868 CeeSection * testSection;
1869 hr = getSectionCreate(".test",
1870 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
1871 &testSection);
1872 if (SUCCEEDED(hr))
1873 {
1874 struct FixupEntry
1875 {
1876 char sz[18];
1877 DWORD wTargets[8];
1878 };
1879
1880 struct FixupTypes
1881 {
1882 char * pszType;
1883 CeeSectionRelocType relocType;
1884 };
1885
1886 FixupTypes rgTypes[] =
1887 {
1888 { "srRelocAbsolute ", srRelocAbsolute },
1889 { "srRelocAbsolutePtr", srRelocAbsolutePtr },
1890 { "srRelocHighLow ", srRelocHighLow },
1891 { "srRelocHighLowPtr ", srRelocHighLowPtr },
1892 // { "srRelocRelative ", srRelocRelative },
1893 // { "srRelocRelativePtr", srRelocRelativePtr },
1894 { "srRelocMapToken ", srRelocMapToken },
1895 // { "srRelocFilePos ", srRelocFilePos },
1896 // { "srRelocHighAdj ", srRelocHighAdj },
1897 };
1898
1899 const size_t cFixups = sizeof(rgTypes) / sizeof(rgTypes[0]);
1900
1901 DWORD * pdwTargets[20];
1902
1903 // Target Blocks:
1904
1905 for (size_t idx = 0; idx < cFixups; idx++)
1906 {
1907 hr = GetSectionBlock(testSection, sizeof(DWORD), 1, (void **) &pdwTargets[idx]);
1908 _ASSERTE(SUCCEEDED(hr));
1909
1910 DWORD * pdw = pdwTargets[idx];
1911 *pdw = idx;
1912 }
1913
1914 for (size_t idxType = 0; idxType < cFixups; idxType++)
1915 {
1916 // Fixup Entries
1917 FixupEntry * pEntry;
1918 hr = GetSectionBlock(testSection, sizeof(FixupEntry), 1, (void **) &pEntry);
1919 _ASSERTE(SUCCEEDED(hr));
1920
1921 memset(pEntry, 0, sizeof(FixupEntry));
1922 strcpy_s(pEntry->sz, sizeof(pEntry->sz), rgTypes[idxType].pszType);
1923
1924 size_t ibBlock = testSection->computeOffset((char *) pEntry);
1925
1926 for (size_t idx = 0; idx < cFixups; idx++)
1927 {
1928 size_t ibFixup = ((size_t) &pEntry->wTargets[idx]) - (size_t) pEntry;
1929
1930 switch (rgTypes[idxType].relocType)
1931 {
1932 case srRelocAbsolute:
1933 pEntry->wTargets[idx] = idx * sizeof(DWORD);
1934 break;
1935
1936 case srRelocAbsolutePtr:
1937 pEntry->wTargets[idx] = (DWORD) pdwTargets[idx];
1938 break;
1939
1940 case srRelocHighLow:
1941 pEntry->wTargets[idx] = idx * sizeof(DWORD);
1942 break;
1943
1944 case srRelocHighLowPtr:
1945 pEntry->wTargets[idx] = (DWORD) pdwTargets[idx];
1946 break;
1947
1948 case srRelocRelative:
1949 pEntry->wTargets[idx] = idx;
1950 break;
1951
1952 case srRelocRelativePtr:
1953 {
1954 size_t ibTgt = (size_t) pdwTargets[idx];
1955 size_t ibSrc = ((size_t) &pEntry->wTargets[idx]) + sizeof(DWORD);
1956 pEntry->wTargets[idx] = (DWORD)( ibTgt - ibSrc );
1957 ibFixup += sizeof(DWORD); // offset needs to point at end of DWORD
1958 break;
1959 }
1960
1961 case srRelocHighAdj:
1962 pEntry->wTargets[idx] = idx * sizeof(DWORD);
1963 break;
1964
1965 case srRelocMapToken:
1966 pEntry->wTargets[idx] = idx * sizeof(DWORD);
1967 break;
1968
1969 case srRelocFilePos:
1970 pEntry->wTargets[idx] = idx * sizeof(DWORD);
1971 break;
1972 }
1973
1974 addFixup(*testSection, ibBlock + ibFixup, rgTypes[idxType].relocType, testSection);
1975 testSection->addSectReloc(ibBlock + ibFixup, *testSection, rgTypes[idxType].relocType);
1976 }
1977 }
1978 }
1979
1980 return(S_OK);
1981}
1982#endif // TEST_EMIT_FIXUPS
1983#endif // EMIT_FIXUPS
1984
1985#ifndef FEATURE_MERGE_JIT_AND_ENGINE
1986
1987//*****************************************************************************
1988// Handle lifetime of loaded library.
1989//*****************************************************************************
1990extern "C"
1991BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
1992{
1993 switch (dwReason)
1994 {
1995 case DLL_PROCESS_ATTACH:
1996 { // Save the module handle.
1997 g_hThisInst = (HINSTANCE)hInstance;
1998 DisableThreadLibraryCalls((HMODULE)hInstance);
1999 }
2000 break;
2001 case DLL_PROCESS_DETACH:
2002 break;
2003 }
2004
2005 return (true);
2006} // BOOL WINAPI DllMain()
2007
2008
2009HINSTANCE GetModuleInst()
2010{
2011 return (g_hThisInst);
2012} // HINSTANCE GetModuleInst()
2013
2014#endif //FEATURE_MERGE_JIT_AND_ENGINE
2015