summaryrefslogtreecommitdiff
path: root/src/dlls/mscorpe
diff options
context:
space:
mode:
Diffstat (limited to 'src/dlls/mscorpe')
-rw-r--r--src/dlls/mscorpe/.gitmirrorall1
-rw-r--r--src/dlls/mscorpe/CMakeLists.txt23
-rw-r--r--src/dlls/mscorpe/Native.rc8
-rw-r--r--src/dlls/mscorpe/ceefilegenwriter.cpp2007
-rw-r--r--src/dlls/mscorpe/ceefilegenwritertokens.cpp266
-rw-r--r--src/dlls/mscorpe/dirs.proj15
-rw-r--r--src/dlls/mscorpe/iceefilegen.cpp732
-rw-r--r--src/dlls/mscorpe/mscorpe/mscorpe.def11
-rw-r--r--src/dlls/mscorpe/mscorpe/mscorpe.nativeproj46
-rw-r--r--src/dlls/mscorpe/mscorpe/wrapper.cpp149
-rw-r--r--src/dlls/mscorpe/mscorpehost/mscorpehost.def12
-rw-r--r--src/dlls/mscorpe/mscorpehost/mscorpehost.nativeproj68
-rw-r--r--src/dlls/mscorpe/pewriter.cpp2401
-rw-r--r--src/dlls/mscorpe/pewriter.h337
-rw-r--r--src/dlls/mscorpe/stdafx.cpp10
-rw-r--r--src/dlls/mscorpe/stdafx.h24
-rw-r--r--src/dlls/mscorpe/stubs.h169
-rw-r--r--src/dlls/mscorpe/utilcodeinit.cpp11
18 files changed, 6290 insertions, 0 deletions
diff --git a/src/dlls/mscorpe/.gitmirrorall b/src/dlls/mscorpe/.gitmirrorall
new file mode 100644
index 0000000000..9ee5c57b99
--- /dev/null
+++ b/src/dlls/mscorpe/.gitmirrorall
@@ -0,0 +1 @@
+This folder will be mirrored by the Git-TFS Mirror recursively. \ No newline at end of file
diff --git a/src/dlls/mscorpe/CMakeLists.txt b/src/dlls/mscorpe/CMakeLists.txt
new file mode 100644
index 0000000000..e8f22f2e9b
--- /dev/null
+++ b/src/dlls/mscorpe/CMakeLists.txt
@@ -0,0 +1,23 @@
+project(mscorpe)
+
+add_definitions(-DFEATURE_CORECLR)
+
+set(MSCORPE_SOURCES
+ iceefilegen.cpp
+ ceefilegenwriter.cpp
+ pewriter.cpp
+ ceefilegenwritertokens.cpp
+ utilcodeinit.cpp
+)
+
+if(WIN32)
+ list(APPEND MSCORPE_SOURCES
+ Native.rc
+ )
+else()
+ add_compile_options(-Wno-delete-non-virtual-dtor)
+endif(WIN32)
+
+add_library_clr(mscorpe STATIC
+ ${MSCORPE_SOURCES}
+)
diff --git a/src/dlls/mscorpe/Native.rc b/src/dlls/mscorpe/Native.rc
new file mode 100644
index 0000000000..e652bf3f1d
--- /dev/null
+++ b/src/dlls/mscorpe/Native.rc
@@ -0,0 +1,8 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Runtime PE File Generator\0"
+
+#include <fxver.h>
+#include <fxver.rc>
diff --git a/src/dlls/mscorpe/ceefilegenwriter.cpp b/src/dlls/mscorpe/ceefilegenwriter.cpp
new file mode 100644
index 0000000000..cfd1ebb644
--- /dev/null
+++ b/src/dlls/mscorpe/ceefilegenwriter.cpp
@@ -0,0 +1,2007 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// Derived class from CCeeGen which handles writing out
+// the exe. All references to PEWriter pulled out of CCeeGen,
+// and moved here
+//
+//
+
+#include "stdafx.h"
+
+#include <string.h>
+#include <limits.h>
+
+#include "corerror.h"
+#include "stubs.h"
+#include <posterror.h>
+#include <shlwapi.h>
+
+// Globals.
+HINSTANCE g_hThisInst; // This library.
+
+
+#ifdef EMIT_FIXUPS
+
+// Emitted PEFIXUP structure looks like this
+struct PEFIXUP
+{
+ WORD wType;
+ WORD wSpare;
+ DWORD rva;
+ DWORD rvaTarget;
+};
+
+// Following structure is used to store the reloc information which
+// will be used at UpdateFixups time to get the final data from the section
+// bytes to update the fixup information.
+//
+struct DBG_FIXUP
+{
+ WORD wType;
+ WORD wSpare;
+
+ union
+ {
+ DWORD rva;
+ unsigned offset;
+ };
+
+ union
+ {
+ DWORD rvaTarget;
+ CeeSection * sectionSource;
+ };
+};
+
+enum
+{
+ IMAGE_REL_I386_DIR24NB = 0x0081, // 24-bit base relative
+ IMAGE_REL_I386_FILEPOS = 0x0082, // 32-bit file relative
+ // all other relocation types are
+ // in winnt.h, for some reason
+ // this one is missing
+ IMAGE_REL_I386_DIR30NB = 0x0083, // 30-bit base relative
+};
+
+#endif // EMIT_FIXUPS
+
+// Get the Symbol entry given the head and a 0-based index
+inline IMAGE_SYMBOL* GetSymbolEntry(IMAGE_SYMBOL* pHead, SIZE_T idx)
+{
+ return (IMAGE_SYMBOL*) (((BYTE*) pHead) + IMAGE_SIZEOF_SYMBOL * idx);
+}
+
+#ifdef EnC_SUPPORTED
+#define ENC_DELTA_HACK
+#endif
+
+#ifdef ENC_DELTA_HACK
+ BOOL g_EnCMode = FALSE;
+#endif
+
+//*****************************************************************************
+// To get a new instance, call CreateNewInstance() or CreateNewInstanceEx() instead of new
+//*****************************************************************************
+
+HRESULT CeeFileGenWriter::CreateNewInstance(CCeeGen *pCeeFileGenFrom,
+ CeeFileGenWriter* & pGenWriter,
+ DWORD createFlags)
+{
+ return CreateNewInstanceEx(pCeeFileGenFrom, pGenWriter, createFlags);
+}
+
+//
+// Seed file is used as the base file. The new file data will be "appended" to the seed file
+//
+
+HRESULT CeeFileGenWriter::CreateNewInstanceEx(CCeeGen *pCeeFileGenFrom,
+ CeeFileGenWriter* & pGenWriter,
+ DWORD createFlags,
+ LPCWSTR seedFileName)
+{
+ HRESULT hr = S_OK;
+ ULONG preallocatedOffset = 0;
+ NewHolder<PEWriter> pPEWriter(NULL);
+ NewHolder<CeeFileGenWriter> pPrivateGenWriter;
+ CeeSection *corHeaderSection = NULL;
+
+ pPrivateGenWriter = new (nothrow) CeeFileGenWriter;
+ if (pPrivateGenWriter == NULL)
+ IfFailGo(E_OUTOFMEMORY);
+
+ pPEWriter = new (nothrow) PEWriter;
+ if (pPEWriter == NULL)
+ IfFailGo(E_OUTOFMEMORY);
+
+ //workaround
+ //What's really the correct thing to be doing here?
+ //HRESULT hr = pPEWriter->Init(pCeeFileGenFrom ? pCeeFileGenFrom->getPESectionMan() : NULL);
+ hr = pPEWriter->Init(NULL, createFlags, seedFileName);
+ IfFailGo(hr);
+
+ //Create the general PEWriter.
+ pPrivateGenWriter->m_peSectionMan = pPEWriter;
+ hr = pPrivateGenWriter->Init(); // base class member to finish init
+ IfFailGo(hr);
+
+ if (!seedFileName) // Use base file's preferred base (if present)
+ {
+ if (pPEWriter->isPE32())
+ {
+ pPrivateGenWriter->setImageBase((DWORD) CEE_IMAGE_BASE_32); // use same default as linker
+ }
+ else
+ {
+ pPrivateGenWriter->setImageBase64((ULONGLONG) CEE_IMAGE_BASE_64); // use same default as linker
+ }
+ }
+
+ pPrivateGenWriter->setSubsystem(IMAGE_SUBSYSTEM_WINDOWS_CUI, CEE_IMAGE_SUBSYSTEM_MAJOR_VERSION, CEE_IMAGE_SUBSYSTEM_MINOR_VERSION);
+
+ if (pPEWriter->createCorMainStub())
+ {
+ hr = pPrivateGenWriter->allocateIAT(); // so the IAT goes out first
+ IfFailGo(hr);
+ }
+
+ hr = pPrivateGenWriter->allocateCorHeader(); // get COR header near front
+ IfFailGo(hr);
+
+#if 0 // Need to add this if we want to propagate the old COM+ header
+ if (seedFileName)
+ {
+ memcpy(m_corHeader, baseFileDecoder->ntHeaders32()->corHeader, sizeof(IMAGE_COR20_HEADER));
+ }
+#endif
+
+ //If we were passed a CCeeGen at the beginning, copy it's data now.
+ if (pCeeFileGenFrom) {
+ pCeeFileGenFrom->cloneInstance((CCeeGen*)pPrivateGenWriter);
+ }
+
+ hr = pPrivateGenWriter->getSectionCreate(".text0", sdExecute, &corHeaderSection);
+ IfFailGo(hr);
+ preallocatedOffset = corHeaderSection->dataLen();
+
+
+ // set il RVA to be after the preallocated sections
+ pPEWriter->setIlRva(preallocatedOffset);
+
+#ifdef EMIT_FIXUPS
+ if (createFlags & ICEE_CREATE_FILE_EMIT_FIXUPS)
+ {
+ pPrivateGenWriter->setEmitFixups();
+ }
+#endif
+
+ pPEWriter.SuppressRelease();
+ pPrivateGenWriter.SuppressRelease();
+ pGenWriter = pPrivateGenWriter;
+
+ErrExit:
+ return hr;
+} // HRESULT CeeFileGenWriter::CreateNewInstance()
+
+CeeFileGenWriter::CeeFileGenWriter() // ctor is protected
+{
+ m_outputFileName = NULL;
+ m_resourceFileName = NULL;
+ m_dllSwitch = false;
+ m_objSwitch = false;
+ m_libraryName = NULL;
+ m_libraryGuid = GUID_NULL;
+
+ m_entryPoint = 0;
+ m_comImageFlags = COMIMAGE_FLAGS_ILONLY; // ceegen PEs don't have native code
+ m_iatOffset = 0;
+ m_dllCount = 0;
+
+ m_dwMacroDefinitionSize = 0;
+ m_dwMacroDefinitionRVA = NULL;
+
+ m_dwManifestSize = 0;
+ m_dwManifestRVA = NULL;
+
+ m_dwStrongNameSize = 0;
+ m_dwStrongNameRVA = NULL;
+
+ m_dwVTableSize = 0;
+ m_dwVTableRVA = NULL;
+
+ m_iDataDlls = NULL;
+
+ m_linked = false;
+ m_fixed = false;
+
+#ifdef EMIT_FIXUPS
+
+ m_fEmitFixups = false;
+ m_fFixupsUpdated = false;
+ m_sectionFixups = NULL;
+ m_pDebugDir = NULL;
+
+#endif
+
+#ifdef ENC_DELTA_HACK
+ // for EnC we want the RVA to be right at the front of the IL stream
+ PathString szFileName;
+ DWORD len = WszGetEnvironmentVariable(W("COMP_ENC_EMIT"), szFileName);
+ if (len > 0)
+ g_EnCMode = TRUE;
+#endif
+
+} // CeeFileGenWriter::CeeFileGenWriter()
+
+//*****************************************************************************
+// Cleanup
+//*****************************************************************************
+HRESULT CeeFileGenWriter::Cleanup() // virtual
+{
+ ((PEWriter *)m_peSectionMan)->Cleanup(); // call derived cleanup
+ delete m_peSectionMan;
+ m_peSectionMan = NULL; // so base class won't delete
+
+ delete[] m_outputFileName;
+ delete[] m_resourceFileName;
+
+ if (m_iDataDlls) {
+ for (int i=0; i < m_dllCount; i++) {
+ if (m_iDataDlls[i].m_methodName)
+ delete[] m_iDataDlls[i].m_methodName;
+ }
+ delete[] m_iDataDlls;
+ }
+
+ return CCeeGen::Cleanup();
+} // HRESULT CeeFileGenWriter::Cleanup()
+
+HRESULT CeeFileGenWriter::EmitMacroDefinitions(void *pData, DWORD cData)
+{
+ // OBSOLETE
+ m_dwMacroDefinitionSize = 0;
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::EmitMacroDefinitions()
+
+HRESULT CeeFileGenWriter::link()
+{
+ HRESULT hr = checkForErrors();
+ if (! SUCCEEDED(hr))
+ return hr;
+
+#ifdef EMIT_FIXUPS
+
+ // The fixups describe each relocation. Each fixup contains the relocation's
+ // type, source RVA, and target RVA. Since the reloc target can be filled
+ // in after the relocation creation, the fixup target RVA discovery needs to
+ // be deferred.
+ // At this point all bytes should be filled in, ensuring that the final
+ // target information is available.
+ // UpdateFixups is called at this point to discover the final relocation target info.
+ //
+ hr = UpdateFixups();
+ if (! SUCCEEDED(hr))
+ return hr;
+
+#endif
+
+ // Don't set this if SetManifestEntry was not called - zapper sets the
+ // resource directory explicitly
+ if (m_dwManifestSize != 0)
+ {
+ m_corHeader->Resources.VirtualAddress = VAL32(m_dwManifestRVA);
+ m_corHeader->Resources.Size = VAL32(m_dwManifestSize);
+ }
+
+ if (m_dwStrongNameSize != 0)
+ {
+ m_corHeader->StrongNameSignature.VirtualAddress = VAL32(m_dwStrongNameRVA);
+ m_corHeader->StrongNameSignature.Size = VAL32(m_dwStrongNameSize);
+ }
+
+ if (m_dwVTableSize != 0)
+ {
+ m_corHeader->VTableFixups.VirtualAddress = VAL32(m_dwVTableRVA);
+ m_corHeader->VTableFixups.Size = VAL32(m_dwVTableSize);
+ }
+
+ unsigned characteristicsMask = IMAGE_FILE_EXECUTABLE_IMAGE;
+
+ if (getPEWriter().isPE32())
+ characteristicsMask |= IMAGE_FILE_32BIT_MACHINE;
+ if (!getPEWriter().isPE32())
+ characteristicsMask |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+
+ getPEWriter().setCharacteristics(characteristicsMask);
+
+ m_corHeader->cb = VAL32(sizeof(IMAGE_COR20_HEADER));
+ m_corHeader->MajorRuntimeVersion = VAL16(COR_VERSION_MAJOR);
+ m_corHeader->MinorRuntimeVersion = VAL16(COR_VERSION_MINOR);
+ if (m_dllSwitch)
+ getPEWriter().setCharacteristics(IMAGE_FILE_DLL);
+ if (m_objSwitch)
+ getPEWriter().clearCharacteristics(IMAGE_FILE_DLL | IMAGE_FILE_EXECUTABLE_IMAGE);
+ m_corHeader->Flags = VAL32(m_comImageFlags);
+ IMAGE_COR20_HEADER_FIELD(*m_corHeader, EntryPointToken) = VAL32(m_entryPoint);
+ _ASSERTE(TypeFromToken(m_entryPoint) == mdtMethodDef || m_entryPoint == mdTokenNil ||
+ TypeFromToken(m_entryPoint) == mdtFile);
+ setDirectoryEntry(getCorHeaderSection(), IMAGE_DIRECTORY_ENTRY_COMHEADER, sizeof(IMAGE_COR20_HEADER), m_corHeaderOffset);
+
+ if ((m_comImageFlags & COMIMAGE_FLAGS_IL_LIBRARY) == 0
+ && !m_linked && !m_objSwitch)
+ {
+ hr = emitExeMain();
+ if (FAILED(hr))
+ return hr;
+#ifndef FEATURE_PAL
+ hr = emitResourceSection();
+ if (FAILED(hr))
+ return hr;
+#endif
+ }
+
+ m_linked = true;
+
+ IfFailRet(getPEWriter().link());
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::link()
+
+
+HRESULT CeeFileGenWriter::fixup()
+{
+ HRESULT hr;
+
+ m_fixed = true;
+
+ if (!m_linked)
+ IfFailRet(link());
+
+ CeeGenTokenMapper *pMapper = getTokenMapper();
+
+ // Apply token remaps if there are any.
+ if (! m_fTokenMapSupported && pMapper != NULL) {
+ IMetaDataImport *pImport;
+ hr = pMapper->GetMetaData(&pImport);
+ _ASSERTE(SUCCEEDED(hr));
+ hr = MapTokens(pMapper, pImport);
+ pImport->Release();
+
+ }
+
+ // remap the entry point if entry point token has been moved
+ if (pMapper != NULL && !m_objSwitch)
+ {
+ mdToken tk = m_entryPoint;
+ pMapper->HasTokenMoved(tk, tk);
+ IMAGE_COR20_HEADER_FIELD(*m_corHeader, EntryPointToken) = VAL32(tk);
+ }
+
+ IfFailRet(getPEWriter().fixup(pMapper));
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::fixup()
+
+HRESULT CeeFileGenWriter::generateImage(void **ppImage)
+{
+ HRESULT hr = S_OK;
+ LPCWSTR outputFileName = NULL;
+
+#ifndef FEATURE_PAL
+ HANDLE hThreadToken = NULL;
+ // Impersonation is only supported on Win2k and above.
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE, TRUE, &hThreadToken))
+ {
+ if (GetLastError() != ERROR_NO_TOKEN)
+ {
+ _ASSERTE(!"Failed to get thread token!");
+ return HRESULT_FROM_GetLastError();
+ }
+ }
+
+ if (hThreadToken != NULL)
+ {
+ if (!RevertToSelf())
+ {
+ _ASSERTE(!"Failed to revert impersonation!");
+ CloseHandle(hThreadToken);
+ return HRESULT_FROM_GetLastError();
+ }
+ }
+#endif // !FEATURE_PAL
+
+#ifdef ENC_DELTA_HACK
+ // fixups break because we've set the base RVA to 0 for the delta stream
+ if (! g_EnCMode)
+#endif
+ if (!m_fixed)
+ IfFailGo(fixup());
+
+ outputFileName = m_outputFileName;
+
+ if (! outputFileName && ppImage == NULL) {
+ if (m_comImageFlags & COMIMAGE_FLAGS_IL_LIBRARY)
+ outputFileName = W("output.ill");
+ else if (m_dllSwitch)
+ outputFileName = W("output.dll");
+ else if (m_objSwitch)
+ outputFileName = W("output.exe");
+ else
+ outputFileName = W("output.obj");
+ }
+
+ // output file name and ppImage are mutually exclusive
+ _ASSERTE((NULL == outputFileName && ppImage != NULL) || (outputFileName != NULL && NULL == ppImage));
+
+ if (outputFileName != NULL)
+ IfFailGo(getPEWriter().write(outputFileName));
+ else
+ IfFailGo(getPEWriter().write(ppImage));
+
+ErrExit:
+#ifndef FEATURE_PAL
+ if (hThreadToken != NULL)
+ {
+ BOOL success = SetThreadToken(NULL, hThreadToken);
+ CloseHandle(hThreadToken);
+
+ if (!success)
+ {
+ _ASSERTE(!"Failed to reimpersonate!");
+ hr = HRESULT_FROM_GetLastError();
+ }
+ }
+#endif // !FEATURE_PAL
+ return hr;
+} // HRESULT CeeFileGenWriter::generateImage()
+
+HRESULT CeeFileGenWriter::setOutputFileName(__in LPWSTR fileName)
+{
+ if (m_outputFileName)
+ delete[] m_outputFileName;
+ int len = lstrlenW(fileName) + 1;
+ m_outputFileName = (LPWSTR)new (nothrow) WCHAR[len];
+ TESTANDRETURN(m_outputFileName!=NULL, E_OUTOFMEMORY);
+ wcscpy_s(m_outputFileName, len, fileName);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setOutputFileName()
+
+HRESULT CeeFileGenWriter::setResourceFileName(__in LPWSTR fileName)
+{
+ if (m_resourceFileName)
+ delete[] m_resourceFileName;
+ int len = lstrlenW(fileName) + 1;
+ m_resourceFileName = (LPWSTR)new (nothrow) WCHAR[len];
+ TESTANDRETURN(m_resourceFileName!=NULL, E_OUTOFMEMORY);
+ wcscpy_s(m_resourceFileName, len, fileName);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setResourceFileName()
+
+HRESULT CeeFileGenWriter::setLibraryName(__in LPWSTR libraryName)
+{
+ if (m_libraryName)
+ delete[] m_libraryName;
+ int len = lstrlenW(libraryName) + 1;
+ m_libraryName = (LPWSTR)new (nothrow) WCHAR[len];
+ TESTANDRETURN(m_libraryName != NULL, E_OUTOFMEMORY);
+ wcscpy_s(m_libraryName, len, libraryName);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setLibraryName()
+
+HRESULT CeeFileGenWriter::setLibraryGuid(__in LPWSTR libraryGuid)
+{
+ return IIDFromString(libraryGuid, &m_libraryGuid);
+} // HRESULT CeeFileGenWriter::setLibraryGuid()
+
+HRESULT CeeFileGenWriter::emitLibraryName(IMetaDataEmit *emitter)
+{
+ HRESULT hr;
+ IfFailRet(emitter->SetModuleProps(m_libraryName));
+
+ // Set the GUID as a custom attribute, if it is not NULL_GUID.
+ if (m_libraryGuid != GUID_NULL)
+ {
+ static COR_SIGNATURE _SIG[] = INTEROP_GUID_SIG;
+ mdTypeRef tr;
+ mdMemberRef mr;
+ WCHAR wzGuid[40];
+ BYTE rgCA[50];
+ IfFailRet(emitter->DefineTypeRefByName(mdTypeRefNil, INTEROP_GUID_TYPE_W, &tr));
+ IfFailRet(emitter->DefineMemberRef(tr, W(".ctor"), _SIG, sizeof(_SIG), &mr));
+ StringFromGUID2(m_libraryGuid, wzGuid, lengthof(wzGuid));
+ memset(rgCA, 0, sizeof(rgCA));
+ // Tag is 0x0001
+ rgCA[0] = 1;
+ // Length of GUID string is 36 characters.
+ rgCA[2] = 0x24;
+ // Convert 36 characters, skipping opening {, into 3rd byte of buffer.
+ WszWideCharToMultiByte(CP_ACP,0, wzGuid+1,36, reinterpret_cast<char*>(&rgCA[3]),36, 0,0);
+ hr = emitter->DefineCustomAttribute(1,mr,rgCA,41,0);
+ }
+ return (hr);
+} // HRESULT CeeFileGenWriter::emitLibraryName()
+
+HRESULT CeeFileGenWriter::setImageBase(size_t imageBase)
+{
+ _ASSERTE(getPEWriter().isPE32());
+ getPEWriter().setImageBase32((DWORD)imageBase);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setImageBase()
+
+HRESULT CeeFileGenWriter::setImageBase64(ULONGLONG imageBase)
+{
+ _ASSERTE(!getPEWriter().isPE32());
+ getPEWriter().setImageBase64(imageBase);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setImageBase64()
+
+HRESULT CeeFileGenWriter::setFileAlignment(ULONG fileAlignment)
+{
+ getPEWriter().setFileAlignment(fileAlignment);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setFileAlignment()
+
+HRESULT CeeFileGenWriter::setSubsystem(DWORD subsystem, DWORD major, DWORD minor)
+{
+ getPEWriter().setSubsystem(subsystem, major, minor);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setSubsystem()
+
+HRESULT CeeFileGenWriter::checkForErrors()
+{
+ if (TypeFromToken(m_entryPoint) == mdtMethodDef) {
+ if (m_dllSwitch) {
+ //current spec would need to check the binary sig of the entry point method
+ }
+ return S_OK;
+ }
+ return S_OK;
+} // HRESULT CeeFileGenWriter::checkForErrors()
+
+HRESULT CeeFileGenWriter::getMethodRVA(ULONG codeOffset, ULONG *codeRVA)
+{
+ _ASSERTE(codeRVA);
+#ifdef ENC_DELTA_HACK
+ // for EnC we want the RVA to be right be relative to the front of the delta IL stream rather
+ // than take into account the .text section and the cor header as we would for a real PE file
+ if (g_EnCMode)
+ *codeRVA = codeOffset;
+ else
+#endif
+ *codeRVA = getPEWriter().getIlRva() + codeOffset;
+ return S_OK;
+} // HRESULT CeeFileGenWriter::getMethodRVA()
+
+HRESULT CeeFileGenWriter::setDirectoryEntry(CeeSection &section, ULONG entry, ULONG size, ULONG offset)
+{
+ return getPEWriter().setDirectoryEntry((PEWriterSection*)(&section.getImpl()), entry, size, offset);
+} // HRESULT CeeFileGenWriter::setDirectoryEntry()
+
+HRESULT CeeFileGenWriter::getFileTimeStamp(DWORD *pTimeStamp)
+{
+ return getPEWriter().getFileTimeStamp(pTimeStamp);
+} // HRESULT CeeFileGenWriter::getFileTimeStamp()
+
+HRESULT CeeFileGenWriter::setAddrReloc(UCHAR *instrAddr, DWORD value)
+{
+ *(DWORD *)instrAddr = VAL32(value);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setAddrReloc()
+
+HRESULT CeeFileGenWriter::addAddrReloc(CeeSection &thisSection, UCHAR *instrAddr, DWORD offset, CeeSection *targetSection)
+{
+ if (!targetSection) {
+ thisSection.addBaseReloc(offset, srRelocHighLow);
+ } else {
+ thisSection.addSectReloc(offset, *targetSection, srRelocHighLow);
+ }
+ return S_OK;
+} // HRESULT CeeFileGenWriter::addAddrReloc()
+
+// create CorExeMain and import directory into .text and the .iat into .data
+//
+// The structure of the import directory information is as follows, but it is not contiguous in
+// section. All the r/o data goes into the .text section and the iat array (which the loader
+// updates with the imported addresses) goes into the .data section because WINCE needs it to be writable.
+//
+// struct IData {
+// // one for each DLL, terminating in NULL
+// IMAGE_IMPORT_DESCRIPTOR iid[];
+// // import lookup table: a set of entries for the methods of each DLL,
+// // terminating each set with NULL
+// IMAGE_THUNK_DATA32/64 ilt[];
+// // hint/name table: an set of entries for each method of each DLL wiht
+// // no terminating entry
+// struct {
+// WORD Hint;
+// // null terminated string
+// BYTE Name[];
+// } ibn; // Hint/name table
+// // import address table: a set of entries for the methods of each DLL,
+// // terminating each set with NULL
+// IMAGE_THUNK_DATA32/64 iat[];
+// // one for each DLL, null terminated strings
+// BYTE DllName[];
+// };
+//
+
+// IAT must be first in its section, so have code here to allocate it up front
+// prior to knowing other info such as if dll or not. This won't work if have > 1
+// function imported, but we'll burn that bridge when we get to it.
+HRESULT CeeFileGenWriter::allocateIAT()
+{
+ m_dllCount = 1;
+ m_iDataDlls = new (nothrow) IDataDllInfo[m_dllCount];
+ if (m_iDataDlls == NULL) {
+ return E_OUTOFMEMORY;
+ }
+ memset(m_iDataDlls, '\0', m_dllCount * sizeof(IDataDllInfo));
+ m_iDataDlls[0].m_name = "mscoree.dll";
+ m_iDataDlls[0].m_numMethods = 1;
+ m_iDataDlls[0].m_methodName = new (nothrow) const char*[m_iDataDlls[0].m_numMethods];
+ if (! m_iDataDlls[0].m_methodName) {
+ return E_OUTOFMEMORY;
+ }
+ m_iDataDlls[0].m_methodName[0] = NULL;
+
+ int iDataSizeIAT = 0;
+
+ for (int i=0; i < m_dllCount; i++) {
+ m_iDataDlls[i].m_iatOffset = iDataSizeIAT;
+ iDataSizeIAT += (m_iDataDlls[i].m_numMethods + 1)
+ * (getPEWriter().isPE32() ? sizeof(IMAGE_THUNK_DATA32)
+ : sizeof(IMAGE_THUNK_DATA64));
+ }
+
+ HRESULT hr = getSectionCreate(".text0", sdExecute, &m_iDataSectionIAT);
+ TESTANDRETURNHR(hr);
+ m_iDataOffsetIAT = m_iDataSectionIAT->dataLen();
+ _ASSERTE(m_iDataOffsetIAT == 0);
+ m_iDataIAT = m_iDataSectionIAT->getBlock(iDataSizeIAT);
+ if (! m_iDataIAT) {
+ return E_OUTOFMEMORY;
+ }
+ memset(m_iDataIAT, '\0', iDataSizeIAT);
+
+ // Don't set the IAT directory entry yet, since we may not actually end up doing
+ // an emitExeMain.
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::allocateIAT()
+
+HRESULT CeeFileGenWriter::emitExeMain()
+{
+ if (m_dllCount == 0)
+ return S_OK;
+
+ // Note: code later on in this method assumes that mscoree.dll is at
+ // index m_iDataDlls[0], with CorDllMain or CorExeMain at method[0]
+
+ _ASSERTE(getPEWriter().createCorMainStub());
+
+ if (m_dllSwitch) {
+ m_iDataDlls[0].m_methodName[0] = "_CorDllMain";
+ } else {
+ m_iDataDlls[0].m_methodName[0] = "_CorExeMain";
+ }
+
+ // IMAGE_IMPORT_DESCRIPTOR on PE/PE+ must be 4-byte or 8-byte aligned
+ int align = (getPEWriter().isPE32()) ? 4 : 8;
+ int curOffset = getTextSection().dataLen();
+
+ int diff = ((curOffset + align -1) & ~(align-1)) - curOffset;
+ if (diff)
+ {
+ char* pDiff = getTextSection().getBlock(diff);
+ if (NULL==pDiff) return E_OUTOFMEMORY;
+ memset(pDiff,0,diff);
+ }
+
+ int iDataSizeRO = (m_dllCount + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
+ CeeSection &iDataSectionRO = getTextSection();
+ int iDataOffsetRO = iDataSectionRO.dataLen();
+ int iDataSizeIAT = 0;
+ int i;
+ for (i=0; i < m_dllCount; i++) {
+ m_iDataDlls[i].m_iltOffset = iDataSizeRO + iDataSizeIAT;
+ iDataSizeIAT += (m_iDataDlls[i].m_numMethods + 1)
+ * (getPEWriter().isPE32() ? sizeof(IMAGE_THUNK_DATA32)
+ : sizeof(IMAGE_THUNK_DATA64));
+ }
+
+ iDataSizeRO += iDataSizeIAT;
+
+ for (i=0; i < m_dllCount; i++) {
+ int delta = (iDataSizeRO + iDataOffsetRO) % 16;
+ // make sure is on a 16-byte offset
+ if (delta != 0)
+ iDataSizeRO += (16 - delta);
+ _ASSERTE((iDataSizeRO + iDataOffsetRO) % 16 == 0);
+ m_iDataDlls[i].m_ibnOffset = iDataSizeRO;
+ for (int j=0; j < m_iDataDlls[i].m_numMethods; j++) {
+ int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
+ iDataSizeRO += sizeof(WORD) + nameLen + nameLen%2;
+ }
+ }
+ for (i=0; i < m_dllCount; i++) {
+ m_iDataDlls[i].m_nameOffset = iDataSizeRO;
+ iDataSizeRO += (int)(strlen(m_iDataDlls[i].m_name) + 2);
+ }
+
+ char *iDataRO = iDataSectionRO.getBlock(iDataSizeRO);
+
+ if (!iDataRO) return E_OUTOFMEMORY;
+
+ memset(iDataRO, '\0', iDataSizeRO);
+
+ setDirectoryEntry(iDataSectionRO, IMAGE_DIRECTORY_ENTRY_IMPORT, iDataSizeRO, iDataOffsetRO);
+
+ IMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)iDataRO;
+ for (i=0; i < m_dllCount; i++) {
+
+ // fill in the import descriptors for each DLL
+ IMAGE_IMPORT_DESC_FIELD(iid[i], OriginalFirstThunk) = VAL32((ULONG)(m_iDataDlls[i].m_iltOffset + iDataOffsetRO));
+ iid[i].Name = VAL32(m_iDataDlls[i].m_nameOffset + iDataOffsetRO);
+ iid[i].FirstThunk = VAL32((ULONG)(m_iDataDlls[i].m_iatOffset + m_iDataOffsetIAT));
+
+ iDataSectionRO.addSectReloc(
+ (unsigned)(iDataOffsetRO + (char *)(&IMAGE_IMPORT_DESC_FIELD(iid[i], OriginalFirstThunk)) - iDataRO), iDataSectionRO, srRelocAbsolute);
+ iDataSectionRO.addSectReloc(
+ (unsigned)(iDataOffsetRO + (char *)(&iid[i].Name) - iDataRO), iDataSectionRO, srRelocAbsolute);
+ iDataSectionRO.addSectReloc(
+ (unsigned)(iDataOffsetRO + (char *)(&iid[i].FirstThunk) - iDataRO), *m_iDataSectionIAT, srRelocAbsolute);
+
+ if (getPEWriter().isPE32())
+ {
+ // now fill in the import lookup table for each DLL
+ IMAGE_THUNK_DATA32 *ilt = (IMAGE_THUNK_DATA32*) (iDataRO + m_iDataDlls[i].m_iltOffset);
+ IMAGE_THUNK_DATA32 *iat = (IMAGE_THUNK_DATA32*) (m_iDataIAT + m_iDataDlls[i].m_iatOffset);
+
+ int ibnOffset = m_iDataDlls[i].m_ibnOffset;
+ for (int j=0; j < m_iDataDlls[i].m_numMethods; j++)
+ {
+ ilt[j].u1.AddressOfData = VAL32((ULONG)(ibnOffset + iDataOffsetRO));
+ iat[j].u1.AddressOfData = VAL32((ULONG)(ibnOffset + iDataOffsetRO));
+
+ iDataSectionRO.addSectReloc( (unsigned)(iDataOffsetRO + (char *)(&ilt[j].u1.AddressOfData) - iDataRO),
+ iDataSectionRO, srRelocAbsolute);
+ m_iDataSectionIAT->addSectReloc( (unsigned)(m_iDataOffsetIAT + (char *)(&iat[j].u1.AddressOfData) - m_iDataIAT),
+ iDataSectionRO, srRelocAbsolute);
+ int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
+ memcpy(iDataRO + ibnOffset + offsetof(IMAGE_IMPORT_BY_NAME, Name),
+ m_iDataDlls[i].m_methodName[j], nameLen);
+ ibnOffset += sizeof(WORD) + nameLen + nameLen%2;
+ }
+ }
+ else
+ {
+ // now fill in the import lookup table for each DLL
+ IMAGE_THUNK_DATA64 *ilt = (IMAGE_THUNK_DATA64*) (iDataRO + m_iDataDlls[i].m_iltOffset);
+ IMAGE_THUNK_DATA64 *iat = (IMAGE_THUNK_DATA64*) (m_iDataIAT + m_iDataDlls[i].m_iatOffset);
+
+ int ibnOffset = m_iDataDlls[i].m_ibnOffset;
+ for (int j=0; j < m_iDataDlls[i].m_numMethods; j++)
+ {
+ ilt[j].u1.AddressOfData = VAL64((ULONG)(ibnOffset + iDataOffsetRO));
+ iat[j].u1.AddressOfData = VAL64((ULONG)(ibnOffset + iDataOffsetRO));
+
+ iDataSectionRO.addSectReloc( (unsigned)(iDataOffsetRO + (char *)(&ilt[j].u1.AddressOfData) - iDataRO),
+ iDataSectionRO, srRelocAbsolute);
+ m_iDataSectionIAT->addSectReloc( (unsigned)(m_iDataOffsetIAT + (char *)(&iat[j].u1.AddressOfData) - m_iDataIAT),
+ iDataSectionRO, srRelocAbsolute);
+ int nameLen = (int)(strlen(m_iDataDlls[i].m_methodName[j]) + 1);
+ memcpy(iDataRO + ibnOffset + offsetof(IMAGE_IMPORT_BY_NAME, Name),
+ m_iDataDlls[i].m_methodName[j], nameLen);
+ ibnOffset += sizeof(WORD) + nameLen + nameLen%2;
+ }
+ }
+
+ // now fill in the import lookup table for each DLL
+ strcpy_s(iDataRO + m_iDataDlls[i].m_nameOffset,
+ iDataSizeRO - m_iDataDlls[i].m_nameOffset,
+ m_iDataDlls[i].m_name);
+
+ } // end of for loop i < m_dllCount
+
+
+ if (getPEWriter().isI386())
+ {
+ // Put the entry point code into the PE file
+ unsigned entryPointOffset = getTextSection().dataLen();
+ int iatOffset = (int) (entryPointOffset + (m_dllSwitch ? CorDllMainX86IATOffset : CorExeMainX86IATOffset));
+ align = 4; // x86 fixups must be 4-byte aligned
+
+ // The IAT offset must be aligned because fixup is applied to it.
+ diff = ((iatOffset + align -1) & ~(align-1)) - iatOffset;
+ if (diff)
+ {
+ char* pDiff = getTextSection().getBlock(diff);
+ if(NULL==pDiff) return E_OUTOFMEMORY;
+ memset(pDiff,0,diff);
+ entryPointOffset += diff;
+ }
+ _ASSERTE((getTextSection().dataLen() + (m_dllSwitch ? CorDllMainX86IATOffset : CorExeMainX86IATOffset)) % align == 0);
+
+ getPEWriter().setEntryPointTextOffset(entryPointOffset);
+ if (m_dllSwitch)
+ {
+ UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainX86Template));
+ if(dllMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(dllMainBuf, DllMainX86Template, sizeof(DllMainX86Template));
+ //mscoree.dll
+ setAddrReloc(dllMainBuf+CorDllMainX86IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
+ addAddrReloc(getTextSection(), dllMainBuf, entryPointOffset+CorDllMainX86IATOffset, m_iDataSectionIAT);
+ }
+ else
+ {
+ UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainX86Template));
+ if(exeMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(exeMainBuf, ExeMainX86Template, sizeof(ExeMainX86Template));
+ //mscoree.dll
+ setAddrReloc(exeMainBuf+CorExeMainX86IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
+ addAddrReloc(getTextSection(), exeMainBuf, entryPointOffset+CorExeMainX86IATOffset, m_iDataSectionIAT);
+ }
+ }
+ else if (getPEWriter().isAMD64())
+ {
+ // Put the entry point code into the PE file
+ unsigned entryPointOffset = getTextSection().dataLen();
+ int iatOffset = (int) (entryPointOffset + (m_dllSwitch ? CorDllMainAMD64IATOffset : CorExeMainAMD64IATOffset));
+ align = 16; // AMD64 fixups must be 8-byte aligned
+
+ // The IAT offset must be aligned because fixup is applied to it.
+ diff = ((iatOffset + align -1) & ~(align-1)) - iatOffset;
+ if (diff)
+ {
+ char* pDiff = getTextSection().getBlock(diff);
+ if(NULL==pDiff) return E_OUTOFMEMORY;
+ memset(pDiff,0,diff);
+ entryPointOffset += diff;
+ }
+ _ASSERTE((getTextSection().dataLen() + (m_dllSwitch ? CorDllMainAMD64IATOffset : CorExeMainAMD64IATOffset)) % align == 0);
+
+ getPEWriter().setEntryPointTextOffset(entryPointOffset);
+ if (m_dllSwitch)
+ {
+ UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainAMD64Template));
+ if(dllMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(dllMainBuf, DllMainAMD64Template, sizeof(DllMainAMD64Template));
+ //mscoree.dll
+ setAddrReloc(dllMainBuf+CorDllMainAMD64IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
+ addAddrReloc(getTextSection(), dllMainBuf, entryPointOffset+CorDllMainAMD64IATOffset, m_iDataSectionIAT);
+ }
+ else
+ {
+ UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainAMD64Template));
+ if(exeMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(exeMainBuf, ExeMainAMD64Template, sizeof(ExeMainAMD64Template));
+ //mscoree.dll
+ setAddrReloc(exeMainBuf+CorExeMainAMD64IATOffset, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
+ addAddrReloc(getTextSection(), exeMainBuf, entryPointOffset+CorExeMainAMD64IATOffset, m_iDataSectionIAT);
+ }
+ }
+ else if (getPEWriter().isIA64())
+ {
+ // Must have a PE+ PE64 file
+ //_ASSERTE(!getPEWriter().isPE32());
+
+ // Put the entry point code into the PE+ file
+ curOffset = getTextSection().dataLen();
+ align = 16; // instructions on ia64 must be 16-byte aligned
+
+ // The entry point address be aligned
+ diff = ((curOffset + align -1) & ~(align-1)) - curOffset;
+ if (diff)
+ {
+ char* pDiff = getTextSection().getBlock(diff);
+ if(NULL==pDiff) return E_OUTOFMEMORY;
+ memset(pDiff,0,diff);
+ }
+
+ unsigned entryPointOffset = getTextSection().dataLen();
+
+ if (m_dllSwitch)
+ {
+ UCHAR *dllMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(DllMainIA64Template));
+ if (dllMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(dllMainBuf, DllMainIA64Template, sizeof(DllMainIA64Template));
+ }
+ else
+ {
+ UCHAR *exeMainBuf = (UCHAR*)getTextSection().getBlock(sizeof(ExeMainIA64Template));
+ if (exeMainBuf==NULL) return E_OUTOFMEMORY;
+ memcpy(exeMainBuf, ExeMainIA64Template, sizeof(ExeMainIA64Template));
+ }
+
+ // Put the entry point function pointer into the PE file
+ unsigned entryPlabelOffset = getTextSection().dataLen();
+ getPEWriter().setEntryPointTextOffset(entryPlabelOffset);
+
+ UCHAR * entryPtr = (UCHAR*)getTextSection().getBlock(sizeof(ULONGLONG));
+ UCHAR * gpPtr = (UCHAR*)getTextSection().getBlock(sizeof(ULONGLONG));
+
+ memset(entryPtr,0,sizeof(ULONGLONG));
+ memset(gpPtr,0,sizeof(ULONGLONG));
+
+ setAddrReloc(entryPtr, entryPointOffset);
+ addAddrReloc(getTextSection(), entryPtr, entryPlabelOffset, &getTextSection());
+
+ setAddrReloc(gpPtr, m_iDataDlls[0].m_iatOffset + m_iDataOffsetIAT);
+ addAddrReloc(getTextSection(), gpPtr, entryPlabelOffset+8, m_iDataSectionIAT);
+ }
+ else
+ {
+ _ASSERTE(!"Unknown target machine");
+ }
+
+ // Now set our IAT entry since we're using the IAT
+ setDirectoryEntry(*m_iDataSectionIAT, IMAGE_DIRECTORY_ENTRY_IAT, iDataSizeIAT, m_iDataOffsetIAT);
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::emitExeMain()
+
+
+HRESULT GetClrSystemDirectory(SString& pbuffer)
+{
+ HRESULT hr = S_OK;
+
+
+ PathString pPath;
+ DWORD dwPath;
+
+ _ASSERTE (g_hThisInst);
+
+ dwPath = WszGetModuleFileName(g_hThisInst, pPath);
+ if(dwPath == 0)
+ {
+ hr = HRESULT_FROM_GetLastErrorNA();
+ return (hr);
+ }
+
+ return CopySystemDirectory(pPath, pbuffer);
+}
+
+#ifndef FEATURE_PAL
+BOOL RunProcess(LPCWSTR tempResObj, LPCWSTR pszFilename, DWORD* pdwExitCode, PEWriter &pewriter)
+{
+ BOOL fSuccess = FALSE;
+
+ PROCESS_INFORMATION pi;
+
+ PathString wszSystemDir;
+ if (FAILED(GetClrSystemDirectory(wszSystemDir)))
+ return FALSE;
+
+ WCHAR* wzMachine;
+ if(pewriter.isIA64())
+ wzMachine = L"IA64";
+ else if(pewriter.isAMD64())
+ wzMachine = L"AMD64";
+ else if(pewriter.isARM())
+ wzMachine = L"ARM";
+ else
+ wzMachine = L"IX86";
+
+ // Res file, so convert it
+ StackSString ssCmdLine;
+
+ LPWSTR ext = PathFindExtension(pszFilename);
+ if(*ext == NULL)
+ {
+ ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s.\"",
+ wszSystemDir.GetUnicode(),
+ wzMachine,
+ tempResObj,
+ pszFilename);
+ }
+ else
+ {
+ ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s\"",
+ wszSystemDir.GetUnicode(),
+ wzMachine,
+ tempResObj,
+ pszFilename);
+ }
+
+ STARTUPINFOW start;
+ ZeroMemory(&start, sizeof(start));
+ start.cb = sizeof(start);
+ start.dwFlags = STARTF_USESHOWWINDOW;
+ start.wShowWindow = SW_HIDE;
+
+ fSuccess = WszCreateProcess(
+ NULL,
+ ssCmdLine.GetUnicode(),
+ NULL,
+ NULL,
+ true,
+ 0,
+ 0,
+ NULL,
+ &start,
+ &pi);
+
+ // If process runs, wait for it to finish
+ if (fSuccess) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ GetExitCodeProcess(pi.hProcess, pdwExitCode);
+
+ CloseHandle(pi.hProcess);
+
+ CloseHandle(pi.hThread);
+ }
+ return fSuccess;
+} // BOOL RunProcess()
+
+// Ensure that pszFilename is an object file (not just a binary resource)
+// If we convert, then return obj filename in pszTempFilename
+HRESULT ConvertResource(const WCHAR * pszFilename, __in_ecount(cchTempFilename) WCHAR *pszTempFilename, size_t cchTempFilename, PEWriter &pewriter)
+{
+ HANDLE hFile = WszCreateFile(pszFilename, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+// failure
+ if (!hFile || (hFile == INVALID_HANDLE_VALUE))
+ {
+ //dbprintf("Can't find resource files:%S\n", pszFilename);
+ return HRESULT_FROM_GetLastError();
+ }
+
+// Read first 4 bytes. If they're all 0, we have a win32 .res file which must be
+// converted. (So call CvtRes.exe). Else it's an obj file.
+
+ DWORD dwCount = -1;
+ DWORD dwData = -1;
+
+ BOOL fRet = ReadFile(hFile,
+ &dwData,
+ 4,
+ &dwCount,
+ NULL
+ );
+
+ CloseHandle(hFile);
+
+ if (!fRet) {
+ //dbprintf("Invalid resource file:%S\n", pszFilename);
+ return HRESULT_FROM_GetLastError();
+ }
+
+ if (dwData != 0)
+ {
+ return S_OK;
+ }
+
+ PathString tempResObj;
+ PathString tempResPath;
+
+ // Create the temp file where the temp path is at rather than where the application is at.
+ if (!WszGetTempPath( tempResPath))
+ {
+ return HRESULT_FROM_GetLastError();
+ }
+
+ if (!WszGetTempFileName(tempResPath, L"RES", 0, tempResObj))
+ {
+ //dbprintf("GetTempFileName failed\n");
+ return HRESULT_FROM_GetLastError();
+ }
+
+ DWORD dwExitCode;
+ fRet = RunProcess(tempResObj, pszFilename, &dwExitCode, pewriter);
+
+ if (!fRet)
+ { // Couldn't run cvtres.exe
+ return PostError(CEE_E_CVTRES_NOT_FOUND);
+ }
+ else if (dwExitCode != 0)
+ { // CvtRes.exe ran, but failed
+ return HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ }
+ else
+ { // Conversion succesful, so return filename.
+ wcscpy_s(pszTempFilename, cchTempFilename, tempResObj);
+ }
+
+ return S_OK;
+} // HRESULT ConvertResource()
+
+
+
+// This function reads a resource file and emits it into the generated PE file.
+// 1. We can only link resources in obj format. Must convert from .res to .obj
+// with CvtRes.exe.
+// 2. Must touch up all COFF relocs from .rsrc$01 (resource header) to .rsrc$02
+// (resource raw data)
+HRESULT CeeFileGenWriter::emitResourceSection()
+{
+ if (m_resourceFileName == NULL)
+ return S_OK;
+
+ // Make sure szResFileName is an obj, not just a .res; change name if we convert
+ WCHAR szTempFileName[MAX_PATH+1];
+ szTempFileName[0] = L'\0';
+ HRESULT hr = ConvertResource(m_resourceFileName, szTempFileName,
+ MAX_PATH+1, getPEWriter());
+ if (FAILED(hr)) return hr;
+
+ // Filename may change (if we convert .res to .obj), so have floating pointer
+ const WCHAR* szResFileName;
+ if (*szTempFileName)
+ szResFileName = szTempFileName;
+ else
+ szResFileName = m_resourceFileName;
+
+ _ASSERTE(szResFileName);
+
+ // read the resource file and spit it out in the .rsrc section
+
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hMap = NULL;
+ IMAGE_FILE_HEADER *hMod = NULL;
+
+ hr = S_OK;
+
+ struct Param
+ {
+ HANDLE hFile;
+ HANDLE hMap;
+ IMAGE_FILE_HEADER *hMod;
+ const WCHAR* szResFileName;
+ CeeFileGenWriter *genWriter;
+ HRESULT hr;
+ } param;
+
+ param.hFile = hFile;
+ param.hMap = hMap;
+ param.hMod = hMod;
+ param.szResFileName = szResFileName;
+ param.genWriter = this;
+ param.hr = S_OK;
+
+ PAL_TRY(Param *, pParam, &param)
+ {
+ SIZE_T cbFileSize;
+ const BYTE *pbStartOfMappedMem;
+ IMAGE_SECTION_HEADER *rsrc[2] = { NULL, NULL };
+ S_SIZE_T cbTotalSizeOfRawData;
+ // create a mapped view of the .res file
+ pParam->hFile = WszCreateFile(pParam->szResFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (pParam->hFile == INVALID_HANDLE_VALUE)
+ {
+ //dbprintf("Resource file %S not found\n", szResFileName);
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ // Grab the file size for verification checks.
+ {
+ DWORD dwFileSizeHigh;
+ DWORD dwFileSize = SafeGetFileSize(pParam->hFile, &dwFileSizeHigh);
+ if (dwFileSize == (DWORD)(-1))
+ {
+ pParam->hr = HRESULT_FROM_GetLastError();
+ goto lDone;
+ }
+
+ // Since we intend to memory map this file, the size of the file can not need 64 bits to represent!
+ if (dwFileSizeHigh != 0)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ cbFileSize = static_cast<SIZE_T>(dwFileSize);
+ }
+
+ pParam->hMap = WszCreateFileMapping(pParam->hFile, 0, PAGE_READONLY, 0, 0, NULL);
+
+ if (pParam->hMap == NULL)
+ {
+ //dbprintf("Invalid .res file: %S\n", szResFileName);
+ pParam->hr = HRESULT_FROM_GetLastError();
+ goto lDone;
+ }
+
+ pbStartOfMappedMem = reinterpret_cast<const BYTE *>(MapViewOfFile(pParam->hMap, FILE_MAP_READ, 0, 0, 0));
+
+ // test failure conditions
+ if (pbStartOfMappedMem == NULL)
+ {
+ //dbprintf("Invalid .res file: %S:Can't get header\n", szResFileName);
+ pParam->hr = HRESULT_FROM_GetLastError();
+ goto lDone;
+ }
+
+ // Check that the file contains an IMAGE_FILE_HEADER structure.
+ if (IMAGE_SIZEOF_FILE_HEADER > cbFileSize)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ pParam->hMod = (IMAGE_FILE_HEADER*)pbStartOfMappedMem;
+
+ if (VAL16(pParam->hMod->SizeOfOptionalHeader) != 0)
+ {
+ //dbprintf("Invalid .res file: %S:Illegal optional header\n", szResFileName);
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); // GetLastError() = 0 since API worked.
+ goto lDone;
+ }
+
+ // Scan all section headers and grab .rsrc$01 and .rsrc$02
+ {
+ // First section is directly after header
+ SIZE_T cSections = static_cast<SIZE_T>(VAL16(pParam->hMod->NumberOfSections));
+ SIZE_T cbStartOfSections = IMAGE_SIZEOF_FILE_HEADER;
+ S_SIZE_T cbEndOfSections(S_SIZE_T(cbStartOfSections) +
+ (S_SIZE_T(cSections) * S_SIZE_T(IMAGE_SIZEOF_SECTION_HEADER)));
+
+ // Check that all sections are within the bounds of the mapped file.
+ if (cbEndOfSections.IsOverflow() ||
+ cbEndOfSections.Value() > cbFileSize)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ {
+ IMAGE_SECTION_HEADER *pSection =
+ (IMAGE_SECTION_HEADER *)(pbStartOfMappedMem + cbStartOfSections);
+ IMAGE_SECTION_HEADER *pSectionEnd = pSection + cSections;
+
+ for (; pSection < pSectionEnd; pSection++)
+ {
+ if (strcmp(".rsrc$01", (char *)pSection->Name) == 0)
+ {
+ rsrc[0] = pSection;
+ }
+ else if (strcmp(".rsrc$02", (char *)pSection->Name) == 0)
+ {
+ rsrc[1] = pSection;
+ }
+ }
+ }
+ }
+
+ // If we don't have both resources, fail.
+ if (!rsrc[0] || !rsrc[1])
+ {
+ //dbprintf("Invalid .res file: %S: Missing sections .rsrc$01 or .rsrc$02\n", szResFileName);
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ // Verify the resource data starts and sizes
+ {
+ cbTotalSizeOfRawData = S_SIZE_T(0);
+
+ for (int i = 0; i < 2; i++)
+ {
+ S_SIZE_T cbStartOfResourceData(static_cast<SIZE_T>(VAL32(rsrc[i]->PointerToRawData)));
+ S_SIZE_T cbSizeOfResourceData(static_cast<SIZE_T>(VAL32(rsrc[i]->SizeOfRawData)));
+ S_SIZE_T cbEndOfResourceData(cbStartOfResourceData + cbSizeOfResourceData);
+
+ if (cbEndOfResourceData.IsOverflow() ||
+ cbEndOfResourceData.Value() > cbFileSize)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ cbTotalSizeOfRawData += cbSizeOfResourceData;
+ }
+
+ // Check that the total raw data doesn't overflow.
+ if (cbTotalSizeOfRawData.IsOverflow() ||
+ cbTotalSizeOfRawData.Value() > cbFileSize)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+ }
+
+ PESection *rsrcSection;
+ pParam->hr = pParam->genWriter->getPEWriter().getSectionCreate(".rsrc", sdReadOnly, &rsrcSection);
+ if (FAILED(pParam->hr)) goto lDone;
+
+ rsrcSection->directoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+ char *data = rsrcSection->getBlock(static_cast<unsigned>(cbTotalSizeOfRawData.Value()), 8);
+ if(data == NULL)
+ {
+ pParam->hr = E_OUTOFMEMORY;
+ goto lDone;
+ }
+
+ // Copy resource header
+ memcpy(data, (char *)pParam->hMod + VAL32(rsrc[0]->PointerToRawData), VAL32(rsrc[0]->SizeOfRawData));
+
+ // Map all the relocs in .rsrc$01 using the reloc and symbol tables in the COFF object.,
+ SIZE_T cReloc = 0; // Total number of relocs
+ IMAGE_RELOCATION *pReloc = NULL; // Reloc table start
+
+ SIZE_T cSymbol = 0; // Total number of symbols
+ IMAGE_SYMBOL *pSymbolTable = NULL; // Symbol table start
+
+ {
+ // Check that the relocations and symbols lie within the resource
+ cReloc = VAL16(rsrc[0]->NumberOfRelocations);
+ SIZE_T cbStartOfRelocations = static_cast<SIZE_T>(VAL32(rsrc[0]->PointerToRelocations));
+ S_SIZE_T cbEndOfRelocations(S_SIZE_T(cbStartOfRelocations) +
+ (S_SIZE_T(cReloc) * S_SIZE_T(sizeof(IMAGE_RELOCATION))));
+
+
+ // Verify the number of symbols fit into the resource.
+ cSymbol = static_cast<SIZE_T>(VAL32(pParam->hMod->NumberOfSymbols));
+ SIZE_T cbStartOfSymbolTable = static_cast<SIZE_T>(VAL32(pParam->hMod->PointerToSymbolTable));
+ S_SIZE_T cbEndOfSymbolTable(S_SIZE_T(cbStartOfSymbolTable) +
+ (S_SIZE_T(cSymbol) * S_SIZE_T(IMAGE_SIZEOF_SYMBOL)));
+
+ if (cbEndOfRelocations.IsOverflow() ||
+ cbEndOfRelocations.Value() > cbFileSize ||
+ cbEndOfSymbolTable.IsOverflow() ||
+ cbEndOfSymbolTable.Value() > cbFileSize)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ pReloc = (IMAGE_RELOCATION *)(pbStartOfMappedMem + cbStartOfRelocations);
+ pSymbolTable = (IMAGE_SYMBOL *)(pbStartOfMappedMem + cbStartOfSymbolTable);
+ }
+
+ _ASSERTE(pReloc != NULL && pSymbolTable != NULL);
+
+ for(SIZE_T iReloc = 0; iReloc < cReloc; iReloc++, pReloc++)
+ {
+ // Ensure this is a valid reloc
+ {
+ S_SIZE_T cbRelocEnd = S_SIZE_T(VAL32(pReloc->VirtualAddress)) + S_SIZE_T(sizeof(DWORD));
+ if (cbRelocEnd.IsOverflow() ||
+ cbRelocEnd.Value() > static_cast<SIZE_T>(VAL32(rsrc[0]->SizeOfRawData)))
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+ }
+
+ // index into symbol table, provides address into $02
+ DWORD iSymbol = VAL32(pReloc->SymbolTableIndex);
+
+ // Make sure the index is in range
+ if (iSymbol >= cSymbol)
+ {
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ IMAGE_SYMBOL* pSymbolEntry = GetSymbolEntry(pSymbolTable, iSymbol);
+
+ // Ensure the symbol entry is valid for a resource.
+ if ((pSymbolEntry->StorageClass != IMAGE_SYM_CLASS_STATIC) ||
+ (VAL16(pSymbolEntry->Type) != IMAGE_SYM_TYPE_NULL) ||
+ (VAL16(pSymbolEntry->SectionNumber) != 3)) // 3rd section is .rsrc$02
+ {
+ //dbprintf("Invalid .res file: %S:Illegal symbol entry\n", szResFileName);
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ // Ensure that RVA is valid address (inside rsrc[1])
+ if (VAL32(pSymbolEntry->Value) >= VAL32(rsrc[1]->SizeOfRawData))
+ {
+ //dbprintf("Invalid .res file: %S:Illegal rva into .rsrc$02\n", szResFileName);
+ pParam->hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ goto lDone;
+ }
+
+ DWORD dwOffsetInRsrc2 = VAL32(pSymbolEntry->Value) + VAL32(rsrc[0]->SizeOfRawData);
+
+ // Create reloc
+ *(DWORD*)(data + VAL32(pReloc->VirtualAddress)) = VAL32(dwOffsetInRsrc2);
+ rsrcSection->addSectReloc(pReloc->VirtualAddress, rsrcSection, srRelocAbsolute);
+ }
+
+ // Copy $02 (resource raw) data
+ memcpy(data+VAL32(rsrc[0]->SizeOfRawData),
+ (char *)pParam->hMod + VAL32(rsrc[1]->PointerToRawData),
+ VAL32(rsrc[1]->SizeOfRawData));
+
+lDone: ;
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ //dbprintf("Exception occured manipulating .res file %S\n", szResFileName);
+ param.hr = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
+ }
+ PAL_ENDTRY
+
+ hMod = param.hMod;
+ hFile = param.hFile;
+ szResFileName = param.szResFileName;
+ hr = param.hr;
+
+ if (hMod != NULL)
+ UnmapViewOfFile(hMod);
+ if (hMap != NULL)
+ CloseHandle(hMap);
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+ if (szResFileName == szTempFileName)
+ // delete temporary file if we created one
+ WszDeleteFile(szResFileName);
+
+ return hr;
+} // HRESULT CeeFileGenWriter::emitResourceSection()
+#endif // !FEATURE_PAL
+
+HRESULT CeeFileGenWriter::setManifestEntry(ULONG size, ULONG offset)
+{
+ if (offset)
+ m_dwManifestRVA = offset;
+ else {
+ CeeSection TextSection = getTextSection();
+ getMethodRVA(TextSection.dataLen() - size, &m_dwManifestRVA);
+ }
+
+ m_dwManifestSize = size;
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setManifestEntry()
+
+HRESULT CeeFileGenWriter::setStrongNameEntry(ULONG size, ULONG offset)
+{
+ m_dwStrongNameRVA = offset;
+ m_dwStrongNameSize = size;
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setStrongNameEntry()
+
+HRESULT CeeFileGenWriter::setVTableEntry64(ULONG size, void* ptr)
+{
+ if (ptr && size)
+ {
+ void * pv;
+ CeeSection TextSection = getTextSection();
+ // make it DWORD-aligned
+ ULONG L = TextSection.dataLen();
+ if((L &= ((ULONG)sizeof(DWORD)-1)))
+ {
+ L = (ULONG)sizeof(DWORD) - L;
+ if((pv = TextSection.getBlock(L)))
+ memset(pv,0,L);
+ else
+ return E_OUTOFMEMORY;
+ }
+ getMethodRVA(TextSection.dataLen(), &m_dwVTableRVA);
+ if((pv = TextSection.getBlock(size)))
+ {
+ memcpy(pv,ptr,size);
+ }
+ else
+ return E_OUTOFMEMORY;
+ m_dwVTableSize = size;
+ }
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setVTableEntry()
+
+HRESULT CeeFileGenWriter::setVTableEntry(ULONG size, ULONG offset)
+{
+ return setVTableEntry64(size,(void*)(ULONG_PTR)offset);
+} // HRESULT CeeFileGenWriter::setVTableEntry()
+
+HRESULT CeeFileGenWriter::setEnCRvaBase(ULONG dataBase, ULONG rdataBase)
+{
+ setEnCMode();
+ getPEWriter().setEnCRvaBase(dataBase, rdataBase);
+ return S_OK;
+} // HRESULT CeeFileGenWriter::setEnCRvaBase()
+
+HRESULT CeeFileGenWriter::computeSectionOffset(CeeSection &section, __in char *ptr,
+ unsigned *offset)
+{
+ *offset = section.computeOffset(ptr);
+
+ return S_OK;
+} // HRESULT CeeFileGenWriter::computeSectionOffset()
+
+HRESULT CeeFileGenWriter::computeOffset(__in char *ptr,
+ CeeSection **pSection, unsigned *offset)
+{
+ TESTANDRETURNPOINTER(pSection);
+
+ CeeSection **s = m_sections;
+ CeeSection **sEnd = s + m_numSections;
+ while (s < sEnd)
+ {
+ if ((*s)->containsPointer(ptr))
+ {
+ *pSection = *s;
+ *offset = (*s)->computeOffset(ptr);
+
+ return S_OK;
+ }
+ s++;
+ }
+
+ return E_FAIL;
+} // HRESULT CeeFileGenWriter::computeOffset()
+
+HRESULT CeeFileGenWriter::getCorHeader(IMAGE_COR20_HEADER **ppHeader)
+{
+ *ppHeader = m_corHeader;
+ return S_OK;
+} // HRESULT CeeFileGenWriter::getCorHeader()
+
+
+#ifdef EMIT_FIXUPS
+
+HRESULT CeeFileGenWriter::InitFixupSection()
+{
+ if (!m_fEmitFixups)
+ {
+ return(E_UNEXPECTED);
+ }
+
+ HRESULT hr;
+
+ hr = getSectionCreate(".fixups",
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
+ &m_sectionFixups);
+ if (SUCCEEDED(hr))
+ {
+ size_t cbDebugDir = sizeof(IMAGE_DEBUG_DIRECTORY);
+ hr = GetSectionBlock(m_sectionFixups, (ULONG) cbDebugDir, 32, (void **) &m_pDebugDir);
+ if (SUCCEEDED(hr))
+ {
+ memset(m_pDebugDir, 0, cbDebugDir);
+ m_pDebugDir->Type = IMAGE_DEBUG_TYPE_FIXUP;
+ m_fFixupsUpdated = false;
+
+ return(S_OK);
+ }
+ }
+
+ m_pDebugDir = NULL;
+ m_sectionFixups = NULL;
+ m_fEmitFixups = false;
+
+ return(E_FAIL);
+
+} // HRESULT CeeFileGenWriter::InitFixupSection()
+
+HRESULT CeeFileGenWriter::addFixup(CeeSection& sectionSource, unsigned offset, CeeSectionRelocType relocType, CeeSection * psectionTarget, CeeSectionRelocExtra *extra)
+{
+ if (!m_fEmitFixups)
+ {
+ return(S_OK);
+ }
+
+ _ASSERTE(sizeof(DBG_FIXUP) == sizeof(PEFIXUP));
+ _ASSERTE(m_fFixupsUpdated == false);
+
+ DBG_FIXUP * pfixup;
+
+ if (m_sectionFixups == NULL)
+ {
+ HRESULT hr = InitFixupSection();
+ if (FAILED(hr))
+ {
+ return(hr);
+ }
+
+ // The fixup section begins with a IMAGE_DEBUG_DIRECTORY containing a
+ // IMAGE_DEBUG_TYPE_FIXUP directory entry, which describes the array
+ // of fixups which follows it.
+
+ // The very first item of this array is aligned on a 32 bit boundary.
+ // All other fixup entries follow unaligned.
+ pfixup = (DBG_FIXUP *) m_sectionFixups->getBlock(sizeof(DBG_FIXUP), 32);
+ TESTANDRETURN(pfixup != NULL, E_OUTOFMEMORY);
+
+ // Initialize the IMAGE_DEBUG_TYPE_FIXUP entry relocations
+#ifdef _WIN64
+ _ASSERTE(!"Base relocs are not yet implemented for 64-bit");
+ m_pDebugDir->AddressOfRawData = 0; // @ToDo: srRelocAbsolutePtr can't take a 64-bit address
+#else
+ m_pDebugDir->AddressOfRawData = (size_t) pfixup;
+ m_sectionFixups->addSectReloc(offsetof(IMAGE_DEBUG_DIRECTORY, AddressOfRawData), *m_sectionFixups, srRelocAbsolutePtr);
+#endif
+
+ m_pDebugDir->PointerToRawData = m_sectionFixups->computeOffset((char *) pfixup);
+
+ m_sectionFixups->addSectReloc(offsetof(IMAGE_DEBUG_DIRECTORY, PointerToRawData), *m_sectionFixups, srRelocFilePos);
+
+ unsigned offsetDir = m_sectionFixups->computeOffset((char *) m_pDebugDir);
+ setDirectoryEntry(*m_sectionFixups, IMAGE_DIRECTORY_ENTRY_DEBUG, sizeof(IMAGE_DEBUG_DIRECTORY), offsetDir);
+
+#ifdef TEST_EMIT_FIXUPS
+ TestEmitFixups();
+#endif
+ }
+ else
+ {
+ pfixup = (DBG_FIXUP *) m_sectionFixups->getBlock(sizeof(DBG_FIXUP), 1);
+ TESTANDRETURN(pfixup != NULL, E_OUTOFMEMORY);
+ }
+
+ // Save off the relocation information for use later. The relocation's
+ // target information can be filled in later.
+ // The relocation target info is not always immediately available, so it needs
+ // to be extracted later, during the link phase. For now the relocation info
+ // is stored so the target can be extracted at link time in the UpdateFixups
+ // function.
+ //
+ unsigned offsetFixup = m_sectionFixups->computeOffset((char *) pfixup);
+ pfixup->wSpare = 0;
+ pfixup->wType = relocType;
+ _ASSERTE(pfixup->wType == relocType);
+ pfixup->offset = offset;
+ pfixup->sectionSource = &sectionSource;
+
+ m_pDebugDir->SizeOfData += sizeof(DBG_FIXUP);
+
+ // Add a relocation for the fixup's source RVA field, (no fixup on this reloc)
+ m_sectionFixups->addSectReloc(offsetFixup + offsetof(DBG_FIXUP, rva), sectionSource, srRelocAbsolutePtr);
+
+ // Add a relocation for the fixup's target RVA field. Correct target extracted
+ // later in UpdateFixups, (no fixup on this reloc)
+ CeeSectionRelocType tgtRelocType;
+
+ switch (relocType)
+ {
+ case srRelocMapToken:
+ // not an RVA
+ tgtRelocType = srRelocMapToken;
+ break;
+
+ case srRelocFilePos:
+ tgtRelocType = srRelocFilePos;
+ break;
+
+ case srRelocHighAdj:
+ tgtRelocType = srRelocHighAdj;
+ break;
+
+ default:
+ tgtRelocType = (relocType & srRelocPtr) ? srRelocAbsolutePtr : srRelocAbsolute;
+ break;
+ }
+
+ if (psectionTarget != NULL)
+ {
+ m_sectionFixups->addSectReloc(offsetFixup + offsetof(DBG_FIXUP, rvaTarget), *psectionTarget, tgtRelocType, extra);
+ }
+ else
+ {
+ m_sectionFixups->addBaseReloc(offsetFixup + offsetof(DBG_FIXUP, rvaTarget), tgtRelocType, extra);
+ }
+
+ return(S_OK);
+} // HRESULT CeeFileGenWriter::addFixup()
+
+HRESULT CeeFileGenWriter::UpdateFixups()
+{
+ // This method extracts the correct relocation target. See addFixup method.
+
+ if (!m_fEmitFixups || m_fFixupsUpdated)
+ {
+ return(S_OK);
+ }
+ m_fFixupsUpdated = true; // prevent UpdateFixups from being called again.
+
+ size_t cfixups = m_pDebugDir->SizeOfData / sizeof(DBG_FIXUP);
+ _ASSERT(m_pDebugDir->SizeOfData % sizeof(DBG_FIXUP) == 0);
+ unsigned ibFixup = m_pDebugDir->PointerToRawData;
+
+ for (size_t idx = 0; idx < cfixups; idx++, ibFixup += sizeof(DBG_FIXUP))
+ {
+ DBG_FIXUP * pfixup = (DBG_FIXUP *) m_sectionFixups->computePointer(ibFixup);
+ CeeSection * sectionSource = pfixup->sectionSource;
+ CeeSectionRelocType relocType = (CeeSectionRelocType) pfixup->wType;
+ unsigned offset = pfixup->offset;
+
+ // Get current data for replacing fixup contents
+ const DWORD * pdw = (DWORD *) sectionSource->computePointer(offset);
+ pfixup->rva = (DWORD) (UINT_PTR) pdw;
+ pfixup->rvaTarget = *pdw;
+
+ switch (relocType)
+ {
+#ifdef _X86_
+ case srRelocAbsolute:
+ // Emitted bytes: RVA, offset relative to image base
+ // reloc src contains target offset relative to target section
+ if ((*pdw & 0xFF000000) == 0)
+ {
+ pfixup->wType = IMAGE_REL_I386_DIR32NB;
+ }
+ else
+ {
+ // MethodDesc::Fixup function creates a 24 bit RVA, where the
+ // high byte of the DWORD stores the flag value: METHOD_NEEDS_PRESTUB_RUN_FLAG.
+ // work around it by converting the type to 24 bits here
+ pfixup->wType = IMAGE_REL_I386_DIR24NB;
+ pfixup->rvaTarget = *pdw & 0x00FFFFFF;
+ }
+ break;
+
+ case srRelocAbsolutePtr:
+ // Emitted bytes: RVA, offset relative to image base
+ // reloc src contains target pointer
+ pfixup->wType = IMAGE_REL_I386_DIR32NB;
+ break;
+
+ case srRelocHighLow:
+ // Emitted bytes: full address of target
+ // reloc src contains target offset relative to target section
+ pfixup->wType = IMAGE_REL_I386_DIR32;
+ break;
+
+ case srRelocHighLowPtr:
+ // Emitted bytes: full address of target
+ // reloc src contains target pointer
+ pfixup->wType = IMAGE_REL_I386_DIR32;
+ break;
+
+ case srRelocRelative:
+ // Emitted bytes: value of reloc tgt - (reloc source + sizeof(DWORD))
+ // reloc src contains offset relative to target section, minus sizeof(DWORD)
+ // the reloc type for pFixup->rvaTarget is srRelocAbsolute
+ // so contents of pFixup->rvaTarget need to be offset Target + sizeof(DWORD)
+ // which is offset Target == Source contents + sizeof(DWORD) == *pdw + sizeof(DWORD)
+ pfixup->wType = IMAGE_REL_I386_REL32;
+ pfixup->rvaTarget = *pdw + sizeof(DWORD);
+ break;
+
+ case srRelocRelativePtr:
+ // Emitted bytes: value of reloc tgt - (reloc source + sizeof(DWORD))
+ // reloc src contains disp, disp = pTarget - (pSource + sizeof(DWORD))
+ // the reloc type for pFixup->rvaTarget is srRelocAbsolutePtr
+ // so contents of pFixup->rvaTarget need to be pTarget
+ // which is pTarget == pSource + sizeof(DWORD) + disp == pdw + 4 + *pdw
+ pfixup->wType = IMAGE_REL_I386_REL32;
+ pfixup->rvaTarget = (int) (INT_PTR) pdw + sizeof(DWORD) + (int) *pdw;
+ break;
+
+ case srRelocMapToken:
+ // Emitted bytes: contents of reloc source unchanged.
+ // reloc src contains token value
+ pfixup->wType = IMAGE_REL_I386_TOKEN;
+ break;
+
+#elif defined(_AMD64_)
+ /*
+ //
+ // X86-64 relocations
+ //
+ IMAGE_REL_AMD64_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+ IMAGE_REL_AMD64_ADDR64 0x0001 // 64-bit address (VA).
+ IMAGE_REL_AMD64_ADDR32 0x0002 // 32-bit address (VA).
+ IMAGE_REL_AMD64_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
+ IMAGE_REL_AMD64_REL32 0x0004 // 32-bit relative address from byte following reloc
+ IMAGE_REL_AMD64_REL32_1 0x0005 // 32-bit relative address from byte distance 1 from reloc
+ IMAGE_REL_AMD64_REL32_2 0x0006 // 32-bit relative address from byte distance 2 from reloc
+ IMAGE_REL_AMD64_REL32_3 0x0007 // 32-bit relative address from byte distance 3 from reloc
+ IMAGE_REL_AMD64_REL32_4 0x0008 // 32-bit relative address from byte distance 4 from reloc
+ IMAGE_REL_AMD64_REL32_5 0x0009 // 32-bit relative address from byte distance 5 from reloc
+ IMAGE_REL_AMD64_SECTION 0x000A // Section index
+ IMAGE_REL_AMD64_SECREL 0x000B // 32 bit offset from base of section containing target
+ IMAGE_REL_AMD64_SECREL7 0x000C // 7 bit unsigned offset from base of section containing target
+ IMAGE_REL_AMD64_TOKEN 0x000D // 32 bit metadata token
+ IMAGE_REL_AMD64_SREL32 0x000E // 32 bit signed span-dependent value emitted into object
+ IMAGE_REL_AMD64_PAIR 0x000F
+ IMAGE_REL_AMD64_SSPAN32 0x0010 // 32 bit signed span-dependent value applied at link time
+ */
+ case srRelocAbsolute:
+ // Emitted bytes: RVA, offset relative to image base
+ pfixup->wType = IMAGE_REL_AMD64_ADDR32NB;
+ break;
+
+ case srRelocAbsolutePtr:
+ // Emitted bytes: RVA, offset relative to image base
+ // reloc src contains target pointer
+ pfixup->wType = IMAGE_REL_AMD64_ADDR32NB;
+ break;
+
+ case srRelocDir64Ptr:
+ // Emitted bytes: full address of target
+ // reloc src contains target pointer
+ pfixup->wType = IMAGE_REL_IA64_DIR64;
+ break;
+
+ case srRelocMapToken:
+ // Emitted bytes: contents of reloc source unchanged.
+ // reloc src contains token value
+ pfixup->wType = IMAGE_REL_AMD64_TOKEN;
+ break;
+#endif
+ case srRelocFilePos:
+ // Emitted bytes: offset relative to start of file, differs from RVA.
+ pfixup->wType = IMAGE_REL_I386_FILEPOS;
+ break;
+
+ case srRelocAbsoluteTagged:
+ pfixup->wType = IMAGE_REL_I386_DIR30NB;
+ pfixup->rvaTarget = (*pdw & ~0x80000001) >> 1;
+ break;
+
+ case srRelocHighAdj:
+ // Emitted bytes: 2 part relocation, with high part adjusted by constant.
+ pfixup->wType = IMAGE_REL_BASED_HIGHADJ;
+ break;
+
+ default:
+ _ASSERTE(!"Unknown relocation type");
+ return(E_UNEXPECTED);
+ break;
+ }
+ }
+
+ return(S_OK);
+
+} // HRESULT CeeFileGenWriter::UpdateFixups()
+
+
+HRESULT CeeFileGenWriter::setEmitFixups()
+{
+ m_fEmitFixups = true;
+ return(S_OK);
+
+} // HRESULT CeeFileGenWriter::setEmitFixups()
+
+#ifdef TEST_EMIT_FIXUPS
+
+HRESULT CeeFileGenWriter::TestEmitFixups()
+{
+ HRESULT hr;
+ // Test fixups
+
+ CeeSection * testSection;
+ hr = getSectionCreate(".test",
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
+ &testSection);
+ if (SUCCEEDED(hr))
+ {
+ struct FixupEntry
+ {
+ char sz[18];
+ DWORD wTargets[8];
+ };
+
+ struct FixupTypes
+ {
+ char * pszType;
+ CeeSectionRelocType relocType;
+ };
+
+ FixupTypes rgTypes[] =
+ {
+ { "srRelocAbsolute ", srRelocAbsolute },
+ { "srRelocAbsolutePtr", srRelocAbsolutePtr },
+ { "srRelocHighLow ", srRelocHighLow },
+ { "srRelocHighLowPtr ", srRelocHighLowPtr },
+ // { "srRelocRelative ", srRelocRelative },
+ // { "srRelocRelativePtr", srRelocRelativePtr },
+ { "srRelocMapToken ", srRelocMapToken },
+ // { "srRelocFilePos ", srRelocFilePos },
+ // { "srRelocHighAdj ", srRelocHighAdj },
+ };
+
+ const size_t cFixups = sizeof(rgTypes) / sizeof(rgTypes[0]);
+
+ DWORD * pdwTargets[20];
+
+ // Target Blocks:
+
+ for (size_t idx = 0; idx < cFixups; idx++)
+ {
+ hr = GetSectionBlock(testSection, sizeof(DWORD), 1, (void **) &pdwTargets[idx]);
+ _ASSERTE(SUCCEEDED(hr));
+
+ DWORD * pdw = pdwTargets[idx];
+ *pdw = idx;
+ }
+
+ for (size_t idxType = 0; idxType < cFixups; idxType++)
+ {
+ // Fixup Entries
+ FixupEntry * pEntry;
+ hr = GetSectionBlock(testSection, sizeof(FixupEntry), 1, (void **) &pEntry);
+ _ASSERTE(SUCCEEDED(hr));
+
+ memset(pEntry, 0, sizeof(FixupEntry));
+ strcpy_s(pEntry->sz, sizeof(pEntry->sz), rgTypes[idxType].pszType);
+
+ size_t ibBlock = testSection->computeOffset((char *) pEntry);
+
+ for (size_t idx = 0; idx < cFixups; idx++)
+ {
+ size_t ibFixup = ((size_t) &pEntry->wTargets[idx]) - (size_t) pEntry;
+
+ switch (rgTypes[idxType].relocType)
+ {
+ case srRelocAbsolute:
+ pEntry->wTargets[idx] = idx * sizeof(DWORD);
+ break;
+
+ case srRelocAbsolutePtr:
+ pEntry->wTargets[idx] = (DWORD) pdwTargets[idx];
+ break;
+
+ case srRelocHighLow:
+ pEntry->wTargets[idx] = idx * sizeof(DWORD);
+ break;
+
+ case srRelocHighLowPtr:
+ pEntry->wTargets[idx] = (DWORD) pdwTargets[idx];
+ break;
+
+ case srRelocRelative:
+ pEntry->wTargets[idx] = idx;
+ break;
+
+ case srRelocRelativePtr:
+ {
+ size_t ibTgt = (size_t) pdwTargets[idx];
+ size_t ibSrc = ((size_t) &pEntry->wTargets[idx]) + sizeof(DWORD);
+ pEntry->wTargets[idx] = (DWORD)( ibTgt - ibSrc );
+ ibFixup += sizeof(DWORD); // offset needs to point at end of DWORD
+ break;
+ }
+
+ case srRelocHighAdj:
+ pEntry->wTargets[idx] = idx * sizeof(DWORD);
+ break;
+
+ case srRelocMapToken:
+ pEntry->wTargets[idx] = idx * sizeof(DWORD);
+ break;
+
+ case srRelocFilePos:
+ pEntry->wTargets[idx] = idx * sizeof(DWORD);
+ break;
+ }
+
+ addFixup(*testSection, ibBlock + ibFixup, rgTypes[idxType].relocType, testSection);
+ testSection->addSectReloc(ibBlock + ibFixup, *testSection, rgTypes[idxType].relocType);
+ }
+ }
+ }
+
+ return(S_OK);
+}
+#endif // TEST_EMIT_FIXUPS
+#endif // EMIT_FIXUPS
+
+#ifndef FEATURE_MERGE_JIT_AND_ENGINE
+
+//*****************************************************************************
+// Handle lifetime of loaded library.
+//*****************************************************************************
+extern "C"
+BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ { // Save the module handle.
+ g_hThisInst = (HINSTANCE)hInstance;
+ DisableThreadLibraryCalls((HMODULE)hInstance);
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return (true);
+} // BOOL WINAPI DllMain()
+
+
+HINSTANCE GetModuleInst()
+{
+ return (g_hThisInst);
+} // HINSTANCE GetModuleInst()
+
+#endif //FEATURE_MERGE_JIT_AND_ENGINE
diff --git a/src/dlls/mscorpe/ceefilegenwritertokens.cpp b/src/dlls/mscorpe/ceefilegenwritertokens.cpp
new file mode 100644
index 0000000000..e2d448552d
--- /dev/null
+++ b/src/dlls/mscorpe/ceefilegenwritertokens.cpp
@@ -0,0 +1,266 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// CeeFileGenWriterTokens.cpp
+//
+// This code will walk the byte codes for all methods before they are saved
+// to disk and apply the token fix-ups if they have moved.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "ceegen.h"
+#ifndef FEATURE_CORECLR
+#define DECLARE_DATA
+#endif
+#include "../../ildasm/dasmenum.hpp"
+#define MAX_CLASSNAME_LENGTH 1024
+
+//********** Locals. **********************************************************
+OPCODE DecodeOpcode(const BYTE *pCode, DWORD *pdwLen);
+
+
+
+//********** Code. ************************************************************
+
+
+//*****************************************************************************
+// Method bodies are kept in the text section. The meta data contains the
+// RVA of each method body in the image. The TextSection object contains the
+// actual raw bytes where the method bodies are located. This code will
+// determine the raw offset of each method based on the RVA kept in the meta
+// data.
+//*****************************************************************************
+
+HRESULT CeeFileGenWriter::MapTokens(
+ CeeGenTokenMapper *pMapper,
+ IMetaDataImport *pImport)
+{
+ mdTypeDef td;
+ mdMethodDef md;
+ ULONG count;
+ ULONG MethodRVA;
+ ULONG codeOffset;
+ ULONG BaseRVA;
+ DWORD dwFlags;
+ DWORD iFlags;
+ HCORENUM hTypeDefs = 0, hEnum = 0;
+ WCHAR rcwName[MAX_CLASSNAME_LENGTH];
+ HRESULT hr;
+ CeeSection TextSection = getTextSection();
+
+ // Ask for the base RVA of the first method in the stream. All other
+ // method RVA's are >= that value, and will give us the raw offset required.
+
+ hr = getMethodRVA(0, &BaseRVA);
+ _ASSERTE(SUCCEEDED(hr));
+ // do globals first
+ while ((hr = pImport->EnumMethods(&hEnum, mdTokenNil, &md, 1, &count)) == S_OK)
+ {
+ hr = pImport->GetMethodProps(md, NULL,
+ rcwName, lengthof(rcwName), NULL,
+ &dwFlags, NULL, NULL,
+ &MethodRVA, &iFlags);
+ _ASSERTE(SUCCEEDED(hr));
+
+ if (MethodRVA == 0 || ((IsMdAbstract(dwFlags) || IsMiInternalCall(iFlags)) ||
+ (! IsMiIL(iFlags) && ! IsMiOPTIL(iFlags))))
+ continue;
+
+ // The raw offset of the method is the RVA in the image minus
+ // the first method in the text section.
+ codeOffset = MethodRVA - BaseRVA;
+ hr = MapTokensForMethod(pMapper,
+ (BYTE *) TextSection.computePointer(codeOffset),
+ rcwName);
+ if (FAILED(hr))
+ goto ErrExit;
+ }
+ if (hEnum) pImport->CloseEnum(hEnum);
+ hEnum = 0;
+
+ while ((hr = pImport->EnumTypeDefs(&hTypeDefs, &td, 1, &count)) == S_OK)
+ {
+ while ((hr = pImport->EnumMethods(&hEnum, td, &md, 1, &count)) == S_OK)
+ {
+ hr = pImport->GetMethodProps(md, NULL,
+ rcwName, lengthof(rcwName), NULL,
+ &dwFlags, NULL, NULL,
+ &MethodRVA, &iFlags);
+ _ASSERTE(SUCCEEDED(hr));
+
+ if (MethodRVA == 0 || ((IsMdAbstract(dwFlags) || IsMiInternalCall(iFlags)) ||
+ (! IsMiIL(iFlags) && ! IsMiOPTIL(iFlags))))
+ continue;
+
+
+ // The raw offset of the method is the RVA in the image minus
+ // the first method in the text section.
+ codeOffset = MethodRVA - BaseRVA;
+ hr = MapTokensForMethod(pMapper,
+ (BYTE *) TextSection.computePointer(codeOffset),
+ rcwName);
+ if (FAILED(hr))
+ goto ErrExit;
+ }
+
+ if (hEnum) pImport->CloseEnum(hEnum);
+ hEnum = 0;
+ }
+
+ErrExit:
+ if (hTypeDefs) pImport->CloseEnum(hTypeDefs);
+ if (hEnum) pImport->CloseEnum(hEnum);
+ return (hr);
+}
+
+
+//*****************************************************************************
+// This method will walk the byte codes of an IL method looking for tokens.
+// For each token found, it will check to see if it has been moved, and if
+// so, apply the new token value in its place.
+//*****************************************************************************
+HRESULT CeeFileGenWriter::MapTokensForMethod(
+ CeeGenTokenMapper *pMapper,
+ BYTE *pCode,
+ LPCWSTR szMethodName)
+{
+ mdToken tkTo;
+ DWORD PC;
+
+ COR_ILMETHOD_DECODER method((COR_ILMETHOD*) pCode);
+
+ // If compressed IL is being emitted, this routine will have no idea how to walk the tokens,
+ // so don't do it
+ if (m_dwMacroDefinitionSize != 0)
+ return S_OK;
+
+ pCode = const_cast<BYTE*>(method.Code);
+
+ PC = 0;
+ while (PC < method.GetCodeSize())
+ {
+ DWORD Len;
+ DWORD i;
+ OPCODE instr;
+
+ instr = DecodeOpcode(&pCode[PC], &Len);
+
+ if (instr == CEE_COUNT)
+ {
+ _ASSERTE(0 && "Instruction decoding error\n");
+ return E_FAIL;
+ }
+
+
+ PC += Len;
+
+ switch (OpcodeInfo[instr].Type)
+ {
+ DWORD tk;
+
+ default:
+ {
+ _ASSERTE(0 && "Unknown instruction\n");
+ return E_FAIL;
+ }
+
+ case InlineNone:
+ break;
+
+ case ShortInlineI:
+ case ShortInlineVar:
+ case ShortInlineBrTarget:
+ PC++;
+ break;
+
+ case InlineVar:
+ PC += 2;
+ break;
+
+ case InlineI:
+ case ShortInlineR:
+ case InlineBrTarget:
+ case InlineRVA:
+ PC += 4;
+ break;
+
+ case InlineI8:
+ case InlineR:
+ PC += 8;
+ break;
+
+ case InlinePhi:
+ {
+ DWORD cases = pCode[PC];
+ PC += 2 * cases + 1;
+ break;
+ }
+
+ case InlineSwitch:
+ {
+ DWORD cases = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24);
+
+ PC += 4;
+ for (i = 0; i < cases; i++)
+ {
+ PC += 4;
+ }
+
+ // skip bottom of loop which prints szString
+ continue;
+ }
+
+ case InlineTok:
+ case InlineSig:
+ case InlineMethod:
+ case InlineField:
+ case InlineType:
+ case InlineString:
+ {
+ tk = GET_UNALIGNED_VAL32(&pCode[PC]);
+
+ if (pMapper->HasTokenMoved(tk, tkTo))
+ {
+ SET_UNALIGNED_VAL32(&pCode[PC], tkTo);
+ }
+
+ PC += 4;
+ break;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+OPCODE DecodeOpcode(const BYTE *pCode, DWORD *pdwLen)
+{
+ OPCODE opcode;
+
+ *pdwLen = 1;
+ opcode = OPCODE(pCode[0]);
+ switch(opcode) {
+ case CEE_PREFIX1:
+ opcode = OPCODE(pCode[1] + 256);
+ if (opcode < 0 || opcode >= CEE_COUNT)
+ opcode = CEE_COUNT;
+ *pdwLen = 2;
+ break;
+ case CEE_PREFIXREF:
+ case CEE_PREFIX2:
+ case CEE_PREFIX3:
+ case CEE_PREFIX4:
+ case CEE_PREFIX5:
+ case CEE_PREFIX6:
+ case CEE_PREFIX7:
+ *pdwLen = 3;
+ return CEE_COUNT;
+ default:
+ break;
+ }
+ return opcode;
+}
diff --git a/src/dlls/mscorpe/dirs.proj b/src/dlls/mscorpe/dirs.proj
new file mode 100644
index 0000000000..46bb0ce64d
--- /dev/null
+++ b/src/dlls/mscorpe/dirs.proj
@@ -0,0 +1,15 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <!--The following projects will build during PHASE 1-->
+ <PropertyGroup>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildInPhase1>true</BuildInPhase1>
+ </PropertyGroup>
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="mscorpe\mscorpe.nativeproj" />
+ <ProjectFile Include="mscorpehost\mscorpehost.nativeproj" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/dlls/mscorpe/iceefilegen.cpp b/src/dlls/mscorpe/iceefilegen.cpp
new file mode 100644
index 0000000000..f4323b9e8c
--- /dev/null
+++ b/src/dlls/mscorpe/iceefilegen.cpp
@@ -0,0 +1,732 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: CEEGEN.CPP
+// ===========================================================================
+#include "stdafx.h"
+#include "iceefilegen.h"
+#include "ceefilegenwriter.h"
+
+#ifdef EnC_SUPPORTED
+#define ENC_DELTA_HACK
+#endif
+
+#ifdef ENC_DELTA_HACK
+extern BOOL g_EnCMode;
+#endif
+
+// Deprecated
+//****************************************************************************
+ HRESULT ICeeFileGen::EmitMethod ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::EmitSignature ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::SetEntryClassToken ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::GetEntryClassToken ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::SetEntryPointDescr ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::GetEntryPointDescr ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::SetEntryPointFlags ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::GetEntryPointFlags ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::CreateSig ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::AddSigArg ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::SetSigReturnType ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::SetSigCallingConvention ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+ HRESULT ICeeFileGen::DeleteSig ()
+ {
+ _ASSERTE("Deprecated" && 0);
+ return (E_FAIL);
+ }
+//****************************************************************************
+
+EXTERN_C HRESULT __stdcall CreateICeeFileGen(ICeeFileGen** pCeeFileGen)
+{
+ if (!pCeeFileGen)
+ return E_POINTER;
+
+ ICeeFileGen *gen = new (nothrow) ICeeFileGen();
+ IfNullRet(gen);
+
+ *pCeeFileGen = gen;
+ return S_OK;
+}
+
+EXTERN_C HRESULT __stdcall DestroyICeeFileGen(ICeeFileGen** pCeeFileGen)
+{
+ if (!pCeeFileGen)
+ return E_POINTER;
+ delete *pCeeFileGen;
+ *pCeeFileGen = NULL;
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::CreateCeeFile (HCEEFILE *ceeFile)
+{
+ return CreateCeeFileEx(ceeFile, ICEE_CREATE_FILE_PURE_IL);
+}
+
+HRESULT ICeeFileGen::CreateCeeFileEx (HCEEFILE *ceeFile, DWORD createFlags)
+{
+ return CreateCeeFileEx2(ceeFile, createFlags, NULL);
+}
+
+//
+// Seed file is used as the base file. The new file data will be "appended" to the seed file
+//
+
+HRESULT ICeeFileGen::CreateCeeFileEx2 (HCEEFILE *ceeFile, DWORD createFlags, LPCWSTR seedFileName)
+{
+ if (!ceeFile)
+ return E_POINTER;
+
+ CeeFileGenWriter *gen = NULL;
+ HRESULT hr;
+ IfFailRet(CeeFileGenWriter::CreateNewInstanceEx(NULL, gen, createFlags, seedFileName));
+ TESTANDRETURN(gen != NULL, E_OUTOFMEMORY);
+ *ceeFile = gen;
+
+#ifdef ENC_DELTA_HACK
+ // for EnC we want the RVA to be right be relative to the front of the delta IL stream rather
+ // than take into account the .text section and the cor header as we would for a real PE file
+ // However, the RVA must be non-zero, so just stick a dword on the front to push it out.
+ if (g_EnCMode)
+ {
+ CeeSection *sec = &gen->getIlSection();
+ sec->getBlock(sizeof(DWORD), sizeof(DWORD));
+ }
+#endif
+
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::CreateCeeFileFromICeeGen(ICeeGen *pICeeGen, HCEEFILE *ceeFile, DWORD createFlags)
+{
+ if (!ceeFile)
+ return E_POINTER;
+ CCeeGen *genFrom = reinterpret_cast<CCeeGen*>(pICeeGen);
+ CeeFileGenWriter *gen = NULL;
+ if (FAILED(CeeFileGenWriter::CreateNewInstance(genFrom, gen, createFlags))) return FALSE;
+ TESTANDRETURN(gen != NULL, E_OUTOFMEMORY);
+ *ceeFile = gen;
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::DestroyCeeFile(HCEEFILE *ceeFile)
+{
+ if (!ceeFile)
+ return E_POINTER;
+ if (!*ceeFile)
+ return E_POINTER;
+
+ CeeFileGenWriter **gen = reinterpret_cast<CeeFileGenWriter**>(ceeFile);
+ (*gen)->Cleanup();
+ delete *gen;
+ *ceeFile = NULL;
+ return S_OK;
+}
+
+//
+
+HRESULT ICeeFileGen::GetRdataSection (HCEEFILE ceeFile, HCEESECTION *section)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNARG(ceeFile != 0);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ *section = &gen->getStringSection();
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::GetIlSection (HCEEFILE ceeFile, HCEESECTION *section)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNARG(ceeFile != 0);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ *section = &gen->getIlSection();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::GetSectionCreate (HCEEFILE ceeFile, const char *name, DWORD flags,
+ HCEESECTION *section)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNARG(ceeFile != 0);
+ TESTANDRETURNPOINTER(name);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ CeeSection **ceeSection = reinterpret_cast<CeeSection**>(section);
+
+ HRESULT hr = gen->getSectionCreate(name, flags, ceeSection);
+
+ return hr;
+}
+
+HRESULT ICeeFileGen::SetDirectoryEntry(HCEEFILE ceeFile, HCEESECTION section, ULONG num, ULONG size, ULONG offset)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(section);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ CeeSection &sec = *(reinterpret_cast<CeeSection*>(section));
+ return(gen->setDirectoryEntry(sec, num, size, offset));
+}
+
+HRESULT ICeeFileGen::GetSectionDataLen (HCEESECTION section, ULONG *dataLen)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNPOINTER(dataLen);
+
+ CeeSection *sec = reinterpret_cast<CeeSection*>(section);
+ *dataLen = sec->dataLen();
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::GetSectionRVA (HCEESECTION section, ULONG *rva)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNPOINTER(rva);
+
+ CeeSection *sec = reinterpret_cast<CeeSection*>(section);
+ *rva = sec->getBaseRVA();
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::GetSectionBlock (HCEESECTION section, ULONG len,
+ ULONG align, void **ppBytes)
+{
+ TESTANDRETURNPOINTER(section);
+ TESTANDRETURNPOINTER(ppBytes);
+
+ CeeSection *sec = reinterpret_cast<CeeSection*>(section);
+ void *bytes = sec->getBlock(len, align);
+ TESTANDRETURN(bytes != NULL, E_OUTOFMEMORY);
+ *ppBytes = bytes;
+
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::TruncateSection (HCEESECTION section, ULONG len)
+{
+ _ASSERTE(!"This is an obsolete function!");
+ return E_NOTIMPL;
+}
+
+HRESULT ICeeFileGen::AddSectionReloc (HCEESECTION section, ULONG offset, HCEESECTION relativeTo, CeeSectionRelocType relocType)
+{
+ TESTANDRETURNPOINTER(section);
+
+ CeeSection *sec = reinterpret_cast<CeeSection*>(section);
+ CeeSection *relSec = reinterpret_cast<CeeSection*>(relativeTo);
+
+ if (relSec)
+ {
+#ifdef EMIT_FIXUPS
+ CeeFileGenWriter * gen = reinterpret_cast<CeeFileGenWriter*>(&sec->ceeFile());
+ HRESULT hr = gen->addFixup(*sec, offset, relocType, relSec);
+ if (FAILED(hr))
+ {
+ return(hr);
+ }
+#endif
+ return(sec->addSectReloc(offset, *relSec, relocType));
+ }
+ else
+ {
+#ifdef EMIT_FIXUPS
+ CeeFileGenWriter * gen = reinterpret_cast<CeeFileGenWriter*>(&sec->ceeFile());
+ HRESULT hr = gen->addFixup(*sec, offset, relocType);
+ if (FAILED(hr))
+ {
+ return(hr);
+ }
+#endif
+ return(sec->addBaseReloc(offset, relocType));
+ }
+}
+
+HRESULT ICeeFileGen::SetSectionDirectoryEntry(HCEESECTION section, ULONG num)
+{
+ TESTANDRETURNPOINTER(section);
+
+ printf("Warning: deprecated method. Use SetDirectoryEntry instead\n");
+ CeeSection *sec = reinterpret_cast<CeeSection*>(section);
+ return(sec->directoryEntry(num));
+}
+
+HRESULT ICeeFileGen::SetOutputFileName (HCEEFILE ceeFile, __in LPWSTR outputFileName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(outputFileName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setOutputFileName(outputFileName));
+}
+
+__success(return == S_OK) HRESULT ICeeFileGen::GetOutputFileName (HCEEFILE ceeFile, __out LPWSTR *outputFileName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(outputFileName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(outputFileName);
+ *outputFileName = gen->getOutputFileName();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::SetResourceFileName (HCEEFILE ceeFile, __in LPWSTR resourceFileName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(resourceFileName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setResourceFileName(resourceFileName));
+}
+
+__success(return == S_OK)
+HRESULT ICeeFileGen::GetResourceFileName (HCEEFILE ceeFile, __out LPWSTR *resourceFileName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(resourceFileName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(resourceFileName);
+ *resourceFileName = gen->getResourceFileName();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::SetImageBase(HCEEFILE ceeFile, size_t imageBase)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->setImageBase(imageBase);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::SetImageBase64(HCEEFILE ceeFile, ULONGLONG imageBase)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->setImageBase64(imageBase);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::SetFileAlignment(HCEEFILE ceeFile, ULONG fileAlignment)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->setFileAlignment(fileAlignment);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::SetSubsystem(HCEEFILE ceeFile, DWORD subsystem, DWORD major, DWORD minor)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->setSubsystem(subsystem, major, minor);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::GetIMapTokenIface(HCEEFILE ceeFile, IMetaDataEmit *emitter, IUnknown **pIMapToken)
+{
+ _ASSERTE(!"This is an obsolete function!");
+ return E_NOTIMPL;
+}
+
+HRESULT ICeeFileGen::EmitMetaData (HCEEFILE ceeFile, IMetaDataEmit *emitter,
+ mdScope scopeE)
+{
+ _ASSERTE(!"This is an obsolete function!");
+ return E_NOTIMPL;
+}
+
+HRESULT ICeeFileGen::EmitLibraryName (HCEEFILE ceeFile, IMetaDataEmit *emitter,
+ mdScope scopeE)
+{
+ _ASSERTE(!"This is an obsolete function!");
+ return E_NOTIMPL;
+}
+
+HRESULT ICeeFileGen::GetMethodRVA(HCEEFILE ceeFile, ULONG codeOffset, ULONG *codeRVA)
+{
+ TESTANDRETURNARG(ceeFile != 0);
+ TESTANDRETURNPOINTER(codeRVA);
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->getMethodRVA(codeOffset, codeRVA);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::EmitString(HCEEFILE ceeFile, __in LPWSTR strValue, ULONG *strRef)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->getStringSection().getEmittedStringRef(strValue, strRef));
+}
+
+HRESULT ICeeFileGen::LinkCeeFile (HCEEFILE ceeFile)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->link();
+}
+
+HRESULT ICeeFileGen::FixupCeeFile (HCEEFILE ceeFile)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->fixup();
+}
+
+HRESULT ICeeFileGen::GetHeaderInfo (HCEEFILE ceeFile, PIMAGE_NT_HEADERS *ppNtHeaders, PIMAGE_SECTION_HEADER *ppSections, ULONG *pNumSections)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ gen->getPEWriter().getHeaderInfo(ppNtHeaders, ppSections, pNumSections);
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::GenerateCeeFile (HCEEFILE ceeFile)
+{
+ SO_NOT_MAINLINE_FUNCTION;
+
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->generateImage(NULL); // NULL means don't write in-memory buffer, uses outputFileName
+}
+
+// GenerateCeeMemoryImage - returns in ppImage an in-memory PE image allocated by CoTaskMemAlloc()
+// the caller is responsible for calling CoTaskMemFree on this memory image
+HRESULT ICeeFileGen::GenerateCeeMemoryImage (HCEEFILE ceeFile, void **ppImage)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(ppImage);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->generateImage(ppImage);
+}
+
+HRESULT ICeeFileGen::SetEntryPoint(HCEEFILE ceeFile, mdMethodDef method)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setEntryPoint(method);
+}
+
+HRESULT ICeeFileGen::GetEntryPoint(HCEEFILE ceeFile, mdMethodDef *method)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(method);
+ *method = gen->getEntryPoint();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::SetComImageFlags (HCEEFILE ceeFile, DWORD mask)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setComImageFlags(mask);
+}
+
+HRESULT ICeeFileGen::ClearComImageFlags (HCEEFILE ceeFile, DWORD mask)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->clearComImageFlags(mask);
+}
+
+HRESULT ICeeFileGen::GetComImageFlags (HCEEFILE ceeFile, DWORD *mask)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(mask);
+ *mask = gen->getComImageFlags();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::SetDllSwitch (HCEEFILE ceeFile, BOOL dllSwitch)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setDllSwitch(dllSwitch==TRUE));
+}
+
+HRESULT ICeeFileGen::GetDllSwitch (HCEEFILE ceeFile, BOOL *dllSwitch)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(dllSwitch);
+ *dllSwitch = gen->getDllSwitch();
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::SetObjSwitch (HCEEFILE ceeFile, BOOL objSwitch)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setObjSwitch(objSwitch==TRUE));
+}
+
+HRESULT ICeeFileGen::GetObjSwitch (HCEEFILE ceeFile, BOOL *objSwitch)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ TESTANDRETURNPOINTER(objSwitch);
+ *objSwitch = gen->getObjSwitch();
+ return S_OK;
+}
+
+
+HRESULT ICeeFileGen::SetLibraryName (HCEEFILE ceeFile, __in LPWSTR LibraryName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(LibraryName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setLibraryName(LibraryName));
+}
+
+HRESULT ICeeFileGen::SetLibraryGuid (HCEEFILE ceeFile, __in LPWSTR LibraryGuid)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(LibraryGuid);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->setLibraryGuid(LibraryGuid));
+}
+
+__success(return == S_OK) HRESULT ICeeFileGen::GetLibraryName (HCEEFILE ceeFile, __out LPWSTR *LibraryName)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(LibraryName);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ *LibraryName = gen->getLibraryName();
+ return S_OK;
+}
+
+
+
+HRESULT ICeeFileGen::EmitMetaDataEx (HCEEFILE ceeFile, IMetaDataEmit *emitter)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(emitter);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->emitMetaData(emitter));
+}
+
+HRESULT ICeeFileGen::EmitMetaDataAt (HCEEFILE ceeFile, IMetaDataEmit *emitter, HCEESECTION section, DWORD offset, BYTE* buffer, unsigned buffLen)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(emitter);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ CeeSection* sec = reinterpret_cast<CeeSection*>(section);
+
+ return(gen->emitMetaData(emitter, sec, offset, buffer, buffLen));
+}
+
+HRESULT ICeeFileGen::EmitLibraryNameEx (HCEEFILE ceeFile, IMetaDataEmit *emitter)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(emitter);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->emitLibraryName(emitter));
+}
+
+HRESULT ICeeFileGen::GetIMapTokenIfaceEx(HCEEFILE ceeFile, IMetaDataEmit *emitter, IUnknown **pIMapToken)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(pIMapToken);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->getMapTokenIface(pIMapToken);
+}
+
+HRESULT ICeeFileGen::AddNotificationHandler(HCEEFILE ceeFile,
+ IUnknown *pHandler)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(pHandler);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->addNotificationHandler(pHandler);
+}
+
+HRESULT ICeeFileGen::EmitMacroDefinitions(HCEEFILE ceeFile, void *pData, DWORD cData)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->EmitMacroDefinitions(pData, cData);
+}
+
+HRESULT ICeeFileGen::SetManifestEntry(HCEEFILE ceeFile, ULONG size, ULONG offset)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setManifestEntry(size, offset);
+}
+
+HRESULT ICeeFileGen::SetStrongNameEntry(HCEEFILE ceeFile, ULONG size, ULONG offset)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setStrongNameEntry(size, offset);
+}
+
+HRESULT ICeeFileGen::ComputeSectionOffset(HCEESECTION section, __in char *ptr,
+ unsigned *offset)
+{
+ TESTANDRETURNPOINTER(section);
+
+ CeeSection &sec = *(reinterpret_cast<CeeSection*>(section));
+
+ *offset = sec.computeOffset(ptr);
+
+ return S_OK;
+}
+
+__success(return == S_OK)
+HRESULT ICeeFileGen::ComputeSectionPointer(HCEESECTION section, ULONG offset,
+ __out char **ptr)
+{
+ TESTANDRETURNPOINTER(section);
+
+ CeeSection &sec = *(reinterpret_cast<CeeSection*>(section));
+
+ *ptr = sec.computePointer(offset);
+
+ return S_OK;
+}
+
+HRESULT ICeeFileGen::ComputeOffset(HCEEFILE ceeFile, __in char *ptr,
+ HCEESECTION *pSection, unsigned *offset)
+{
+ TESTANDRETURNPOINTER(pSection);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+
+ CeeSection *section;
+
+ HRESULT hr = gen->computeOffset(ptr, &section, offset);
+
+ if (SUCCEEDED(hr))
+ *pSection = reinterpret_cast<HCEESECTION>(section);
+
+ return hr;
+}
+
+HRESULT ICeeFileGen::SetEnCRVABase(HCEEFILE ceeFile, ULONG dataBase, ULONG rdataBase)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setEnCRvaBase(dataBase, rdataBase);
+}
+
+HRESULT ICeeFileGen::GetCorHeader(HCEEFILE ceeFile,
+ IMAGE_COR20_HEADER **header)
+{
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->getCorHeader(header);
+}
+
+HRESULT ICeeFileGen::SetVTableEntry(HCEEFILE ceeFile, ULONG size, ULONG offset)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setVTableEntry(size, offset);
+}
+
+HRESULT ICeeFileGen::SetVTableEntry64(HCEEFILE ceeFile, ULONG size, void* ptr)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return gen->setVTableEntry64(size, ptr);
+}
+
+HRESULT ICeeFileGen::GetFileTimeStamp (HCEEFILE ceeFile, DWORD *pTimeStamp)
+{
+ TESTANDRETURNPOINTER(ceeFile);
+ TESTANDRETURNPOINTER(pTimeStamp);
+
+ CeeFileGenWriter *gen = reinterpret_cast<CeeFileGenWriter*>(ceeFile);
+ return(gen->getFileTimeStamp(pTimeStamp));
+}
+
diff --git a/src/dlls/mscorpe/mscorpe/mscorpe.def b/src/dlls/mscorpe/mscorpe/mscorpe.def
new file mode 100644
index 0000000000..875abc42a7
--- /dev/null
+++ b/src/dlls/mscorpe/mscorpe/mscorpe.def
@@ -0,0 +1,11 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+;
+; mscorpe.def for mscorpe.dll (a simple wrapper around real implementation mscorpehost.dll - see
+; file:wrapper.cpp for more details)
+; PE file generator in EE
+
+EXPORTS
+ CreateICeeFileGen
+ DestroyICeeFileGen
diff --git a/src/dlls/mscorpe/mscorpe/mscorpe.nativeproj b/src/dlls/mscorpe/mscorpe/mscorpe.nativeproj
new file mode 100644
index 0000000000..526cf6088b
--- /dev/null
+++ b/src/dlls/mscorpe/mscorpe/mscorpe.nativeproj
@@ -0,0 +1,46 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <NoCrt>true</NoCrt>
+ <LinkUseCMT>true</LinkUseCMT>
+ <UserIncludes>
+ $(UserIncludes);
+ .
+ </UserIncludes>
+ <CDefines>$(CDefines);__TODO_PORT_TO_WRAPPERS__;UNICODE</CDefines>
+ <OutputName>mscorpe</OutputName>
+ <FileToMarkForSigning>$(BinariesDirectory)\$(OutputName).dll</FileToMarkForSigning>
+ <OutputLibPath>$(IntermediateOutputDirectory)</OutputLibPath>
+ <DllDef>$(OutputName).def</DllDef>
+ <TargetType>DYNLINK</TargetType>
+ <LinkSubsystem>windows</LinkSubsystem>
+ <PogoOptimized>true</PogoOptimized>
+ <DllEntryPoint>_DllMainCRTStartup</DllEntryPoint>
+ <Win32DllLibs>$(ClrLibPath)\utilcodestaticnohost.lib</Win32DllLibs>
+ <UseMsvcrt>false</UseMsvcrt>
+ <NoLinkGdi32>true</NoLinkGdi32>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <TargetLib Include="$(SdkLibPath)\mscoree.lib" />
+ <TargetLib Include="$(SdkLibPath)\oleaut32.lib" />
+ <TargetLib Include="$(SdkLibPath)\uuid.lib" />
+ <TargetLib Include="$(SdkLibPath)\kernel32.lib" />
+ <TargetLib Include="$(SdkLibPath)\advapi32.lib" />
+ <TargetLib Include="$(SdkLibPath)\user32.lib" />
+ <TargetLib Include="$(SdkLibPath)\shlwapi.lib" />
+ <ProjectReference Include="$(ClrSrcDirectory)utilcode\staticnohost\staticnohost.nativeproj"/>
+ </ItemGroup>
+
+ <ItemGroup>
+ <RCResourceFile Include="..\Native.rc" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <CppCompile Include="wrapper.cpp" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/dlls/mscorpe/mscorpe/wrapper.cpp b/src/dlls/mscorpe/mscorpe/wrapper.cpp
new file mode 100644
index 0000000000..d2f1701ec4
--- /dev/null
+++ b/src/dlls/mscorpe/mscorpe/wrapper.cpp
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: wrapper.cpp
+//
+
+//
+// This file implements a simple wrapper DLL (mscorpe.dll) which calls properly into mscorpehost.dll.
+// It exists because of compatibility with 1.x/2.0 apps running on CLR 4.0+. Such older apps could pass
+// full path to LoadLibrary() Windows API and get this DLL.
+//
+// Noone in CLR should ever try to load this DLL directly (using LoadLibrary API). Note that hosting APIs
+// and PInvoke redirect mscorpe.dll to mscorpehost.dll automatically.
+//
+
+#include <MscorpeSxSWrapper.h>
+
+#include <mscoree.h>
+#include <metahost.h>
+
+// Globals
+HINSTANCE g_hThisInst; // This library.
+
+//*****************************************************************************
+// Handle lifetime of loaded library.
+//*****************************************************************************
+extern "C"
+BOOL WINAPI
+DllMain(
+ HINSTANCE hInstance,
+ DWORD dwReason,
+ LPVOID lpReserved)
+{
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ { // Save the module handle.
+ g_hThisInst = hInstance;
+ DisableThreadLibraryCalls((HMODULE)hInstance);
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return TRUE;
+} // DllMain
+
+// Implementation for utilcode
+HINSTANCE
+GetModuleInst()
+{
+ return g_hThisInst;
+} // GetModuleInst
+
+// Load correct SxS version of mscorpe.dll and initialize it (uses shim).
+HRESULT
+LoadMscorpe(HMODULE * phModule)
+{
+ HRESULT hr = S_OK;
+ ICLRMetaHost * pMetaHost = NULL;
+ ICLRRuntimeInfo * pCLRRuntimeInfo = NULL;
+
+ // Get full DLL path
+ WCHAR wszPath[_MAX_PATH];
+ DWORD dwLength = GetModuleFileName((HMODULE)g_hThisInst, wszPath, NumItems(wszPath));
+
+ if ((dwLength == 0) ||
+ ((dwLength == NumItems(wszPath)) &&
+ (GetLastError() == ERROR_INSUFFICIENT_BUFFER)))
+ {
+ IfFailGo(CLR_E_SHIM_RUNTIMELOAD);
+ }
+
+ // Find start of '\mscorpe.dll'
+ LPWSTR wszSeparator = wcsrchr(wszPath, L'\\');
+ if (wszSeparator == NULL)
+ {
+ IfFailGo(CLR_E_SHIM_RUNTIMELOAD);
+ }
+ // Check the name of this DLL
+ _ASSERTE(_wcsicmp(wszSeparator, L"\\mscorpe.dll") == 0);
+ // Remove the DLL name
+ *wszSeparator = 0;
+
+ // Find start of last directory name (\<version>),
+ // C:\Windows\Microsoft.NET\Framework\[[v4.0.12345]]\mscorpe.dll
+ LPWSTR wszLastDirectoryName = wcsrchr(wszPath, L'\\');
+ if (wszLastDirectoryName == NULL)
+ {
+ IfFailGo(CLR_E_SHIM_RUNTIMELOAD);
+ }
+ LPWSTR wszVersion = wszLastDirectoryName + 1;
+
+ IfFailGo(CLRCreateInstance(
+ CLSID_CLRMetaHost,
+ IID_ICLRMetaHost,
+ reinterpret_cast<LPVOID *>(&pMetaHost)));
+
+ IfFailGo(pMetaHost->GetRuntime(
+ wszVersion,
+ IID_ICLRRuntimeInfo,
+ reinterpret_cast<LPVOID *>(&pCLRRuntimeInfo)));
+
+ // Shim will load correct SxS version of mscorpe.dll and will initialize it
+ IfFailGo(pCLRRuntimeInfo->LoadLibrary(
+ L"mscorpe.dll",
+ phModule));
+
+ErrExit:
+ if (pMetaHost != NULL)
+ {
+ pMetaHost->Release();
+ pMetaHost = NULL;
+ }
+ if (pCLRRuntimeInfo != NULL)
+ {
+ pCLRRuntimeInfo->Release();
+ pCLRRuntimeInfo = NULL;
+ }
+
+ if (FAILED(hr))
+ {
+ *phModule = NULL;
+ }
+
+ return hr;
+} // LoadMscorpe
+
+// SxS wrapper of mscorpe.dll entrypoints
+typedef MscorpeSxSWrapper<LoadMscorpe> MscorpeSxS;
+
+// Export of 'original' 1.x/2.0 mscorpe.dll
+EXTERN_C
+HRESULT __stdcall
+CreateICeeFileGen(
+ ICeeFileGen ** ppCeeFileGen)
+{
+ return MscorpeSxS::CreateICeeFileGen(ppCeeFileGen);
+}
+
+// Export of 'original' 1.x/2.0 mscorpe.dll
+EXTERN_C
+HRESULT __stdcall
+DestroyICeeFileGen(ICeeFileGen ** ppCeeFileGen)
+{
+ return MscorpeSxS::DestroyICeeFileGen(ppCeeFileGen);
+}
diff --git a/src/dlls/mscorpe/mscorpehost/mscorpehost.def b/src/dlls/mscorpe/mscorpehost/mscorpehost.def
new file mode 100644
index 0000000000..0cf870b17b
--- /dev/null
+++ b/src/dlls/mscorpe/mscorpehost/mscorpehost.def
@@ -0,0 +1,12 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+;
+; PeWriter.def for PeWriter.dll
+; PE file generator in EE
+
+EXPORTS
+ CreateICeeFileGen
+ DestroyICeeFileGen
+ InitializeSxS
+
diff --git a/src/dlls/mscorpe/mscorpehost/mscorpehost.nativeproj b/src/dlls/mscorpe/mscorpehost/mscorpehost.nativeproj
new file mode 100644
index 0000000000..45af39f38b
--- /dev/null
+++ b/src/dlls/mscorpe/mscorpehost/mscorpehost.nativeproj
@@ -0,0 +1,68 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <LibCLib>$(ClrCrtLib)</LibCLib>
+ <OutputName>mscorpehost</OutputName>
+ <FileToMarkForSigning>$(BinariesDirectory)\$(OutputName).dll</FileToMarkForSigning>
+ <OutputLibPath>$(IntermediateOutputDirectory)</OutputLibPath>
+ <DllDef>$(OutputName).def</DllDef>
+ <TargetType>DYNLINK</TargetType>
+ <PCHHeader>stdafx.h</PCHHeader>
+ <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders>
+ <PCHCompile>..\stdafx.cpp</PCHCompile>
+ <UserIncludes>
+ $(UserIncludes);
+ .;
+ ../../vm
+ </UserIncludes>
+ <CDefines>$(CDefines);__TODO_PORT_TO_WRAPPERS__;UNICODE</CDefines>
+ <LinkSubsystem>windows</LinkSubsystem>
+ <PogoOptimized>true</PogoOptimized>
+ <DllEntryPoint>_DllMainCRTStartup</DllEntryPoint>
+ <ExtDelayImpLib>false</ExtDelayImpLib>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <LinkDelayLoad Condition="'$(LinkDelayLoad)'!=''">$(LinkDelayLoad);</LinkDelayLoad>
+ <LinkDelayLoad>$(LinkDelayLoad)ole32.dll</LinkDelayLoad>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CppCompile Include="..\utilcodeinit.cpp" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <LinkPreCrtLibs Include="$(ClrLibPath)\utilcode.lib">
+ <ProjectReference>$(ClrSrcDirectory)utilcode\dyncrt\dyncrt.nativeproj</ProjectReference>
+ </LinkPreCrtLibs>
+
+ <TargetLib Include="$(SdkLibPath)\mscoree.lib" />
+ <TargetLib Include="$(ClrLibPath)\ceefgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\ceefilegen\ceefgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\delayimp.lib">
+ <ProjectReference>$(ClrSrcDirectory)delayimp\delayimp.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Include="$(SdkLibPath)\oleaut32.lib" />
+ <TargetLib Include="$(SdkLibPath)\uuid.lib" />
+ <TargetLib Include="$(SdkLibPath)\kernel32.lib" />
+ <TargetLib Include="$(SdkLibPath)\advapi32.lib" />
+ <TargetLib Include="$(SdkLibPath)\user32.lib" />
+ <TargetLib Include="$(SdkLibPath)\shlwapi.lib" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <RCResourceFile Include="..\Native.rc" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <CppCompile Include="..\ICeeFileGen.cpp" />
+ <CppCompile Include="..\CeeFileGenWriter.cpp" />
+ <CppCompile Include="..\PEWriter.cpp" />
+ <CppCompile Include="..\CeeFileGenWriterTokens.cpp" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/dlls/mscorpe/pewriter.cpp b/src/dlls/mscorpe/pewriter.cpp
new file mode 100644
index 0000000000..f3b5fb194d
--- /dev/null
+++ b/src/dlls/mscorpe/pewriter.cpp
@@ -0,0 +1,2401 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include "stdafx.h"
+
+#include "blobfetcher.h"
+#include "pedecoder.h"
+
+#ifdef _DEBUG
+#define LOGGING
+#endif
+
+#ifdef LOGGING
+#include "log.h"
+
+static const char* const RelocName[] = {
+ "Absolute", "Unk1", "Unk2", "HighLow", "Unk4", "MapToken",
+ "Relative", "FilePos", "CodeRel", "Movl64", "Dir64", "PcRel25", "PcRel64",
+ "AbsTag" };
+static const char RelocSpaces[] = " ";
+
+static INT64 s_minPcRel25;
+static INT64 s_maxPcRel25;
+#endif
+
+#ifdef EnC_SUPPORTED
+#define ENC_DELTA_HACK
+#endif
+
+ /* This is the stub program that says it can't be run in DOS mode */
+ /* it is x86 specific, but so is dos so I suppose that is OK */
+static const unsigned char x86StubPgm[] = {
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ /* number of pad bytes to make 'len' bytes align to 'align' */
+inline static unsigned roundUp(unsigned len, unsigned align) {
+ return((len + align-1) & ~(align-1));
+}
+
+inline static unsigned padLen(unsigned len, unsigned align) {
+ return(roundUp(len, align) - len);
+}
+
+inline static bool isExeOrDll(IMAGE_NT_HEADERS* ntHeaders) {
+ return ((ntHeaders->FileHeader.Characteristics & VAL16(IMAGE_FILE_EXECUTABLE_IMAGE)) != 0);
+}
+
+#ifndef IMAGE_DLLCHARACTERISTICS_NO_SEH
+#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x400
+#endif
+
+#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
+#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
+#endif
+
+#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
+#endif
+
+#define COPY_AND_ADVANCE(target, src, size) { \
+ ::memcpy((void *) (target), (const void *) (src), (size)); \
+ (char *&) (target) += (size); }
+
+/******************************************************************/
+int __cdecl relocCmp(const void* a_, const void* b_) {
+
+ const PESectionReloc* a = (const PESectionReloc*) a_;
+ const PESectionReloc* b = (const PESectionReloc*) b_;
+ return (a->offset > b->offset ? 1 : (a->offset == b->offset ? 0 : -1));
+}
+
+PERelocSection::PERelocSection(PEWriterSection *pBaseReloc)
+{
+ section = pBaseReloc;
+ relocPage = (unsigned) -1;
+ relocSize = 0;
+ relocSizeAddr = NULL;
+ pages = 0;
+
+#ifdef _DEBUG
+ lastRVA = 0;
+#endif
+}
+
+void PERelocSection::AddBaseReloc(unsigned rva, int type, unsigned short highAdj)
+{
+#ifdef _DEBUG
+ // Guarantee that we're adding relocs in strict increasing order.
+ _ASSERTE(rva > lastRVA);
+ lastRVA = rva;
+#endif
+
+ if (relocPage != (rva & ~0xFFF)) {
+ if (relocSizeAddr) {
+ if ((relocSize & 1) == 1) { // pad to an even number
+ short *ps = (short*) section->getBlock(2);
+ if(ps) {
+ *ps = 0;
+ relocSize++;
+ }
+ }
+ *relocSizeAddr = VAL32(relocSize*2 + sizeof(IMAGE_BASE_RELOCATION));
+ }
+ IMAGE_BASE_RELOCATION* base = (IMAGE_BASE_RELOCATION*) section->getBlock(sizeof(IMAGE_BASE_RELOCATION));
+ if(base) {
+ relocPage = (rva & ~0xFFF);
+ relocSize = 0;
+ base->VirtualAddress = VAL32(relocPage);
+ // Size needs to be fixed up when we know it - save address here
+ relocSizeAddr = &base->SizeOfBlock;
+ pages++;
+ }
+ }
+
+ relocSize++;
+ unsigned short* offset = (unsigned short*) section->getBlock(2);
+ if(offset) {
+ *offset = VAL16((rva & 0xFFF) | (type << 12));
+ }
+}
+
+void PERelocSection::Finish(bool isPE32)
+{
+ // fixup the last reloc block (if there was one)
+ if (relocSizeAddr) {
+ if ((relocSize & 1) == 1) { // pad to an even number
+ short* psh = (short*) section->getBlock(2);
+ if(psh)
+ {
+ *psh = 0;
+ relocSize++;
+ }
+ }
+ *relocSizeAddr = VAL32(relocSize*2 + sizeof(IMAGE_BASE_RELOCATION));
+ }
+}
+
+#define GET_UNALIGNED_INT32(_ptr) ((INT32) GET_UNALIGNED_VAL32(_ptr))
+
+static inline HRESULT SignedFitsIn31Bits(INT64 immediate)
+{
+ INT64 hiBits = immediate >> 31;
+ if ((hiBits == 0) || (hiBits == -1))
+ {
+ return S_OK;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+}
+
+static inline HRESULT UnsignedFitsIn32Bits(UINT64 immediate)
+{
+ UINT64 hiBits = immediate >> 32;
+ if (hiBits == 0)
+ {
+ return S_OK;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+}
+
+static inline HRESULT AddOvf_RVA(DWORD& a, DWORD b)
+{
+ DWORD r = a + b;
+ if (r < a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT AddOvf_S_U32(INT64 & a, unsigned int b)
+{
+ INT64 r = a + b;
+ if (r < a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT AddOvf_S_S32(INT64 & a, int b)
+{
+ INT64 r = a + b;
+ if ( ((r >= a) && (b >= 0)) ||
+ ((r < a) && (b < 0)) )
+ {
+ a = r;
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+static inline HRESULT AddOvf_U_U32(UINT64 & a, unsigned int b)
+{
+ UINT64 r = a + b;
+ if (r < a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT AddOvf_U_U(UINT64 & a, UINT64 b)
+{
+ UINT64 r = a + b;
+ if (r < a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT SubOvf_S_U32(INT64 & a, unsigned int b)
+{
+ INT64 r = a - b;
+ if (r > a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT SubOvf_S_U(INT64 & a, UINT64 b)
+{
+ INT64 r = a - b;
+ if (r > a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+static inline HRESULT SubOvf_U_U32(UINT64 & a, unsigned int b)
+{
+ UINT64 r = a - b;
+ if (r > a) // Check for overflow
+ return E_FAIL;
+ a = r;
+ return S_OK;
+}
+
+#ifndef _AMD64_
+/* subtract two unsigned pointers yeilding a signed pointer sized int */
+static inline HRESULT SubOvf_U_U(INT64 & r, UINT64 a, UINT64 b)
+{
+ r = a - b;
+ if ( ((a >= b) && (r >= 0)) ||
+ ((a < b) && (r < 0)))
+ {
+ return S_OK;
+ }
+ return E_FAIL;
+}
+#endif
+
+
+/******************************************************************/
+/* apply the relocs for this section.
+*/
+
+HRESULT PEWriterSection::applyRelocs(IMAGE_NT_HEADERS * pNtHeaders,
+ PERelocSection * pBaseRelocSection,
+ CeeGenTokenMapper * pTokenMapper,
+ DWORD dataRvaBase,
+ DWORD rdataRvaBase,
+ DWORD codeRvaBase)
+{
+ HRESULT hr;
+
+ _ASSERTE(pBaseRelocSection); // need section to write relocs
+
+#ifdef LOGGING
+ // Ensure that if someone adds a value to CeeSectionRelocType in cor.h,
+ // that they also add an entry to RelocName.
+ static_assert_no_msg(NumItems(RelocName) == srRelocSentinel);
+#ifdef _DEBUG
+ for (unsigned int i = 0; i < srRelocSentinel; i++)
+ {
+ _ASSERTE(strlen(RelocName[i]) <= strlen(RelocSpaces));
+ }
+#endif // _DEBUG
+#endif // LOGGING
+
+ if (m_relocCur == m_relocStart)
+ return S_OK;
+
+ bool isPE32 = (pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC));
+
+#ifdef LOGGING
+ LOG((LF_ZAP, LL_INFO100000,
+ "APPLYING section relocs for section %s start RVA = 0x%x\n",
+ m_name, m_baseRVA));
+#endif
+
+ UINT64 imageBase = isPE32 ? VAL32(((IMAGE_NT_HEADERS32 *) pNtHeaders)->OptionalHeader.ImageBase)
+ : VAL64(((IMAGE_NT_HEADERS64 *) pNtHeaders)->OptionalHeader.ImageBase);
+
+ // sort them to make the baseRelocs pretty
+ qsort(m_relocStart, (m_relocCur - m_relocStart), sizeof(PESectionReloc), relocCmp);
+
+ for (PESectionReloc * cur = m_relocStart; cur < m_relocCur; cur++)
+ {
+ _ASSERTE((cur->offset + 4) <= m_blobFetcher.GetDataLen());
+
+ int curType = cur->type;
+ DWORD curOffset = cur->offset;
+ bool isRelocPtr = ((curType & srRelocPtr) != 0);
+ bool noBaseBaseReloc = ((curType & srNoBaseReloc) != 0);
+ UINT64 targetOffset = 0;
+ int slotNum = 0;
+ INT64 oldStarPos;
+
+ // If cur->section is NULL then this is a pointer outside the module.
+ bool externalAddress = (cur->section == NULL);
+
+ curType &= ~(srRelocPtr | srNoBaseReloc);
+
+ /* If we see any srRelocHighLow's in a PE64 file we convert them into DIR64 relocs */
+ if (!isPE32 && (curType == srRelocHighLow))
+ curType = srRelocDir64;
+
+ /* If we have an IA64 instruction fixup then extract the slot number and adjust curOffset */
+ if ((curType == srRelocIA64PcRel25) || (curType == srRelocIA64Imm64) || (curType == srRelocIA64PcRel64))
+ {
+ _ASSERTE((curOffset & 0x3) == 0);
+ slotNum = (curOffset & 0xf) >> 2;
+ curOffset &= ~0xf;
+ }
+
+ DWORD curRVA = m_baseRVA; // RVA in the PE image of the reloc site
+ IfFailRet(AddOvf_RVA(curRVA, curOffset));
+ DWORD UNALIGNED * pos = (DWORD *) m_blobFetcher.ComputePointer(curOffset);
+
+ PREFIX_ASSUME(pos != NULL);
+
+#ifdef LOGGING
+ LOG((LF_ZAP, LL_INFO1000000,
+ " Reloc %s%s%s at %-7s+%04x (RVA=%08x) at" FMT_ADDR,
+ RelocName[curType], (isRelocPtr) ? "Ptr" : " ",
+ &RelocSpaces[strlen(RelocName[curType])],
+ m_name, curOffset, curRVA, DBG_ADDR(pos)));
+#endif
+ //
+ // 'pos' is the site of the reloc
+ // Compute 'targetOffset' from pointer if necessary
+ //
+
+ if (isRelocPtr)
+ {
+ // Calculate the value of ptr to pass to computeOffset
+ char * ptr = (char *) pos;
+
+ if (curType == srRelocRelative) {
+ //
+ // Here we add sizeof(int) because we need to calculate
+ // ptr as the true call target address (x86 pc-rel)
+ // We need to true call target address since pass it
+ // to computeOffset and this function would fall if
+ // the address we pass is before the start of a section
+ //
+ oldStarPos = (SSIZE_T) ptr;
+ IfFailRet(AddOvf_S_S32(oldStarPos, GET_UNALIGNED_INT32(pos)));
+ IfFailRet(AddOvf_S_U32(oldStarPos, sizeof(int)));
+ ptr = (char *) oldStarPos;
+ targetOffset = externalAddress ? (size_t) ptr
+ : cur->section->computeOffset(ptr);
+ // We subtract off the four bytes that we added previous
+ // since the code below depends upon this
+ IfFailRet(SubOvf_U_U32(targetOffset, sizeof(int)));
+ IfFailRet(UnsignedFitsIn32Bits(targetOffset)); // Check for overflow
+ SET_UNALIGNED_VAL32(pos, targetOffset);
+ }
+ else if (curType == srRelocIA64Imm64) {
+ _ASSERTE(slotNum == 1);
+ ptr = (char *) ((intptr_t) GetIA64Imm64((UINT64 *) ptr));
+ oldStarPos = (SSIZE_T) ptr;
+ targetOffset = externalAddress ? (size_t) ptr
+ : cur->section->computeOffset(ptr);
+ _ASSERTE(!isPE32);
+ PutIA64Imm64((UINT64 *)pos, targetOffset);
+ }
+ else if (curType == srRelocIA64PcRel64) {
+ _ASSERTE(slotNum == 1);
+ ptr = (char *) ((intptr_t) GetIA64Rel64((UINT64 *) ptr));
+ oldStarPos = (SSIZE_T) ptr;
+ targetOffset = externalAddress ? (size_t) ptr
+ : cur->section->computeOffset(ptr);
+ _ASSERTE(!isPE32);
+ PutIA64Rel64((UINT64 *)pos, targetOffset);
+ }
+ else {
+ _ASSERTE(curType != srRelocIA64PcRel25);
+ ptr = (char *) GET_UNALIGNED_VALPTR(ptr);
+ oldStarPos = (SSIZE_T) ptr;
+ targetOffset = externalAddress ? (size_t) ptr
+ : cur->section->computeOffset(ptr);
+ IfFailRet(UnsignedFitsIn32Bits(targetOffset)); // Check for overflow
+ SET_UNALIGNED_VAL32(pos, targetOffset);
+ /* Zero the upper 32-bits for a machine with 64-bit pointers */
+ if (!isPE32)
+ SET_UNALIGNED_VAL32(pos+1, 0);
+ }
+ }
+#ifdef LOGGING
+ else
+ {
+ if (curType == srRelocIA64PcRel25)
+ {
+ oldStarPos = GetIA64Rel25((UINT64 *) pos, slotNum);
+ }
+ else
+ {
+ if (curType == srRelocIA64PcRel64)
+ {
+ _ASSERTE(slotNum == 1);
+ oldStarPos = GetIA64Rel64((UINT64 *) pos);
+ }
+ else if (curType == srRelocIA64Imm64)
+ {
+ oldStarPos = GetIA64Imm64((UINT64 *)pos);
+ }
+ else
+ {
+ oldStarPos = GET_UNALIGNED_VAL32(pos);
+ }
+ }
+ }
+#endif
+
+ //
+ // 'targetOffset' has now been computed. Write out the appropriate value.
+ // Record base relocs as necessary.
+ //
+
+ bool fBaseReloc = false;
+ bool fNeedBrl = false;
+ INT64 newStarPos = 0; // oldStarPos gets updated to newStarPos
+
+ if (curType == srRelocAbsolute || curType == srRelocAbsoluteTagged) {
+ _ASSERTE(!externalAddress);
+
+ newStarPos = GET_UNALIGNED_INT32(pos);
+
+ if (curType == srRelocAbsoluteTagged)
+ newStarPos = (newStarPos & ~0x80000001) >> 1;
+
+ if (rdataRvaBase > 0 && ! strcmp((const char *)(cur->section->m_name), ".rdata"))
+ IfFailRet(AddOvf_S_U32(newStarPos, rdataRvaBase));
+ else if (dataRvaBase > 0 && ! strcmp((const char *)(cur->section->m_name), ".data"))
+ IfFailRet(AddOvf_S_U32(newStarPos, dataRvaBase));
+ else
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_baseRVA));
+
+ if (curType == srRelocAbsoluteTagged)
+ newStarPos = (newStarPos << 1) | 0x80000001;
+
+ SET_UNALIGNED_VAL32(pos, newStarPos);
+ }
+ else if (curType == srRelocMapToken)
+ {
+ mdToken newToken;
+ if (pTokenMapper != NULL && pTokenMapper->HasTokenMoved((mdToken)GET_UNALIGNED_VAL32(pos), newToken)) {
+ // we have a mapped token
+ SET_UNALIGNED_VAL32(pos, newToken);
+ }
+ newStarPos = GET_UNALIGNED_VAL32(pos);
+ }
+ else if (curType == srRelocFilePos)
+ {
+ _ASSERTE(!externalAddress);
+ newStarPos = GET_UNALIGNED_VAL32(pos);
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_filePos));
+ SET_UNALIGNED_VAL32(pos, newStarPos);
+ }
+ else if (curType == srRelocRelative)
+ {
+ if (externalAddress) {
+#if defined(_AMD64_)
+ newStarPos = GET_UNALIGNED_INT32(pos);
+#else // x86
+ UINT64 targetAddr = GET_UNALIGNED_VAL32(pos);
+ IfFailRet(SubOvf_U_U(newStarPos, targetAddr, imageBase));
+#endif
+ }
+ else {
+ newStarPos = GET_UNALIGNED_INT32(pos);
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_baseRVA));
+ }
+ IfFailRet(SubOvf_S_U32(newStarPos, curRVA));
+ IfFailRet(SignedFitsIn31Bits(newStarPos)); // Check for overflow
+ SET_UNALIGNED_VAL32(pos, newStarPos);
+ }
+ else if (curType == srRelocCodeRelative)
+ {
+ newStarPos = GET_UNALIGNED_INT32(pos);
+ IfFailRet(SubOvf_S_U32(newStarPos, codeRvaBase));
+ if (externalAddress)
+ IfFailRet(SubOvf_S_U(newStarPos, imageBase));
+ else
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_baseRVA));
+ IfFailRet(SignedFitsIn31Bits(newStarPos)); // Check for overflow
+ SET_UNALIGNED_VAL32(pos, newStarPos);
+
+ }
+ else if (curType == srRelocIA64PcRel25)
+ {
+ _ASSERTE((m_baseRVA & 15) == 0);
+ _ASSERTE((cur->section->m_baseRVA & 15) == 0);
+
+ newStarPos = GetIA64Rel25((UINT64 *) pos, slotNum);
+ IfFailRet(SubOvf_S_U32(newStarPos, curRVA));
+ if (externalAddress)
+ IfFailRet(SubOvf_S_U(newStarPos, imageBase));
+ else
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_baseRVA));
+
+ INT64 hiBits = newStarPos >> 24;
+
+ _ASSERTE((hiBits==0) || (hiBits==-1));
+
+ IfFailRet(AddOvf_S_U32(newStarPos, GetIA64Rel25((UINT64 *) pos, slotNum)));
+
+ hiBits = newStarPos >> 24;
+
+ _ASSERTE((hiBits==0) || (hiBits==-1));
+
+ INT32 delta32 = (INT32) newStarPos;
+
+ PutIA64Rel25((UINT64 *) pos, slotNum, delta32);
+
+ _ASSERTE(GetIA64Rel25((UINT64 *) pos, slotNum) == delta32);
+
+#ifdef LOGGING
+ if (newStarPos < s_minPcRel25)
+ s_minPcRel25 = newStarPos;
+ if (newStarPos > s_maxPcRel25)
+ s_maxPcRel25 = newStarPos;
+#endif
+ }
+ else if (curType == srRelocIA64PcRel64)
+ {
+ _ASSERTE((m_baseRVA & 15) == 0);
+ _ASSERTE(slotNum == 1);
+
+ newStarPos = GetIA64Rel64((UINT64 *) pos);
+ IfFailRet(SubOvf_S_U32(newStarPos, m_baseRVA));
+
+ if (externalAddress)
+ IfFailRet(SubOvf_S_U(newStarPos, imageBase));
+ else
+ {
+ _ASSERTE((cur->section->m_baseRVA & 15) == 0);
+ IfFailRet(AddOvf_S_U32(newStarPos, cur->section->m_baseRVA));
+ }
+
+ INT64 hiBits = newStarPos >> 24;
+
+ fNeedBrl = (hiBits != 0) && (hiBits != -1);
+
+ /* Can we convert the brl.call into a br.call? */
+ if (!fNeedBrl)
+ {
+ INT32 delta32 = (INT32) newStarPos;
+
+ UINT64 temp0 = ((UINT64 *) pos)[0];
+ UINT64 temp1 = ((UINT64 *) pos)[1];
+#ifdef _DEBUG
+ //
+ // make certain we're decoding a brl opcode, with template 4 or 5
+ //
+ UINT64 templa = (temp0 >> 0) & 0x1f;
+ UINT64 opcode = (temp1 >> 60) & 0xf;
+
+ _ASSERTE(((opcode == 0xC) || (opcode == 0xD)) &&
+ ((templa == 0x4) || (templa == 0x5)));
+#endif
+ const UINT64 mask0 = UI64(0x00003FFFFFFFFFE1);
+ const UINT64 mask1 = UI64(0x7700000FFF800000);
+
+ /* Clear all bits used as part of the slot1 and slot2 */
+ temp0 &= mask0; // opcode becomes 4 or 5
+ temp1 &= mask1;
+
+ temp0 |= 0x10; // template becomes 0x10 or 0x11
+ temp1 |= 0x200; // slot 1 becomes nop.i
+
+ ((UINT64 *) pos)[0] = temp0;
+ ((UINT64 *) pos)[1] = temp1;
+
+ PutIA64Rel25((UINT64 *) pos, 2, delta32);
+ _ASSERTE(GetIA64Rel25((UINT64 *) pos, 2) == delta32);
+ }
+ else
+ {
+ PutIA64Rel64((UINT64 *) pos, newStarPos);
+ _ASSERTE(GetIA64Rel64((UINT64 *) pos) == newStarPos);
+ }
+ }
+ else if (curType == srRelocHighLow)
+ {
+ _ASSERTE(isPE32);
+
+ // we have a 32-bit value at pos
+ UINT64 value = GET_UNALIGNED_VAL32(pos);
+
+ if (!externalAddress)
+ {
+ IfFailRet(AddOvf_U_U32(value, cur->section->m_baseRVA));
+ IfFailRet(AddOvf_U_U(value, imageBase));
+ }
+
+ IfFailRet(UnsignedFitsIn32Bits(value)); // Check for overflow
+ SET_UNALIGNED_VAL32(pos, value);
+
+ newStarPos = value;
+
+ fBaseReloc = true;
+ }
+ else if (curType == srRelocDir64)
+ {
+ _ASSERTE(!isPE32);
+
+ // we have a 64-bit value at pos
+ UINT64 UNALIGNED * p_value = (UINT64 *) pos;
+ targetOffset = *p_value;
+
+ if (!externalAddress)
+ {
+ // The upper bits of targetOffset must be zero
+ IfFailRet(UnsignedFitsIn32Bits(targetOffset));
+
+ IfFailRet(AddOvf_U_U32(targetOffset, cur->section->m_baseRVA));
+ IfFailRet(AddOvf_U_U(targetOffset, imageBase));
+ }
+
+ *p_value = targetOffset;
+ newStarPos = targetOffset;
+ fBaseReloc = true;
+ }
+ else if (curType == srRelocIA64Imm64)
+ {
+ _ASSERTE(!isPE32);
+ _ASSERTE((curRVA & 15) == 0); // This reloc should be 16-byte aligned
+
+ // we have a 64-bit value encoded in the instruction at pos
+ targetOffset = GetIA64Imm64((UINT64 *)pos);
+
+ if (!externalAddress)
+ {
+ // The upper bits of targetOffset must be zero
+ IfFailRet(UnsignedFitsIn32Bits(targetOffset));
+
+ IfFailRet(AddOvf_U_U32(targetOffset, cur->section->m_baseRVA));
+ IfFailRet(AddOvf_U_U(targetOffset, imageBase));
+ }
+
+ PutIA64Imm64((UINT64 *)pos, targetOffset);
+ newStarPos = targetOffset;
+ fBaseReloc = true;
+ }
+ else
+ {
+ _ASSERTE(!"Unknown Relocation type");
+ }
+
+ if (fBaseReloc && !noBaseBaseReloc)
+ {
+ pBaseRelocSection->AddBaseReloc(curRVA, curType);
+ }
+
+#ifdef LOGGING
+ const char* sectionName;
+
+ if (externalAddress)
+ {
+ sectionName = "external";
+ }
+ else
+ {
+ sectionName = cur->section->m_name;
+ }
+
+ LOG((LF_ZAP, LL_INFO1000000,
+ "to %-7s+%04x, old =" FMT_ADDR "new =" FMT_ADDR "%s%s\n",
+ sectionName, targetOffset,
+ DBG_ADDR(oldStarPos), DBG_ADDR(newStarPos),
+ fBaseReloc ? "(BASE RELOC)" : "",
+ fNeedBrl ? "(BRL)" : "" ));
+#endif
+
+ }
+ return S_OK;
+}
+
+/******************************************************************/
+
+PESeedSection::PESeedSection(PEDecoder * peDecoder,
+ IMAGE_SECTION_HEADER * seedSection)
+ : PEWriterSection((const char *)seedSection->Name,
+ VAL32(seedSection->Characteristics),
+ VAL32(seedSection->SizeOfRawData),
+ 0),
+ m_pSeedFileDecoder(peDecoder),
+ m_pSeedSectionHeader(seedSection)
+{
+ m_baseRVA = VAL32(seedSection->VirtualAddress);
+}
+
+HRESULT PESeedSection::write(HANDLE file) {
+ ULONG sizeOfSection = VAL32(m_pSeedSectionHeader->SizeOfRawData);
+ LPCVOID sectionData = PBYTE(m_pSeedFileDecoder->GetBase()) + m_pSeedSectionHeader->PointerToRawData;
+
+ DWORD dwWritten = 0;
+ if (!WriteFile(file, sectionData, sizeOfSection, &dwWritten, NULL)) {
+ return HRESULT_FROM_GetLastError();
+ }
+ _ASSERTE(dwWritten == sizeOfSection);
+ return S_OK;
+}
+
+unsigned PESeedSection::writeMem(void ** pMem) {
+ ULONG sizeOfSection = VAL32(m_pSeedSectionHeader->SizeOfRawData);
+ LPCVOID sectionData = PBYTE(m_pSeedFileDecoder->GetBase()) + m_pSeedSectionHeader->PointerToRawData;
+
+ COPY_AND_ADVANCE(*pMem, sectionData, sizeOfSection);
+ return sizeOfSection;
+}
+
+/******************************************************************/
+HRESULT PEWriter::Init(PESectionMan *pFrom, DWORD createFlags, LPCWSTR seedFileName)
+{
+ if (pFrom)
+ *(PESectionMan*)this = *pFrom;
+ else {
+ HRESULT hr = PESectionMan::Init();
+ if (FAILED(hr))
+ return hr;
+ }
+ time_t now;
+ time(&now);
+
+#ifdef LOGGING
+ InitializeLogging();
+#endif
+
+ // Save the timestamp so that we can give it out if someone needs
+ // it.
+ m_peFileTimeStamp = (DWORD) now;
+
+ // We must be creating either a PE32 or a PE64 file
+ if (createFlags & ICEE_CREATE_FILE_PE64)
+ {
+ m_ntHeaders = (IMAGE_NT_HEADERS *) new (nothrow) IMAGE_NT_HEADERS64;
+ m_ntHeadersSize = sizeof(IMAGE_NT_HEADERS64);
+
+ if (!m_ntHeaders) return E_OUTOFMEMORY;
+ memset(m_ntHeaders, 0, m_ntHeadersSize);
+
+ m_ntHeaders->OptionalHeader.Magic = VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
+ m_ntHeaders->FileHeader.SizeOfOptionalHeader = VAL16(sizeof(IMAGE_OPTIONAL_HEADER64));
+ }
+ else
+ {
+ _ASSERTE(createFlags & ICEE_CREATE_FILE_PE32);
+ m_ntHeaders = (IMAGE_NT_HEADERS *) new (nothrow) IMAGE_NT_HEADERS32;
+ m_ntHeadersSize = sizeof(IMAGE_NT_HEADERS32);
+
+ if (!m_ntHeaders) return E_OUTOFMEMORY;
+ memset(m_ntHeaders, 0, m_ntHeadersSize);
+
+ m_ntHeaders->OptionalHeader.Magic = VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
+ m_ntHeaders->FileHeader.SizeOfOptionalHeader = VAL16(sizeof(IMAGE_OPTIONAL_HEADER32));
+ }
+
+ // Record whether we should create the CorExeMain and CorDllMain stubs
+ m_createCorMainStub = ((createFlags & ICEE_CREATE_FILE_CORMAIN_STUB) != 0);
+
+ // We must have a valid target machine selected
+ if ((createFlags & ICEE_CREATE_MACHINE_MASK) == ICEE_CREATE_MACHINE_I386)
+ {
+ m_ntHeaders->FileHeader.Machine = VAL16(IMAGE_FILE_MACHINE_I386);
+ }
+ else if ((createFlags & ICEE_CREATE_MACHINE_MASK) == ICEE_CREATE_MACHINE_IA64)
+ {
+ m_ntHeaders->FileHeader.Machine = VAL16(IMAGE_FILE_MACHINE_IA64);
+ }
+ else if ((createFlags & ICEE_CREATE_MACHINE_MASK) == ICEE_CREATE_MACHINE_AMD64)
+ {
+ m_ntHeaders->FileHeader.Machine = VAL16(IMAGE_FILE_MACHINE_AMD64);
+ }
+ else if ((createFlags & ICEE_CREATE_MACHINE_MASK) == ICEE_CREATE_MACHINE_ARM)
+ {
+ m_ntHeaders->FileHeader.Machine = VAL16(IMAGE_FILE_MACHINE_ARMNT);
+
+ // The OS loader already knows how to initialize pure managed assemblies and we have no legacy OS
+ // support to worry about on ARM so don't ever create the stub for ARM binaries.
+ m_createCorMainStub = false;
+ }
+ else
+ {
+ _ASSERTE(!"Invalid target machine");
+ }
+
+ cEntries = IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR + 1;
+ pEntries = new (nothrow) directoryEntry[cEntries];
+ if (pEntries == NULL) return E_OUTOFMEMORY;
+ memset(pEntries, 0, sizeof(*pEntries) * cEntries);
+
+ m_ntHeaders->Signature = VAL32(IMAGE_NT_SIGNATURE);
+ m_ntHeaders->FileHeader.TimeDateStamp = VAL32((ULONG) now);
+ m_ntHeaders->FileHeader.Characteristics = VAL16(0);
+
+ if (createFlags & ICEE_CREATE_FILE_STRIP_RELOCS)
+ {
+ m_ntHeaders->FileHeader.Characteristics |= VAL16(IMAGE_FILE_RELOCS_STRIPPED);
+ }
+
+ // Linker version should be consistent with current VC level
+ m_ntHeaders->OptionalHeader.MajorLinkerVersion = 11;
+ m_ntHeaders->OptionalHeader.MinorLinkerVersion = 0;
+
+ m_ntHeaders->OptionalHeader.SectionAlignment = VAL32(IMAGE_NT_OPTIONAL_HDR_SECTION_ALIGNMENT);
+ m_ntHeaders->OptionalHeader.FileAlignment = VAL32(0);
+ m_ntHeaders->OptionalHeader.AddressOfEntryPoint = VAL32(0);
+
+ m_ntHeaders->OptionalHeader.MajorOperatingSystemVersion = VAL16(4);
+ m_ntHeaders->OptionalHeader.MinorOperatingSystemVersion = VAL16(0);
+
+ m_ntHeaders->OptionalHeader.MajorImageVersion = VAL16(0);
+ m_ntHeaders->OptionalHeader.MinorImageVersion = VAL16(0);
+ m_ntHeaders->OptionalHeader.MajorSubsystemVersion = VAL16(4);
+ m_ntHeaders->OptionalHeader.MinorSubsystemVersion = VAL16(0);
+ m_ntHeaders->OptionalHeader.Win32VersionValue = VAL32(0);
+ m_ntHeaders->OptionalHeader.Subsystem = VAL16(0);
+ m_ntHeaders->OptionalHeader.DllCharacteristics = VAL16(0);
+ m_ntHeaders->OptionalHeader.CheckSum = VAL32(0);
+ setDllCharacteristics(IMAGE_DLLCHARACTERISTICS_NO_SEH |
+ IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
+ IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
+ IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE);
+
+ if (isPE32())
+ {
+ IMAGE_NT_HEADERS32* p_ntHeaders32 = ntHeaders32();
+ p_ntHeaders32->OptionalHeader.ImageBase = VAL32(CEE_IMAGE_BASE_32);
+ p_ntHeaders32->OptionalHeader.SizeOfStackReserve = VAL32(0x100000);
+ p_ntHeaders32->OptionalHeader.SizeOfStackCommit = VAL32(0x1000);
+ p_ntHeaders32->OptionalHeader.SizeOfHeapReserve = VAL32(0x100000);
+ p_ntHeaders32->OptionalHeader.SizeOfHeapCommit = VAL32(0x1000);
+ p_ntHeaders32->OptionalHeader.LoaderFlags = VAL32(0);
+ p_ntHeaders32->OptionalHeader.NumberOfRvaAndSizes = VAL32(16);
+ }
+ else
+ {
+ IMAGE_NT_HEADERS64* p_ntHeaders64 = ntHeaders64();
+ // FIX what are the correct values for PE+ (64-bit) ?
+ p_ntHeaders64->OptionalHeader.ImageBase = VAL64(CEE_IMAGE_BASE_64);
+ p_ntHeaders64->OptionalHeader.SizeOfStackReserve = VAL64(0x400000);
+ p_ntHeaders64->OptionalHeader.SizeOfStackCommit = VAL64(0x4000);
+ p_ntHeaders64->OptionalHeader.SizeOfHeapReserve = VAL64(0x100000);
+ p_ntHeaders64->OptionalHeader.SizeOfHeapCommit = VAL64(0x2000);
+ p_ntHeaders64->OptionalHeader.LoaderFlags = VAL32(0);
+ p_ntHeaders64->OptionalHeader.NumberOfRvaAndSizes = VAL32(16);
+ }
+
+ m_ilRVA = (DWORD) -1;
+ m_dataRvaBase = 0;
+ m_rdataRvaBase = 0;
+ m_codeRvaBase = 0;
+ m_encMode = FALSE;
+
+ virtualPos = 0;
+ filePos = 0;
+ reloc = NULL;
+ strtab = NULL;
+ headers = NULL;
+ headersEnd = NULL;
+
+ m_file = INVALID_HANDLE_VALUE;
+
+ //
+ // Seed file
+ //
+
+ m_hSeedFile = INVALID_HANDLE_VALUE;
+ m_hSeedFileMap = INVALID_HANDLE_VALUE;
+ m_pSeedFileDecoder = NULL;
+ m_iSeedSections = 0;
+ m_pSeedSectionToAdd = NULL;
+
+ if (seedFileName)
+ {
+ HandleHolder hFile (WszCreateFile(seedFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL));
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ return HRESULT_FROM_GetLastError();
+
+ MapViewHolder hMapFile (WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
+ DWORD dwFileLen = SafeGetFileSize(hFile, 0);
+ if (dwFileLen == 0xffffffff)
+ return HRESULT_FROM_GetLastError();
+
+ if (hMapFile == NULL)
+ return HRESULT_FROM_GetLastError();
+
+ BYTE * baseFileView = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
+
+ PEDecoder * pPEDecoder = new (nothrow) PEDecoder(baseFileView, (COUNT_T)dwFileLen);
+ if (pPEDecoder == NULL) return E_OUTOFMEMORY;
+
+ if (pPEDecoder->Has32BitNTHeaders())
+ {
+ if ((createFlags & ICEE_CREATE_FILE_PE32) == 0)
+ return E_FAIL;
+
+ setImageBase32(DWORD(size_t(pPEDecoder->GetPreferredBase())));
+ }
+ else
+ {
+ if ((createFlags & ICEE_CREATE_FILE_PE64) == 0)
+ return E_FAIL;
+
+ setImageBase64(UINT64((intptr_t) pPEDecoder->GetPreferredBase()));
+ }
+
+ setFileAlignment (VAL32(pPEDecoder->GetFileAlignment()));
+ setSectionAlignment(VAL32(pPEDecoder->GetSectionAlignment()));
+
+ hFile.SuppressRelease();
+ hMapFile.SuppressRelease();
+
+ m_hSeedFile = hFile;
+ m_hSeedFileMap = hMapFile;
+ m_pSeedFileDecoder = pPEDecoder;
+
+#ifdef _WIN64
+ m_pSeedFileNTHeaders = pPEDecoder->GetNTHeaders64();
+#else
+ m_pSeedFileNTHeaders = pPEDecoder->GetNTHeaders32();
+#endif
+
+ // Add the seed sections
+
+ m_pSeedSections = m_pSeedFileDecoder->FindFirstSection();
+
+ m_pSeedSectionToAdd = m_pSeedSections;
+ m_iSeedSections = m_pSeedFileDecoder->GetNumberOfSections();
+
+ for (unsigned i = 0; i < m_iSeedSections; m_pSeedSectionToAdd++, i++) {
+ PESection * dummy;
+ getSectionCreate((const char *)(m_pSeedSectionToAdd->Name),
+ VAL32(m_pSeedSectionToAdd->Characteristics),
+ &dummy);
+ }
+
+ m_pSeedSectionToAdd = NULL;
+ }
+
+ return S_OK;
+}
+
+/******************************************************************/
+HRESULT PEWriter::Cleanup() {
+
+ if (m_hSeedFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(m_hSeedFile);
+ CloseHandle(m_hSeedFileMap);
+ delete m_pSeedFileDecoder;
+ }
+
+ if (isPE32())
+ {
+ delete ntHeaders32();
+ }
+ else
+ {
+ delete ntHeaders64();
+ }
+
+ if (headers != NULL)
+ delete [] headers;
+
+ if (pEntries != NULL)
+ delete [] pEntries;
+
+ return PESectionMan::Cleanup();
+}
+
+PESection* PEWriter::getSection(const char* name)
+{
+ int len = (int)strlen(name);
+
+ // the section name can be at most 8 characters including the null.
+ if (len < 8)
+ len++;
+ else
+ len = 8;
+
+ // dbPrintf(("looking for section %s\n", name));
+ // Skip over the seed sections
+
+ for(PESection** cur = sectStart+m_iSeedSections; cur < sectCur; cur++) {
+ // dbPrintf(("searching section %s\n", (*cur)->m_ame));
+ if (strncmp((*cur)->m_name, name, len) == 0) {
+ // dbPrintf(("found section %s\n", (*cur)->m_name));
+ return(*cur);
+ }
+ }
+ return(0);
+}
+
+HRESULT PEWriter::newSection(const char* name, PESection **section,
+ unsigned flags, unsigned estSize,
+ unsigned estRelocs)
+{
+ if (m_pSeedSectionToAdd) {
+ _ASSERTE(strcmp((const char *)(m_pSeedSectionToAdd->Name), name) == 0 &&
+ VAL32(m_pSeedSectionToAdd->Characteristics) == flags);
+
+ PESeedSection * ret = new (nothrow) PESeedSection(m_pSeedFileDecoder, m_pSeedSectionToAdd);
+ *section = ret;
+ TESTANDRETURNMEMORY(ret);
+ return S_OK;
+ }
+
+ PEWriterSection * ret = new (nothrow) PEWriterSection(name, flags, estSize, estRelocs);
+ *section = ret;
+ TESTANDRETURNMEMORY(ret);
+ return S_OK;
+}
+
+ULONG PEWriter::getIlRva()
+{
+ // assume that pe optional header is less than size of section alignment. So this
+ // gives out the rva for the .text section, which is merged after the .text0 section
+ // This is verified in debug build when actually write out the file
+ _ASSERTE(m_ilRVA > 0);
+ return m_ilRVA;
+}
+
+void PEWriter::setIlRva(ULONG offset)
+{
+ // assume that pe optional header is less than size of section alignment. So this
+ // gives out the rva for the .text section, which is merged after the .text0 section
+ // This is verified in debug build when actually write out the file
+ m_ilRVA = roundUp(VAL32(m_ntHeaders->OptionalHeader.SectionAlignment) + offset, SUBSECTION_ALIGN);
+}
+
+HRESULT PEWriter::setDirectoryEntry(PEWriterSection *section, ULONG entry, ULONG size, ULONG offset)
+{
+ if (entry >= cEntries)
+ {
+ USHORT cNewEntries = (USHORT)max((ULONG)cEntries * 2, entry + 1);
+
+ if (cNewEntries <= cEntries) return E_OUTOFMEMORY; // Integer overflow
+ if (cNewEntries <= entry) return E_OUTOFMEMORY; // Integer overflow
+
+ directoryEntry *pNewEntries = new (nothrow) directoryEntry [ cNewEntries ];
+ if (pNewEntries == NULL) return E_OUTOFMEMORY;
+
+ CopyMemory(pNewEntries, pEntries, cEntries * sizeof(*pNewEntries));
+ ZeroMemory(pNewEntries + cEntries, (cNewEntries - cEntries) * sizeof(*pNewEntries));
+
+ delete [] pEntries;
+ pEntries = pNewEntries;
+ cEntries = cNewEntries;
+ }
+
+ pEntries[entry].section = section;
+ pEntries[entry].offset = offset;
+ pEntries[entry].size = size;
+ return S_OK;
+}
+
+void PEWriter::setEnCRvaBase(ULONG dataBase, ULONG rdataBase)
+{
+ m_dataRvaBase = dataBase;
+ m_rdataRvaBase = rdataBase;
+ m_encMode = TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// These 2 write functions must be implemented here so that they're in the same
+// .obj file as whoever creates the FILE struct. We can't pass a FILE struct
+// across a dll boundary and use it.
+//-----------------------------------------------------------------------------
+
+HRESULT PEWriterSection::write(HANDLE file)
+{
+ return m_blobFetcher.Write(file);
+}
+
+//-----------------------------------------------------------------------------
+// Write out the section to the stream
+//-----------------------------------------------------------------------------
+HRESULT CBlobFetcher::Write(HANDLE file)
+{
+// Must write out each pillar (including idx = m_nIndexUsed), one after the other
+ unsigned idx;
+ for(idx = 0; idx <= m_nIndexUsed; idx ++) {
+ if (m_pIndex[idx].GetDataLen() > 0)
+ {
+ ULONG length = m_pIndex[idx].GetDataLen();
+ DWORD dwWritten = 0;
+ if (!WriteFile(file, m_pIndex[idx].GetRawDataStart(), length, &dwWritten, NULL))
+ {
+ return HRESULT_FROM_GetLastError();
+ }
+ _ASSERTE(dwWritten == length);
+ }
+ }
+
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// These 2 write functions must be implemented here so that they're in the same
+// .obj file as whoever creates the FILE struct. We can't pass a FILE struct
+// across a dll boundary and use it.
+//-----------------------------------------------------------------------------
+
+unsigned PEWriterSection::writeMem(void **ppMem)
+{
+ HRESULT hr;
+ hr = m_blobFetcher.WriteMem(ppMem);
+ _ASSERTE(SUCCEEDED(hr));
+
+ return m_blobFetcher.GetDataLen();
+}
+
+//-----------------------------------------------------------------------------
+// Write out the section to memory
+//-----------------------------------------------------------------------------
+HRESULT CBlobFetcher::WriteMem(void **ppMem)
+{
+ char **ppDest = (char **)ppMem;
+ // Must write out each pillar (including idx = m_nIndexUsed), one after the other
+ unsigned idx;
+ for(idx = 0; idx <= m_nIndexUsed; idx ++) {
+ if (m_pIndex[idx].GetDataLen() > 0)
+ {
+ // WARNING: macro - must enclose in curly braces
+ COPY_AND_ADVANCE(*ppDest, m_pIndex[idx].GetRawDataStart(), m_pIndex[idx].GetDataLen());
+ }
+ }
+
+ return S_OK;
+}
+
+/******************************************************************/
+
+//
+// Intermediate table to sort to help determine section order
+//
+struct entry {
+ const char * name; // full name of the section
+ unsigned char nameLength; // length of the text part of the name
+ signed char index; // numeral value at the end of the name; -1 if none
+ unsigned short arrayIndex; // index of section within sectStart[]
+};
+
+class SectionNameSorter : protected CQuickSort<entry>
+{
+ entry * m_entries;
+ PEWriterSection ** m_sections;
+ unsigned m_count;
+ unsigned m_seedCount;
+
+ public:
+ SectionNameSorter(entry *entries, PEWriterSection ** sections, int count, unsigned seedSections)
+ : CQuickSort<entry>(entries, count),
+ m_entries(entries),
+ m_sections(sections),
+ m_count(unsigned(count)),
+ m_seedCount(seedSections)
+ {}
+
+ // Sorts the entries according to alphabetical + numerical order
+
+ int Compare(entry *first, entry *second)
+ {
+ PEWriterSection * firstSection = m_sections[first->arrayIndex];
+ PEWriterSection * secondSection = m_sections[second->arrayIndex];
+
+ // Seed sections are always at the start, in the order they were
+ // added to the PEWriter
+
+ if (firstSection->isSeedSection() || secondSection->isSeedSection()) {
+ if (firstSection->isSeedSection() && secondSection->isSeedSection())
+ return first->arrayIndex - second->arrayIndex;
+
+ return firstSection->isSeedSection() ? -1 : 1;
+ }
+
+ // Sort the names
+
+ int lenDiff = first->nameLength - second->nameLength;
+ int smallerLen;
+ if (lenDiff < 0)
+ smallerLen = first->nameLength;
+ else
+ smallerLen = second->nameLength;
+
+ int result = strncmp(first->name, second->name, smallerLen);
+
+ if (result != 0)
+ return result;
+ else
+ {
+ if (lenDiff != 0)
+ return lenDiff;
+ else
+ return (int)(first->index - second->index);
+ }
+ }
+
+ int SortSections()
+ {
+ Sort();
+
+ entry * ePrev = m_entries;
+ entry * e = ePrev + 1;
+ int iSections = 1; // First section is obviously unique
+
+ for (unsigned i = 1; i < m_count; i++, ePrev = e, e++) {
+
+ // Seed sections should stay at the front
+ _ASSERTE(i >= m_seedCount || i == e->arrayIndex);
+
+ if (!m_sections[ePrev->arrayIndex]->isSeedSection() &&
+ (ePrev->nameLength == e->nameLength) &&
+ strncmp(ePrev->name, e->name, e->nameLength) == 0)
+ {
+ continue;
+ }
+
+ iSections++;
+ }
+
+ return iSections;
+ }
+};
+
+#define SectionIndex IMAGE_SECTION_HEADER::VirtualAddress
+#define FirstEntryIndex IMAGE_SECTION_HEADER::SizeOfRawData
+
+HRESULT PEWriter::linkSortSections(entry * entries,
+ unsigned * piEntries,
+ unsigned * piUniqueSections)
+{
+ //
+ // Preserve current section order as much as possible, but apply the following
+ // rules:
+ // - sections named "xxx#" are collated into a single PE section "xxx".
+ // The contents of the CeeGen sections are sorted according to numerical
+ // order & made contiguous in the PE section
+ // - "text" always comes first in the file
+ // - empty sections receive no PE section
+ //
+
+ bool ExeOrDll = isExeOrDll(m_ntHeaders);
+
+ entry *e = entries;
+ for (PEWriterSection **cur = getSectStart(); cur < getSectCur(); cur++) {
+
+ //
+ // Throw away any old headers we've used.
+ //
+
+ (*cur)->m_header = NULL;
+
+ //
+ // Don't allocate PE data for 0 length sections
+ //
+
+ if ((*cur)->dataLen() == 0)
+ continue;
+
+ //
+ // Special case: omit "text0" from obj's
+ //
+
+ if (!ExeOrDll && strcmp((*cur)->m_name, ".text0") == 0)
+ continue;
+
+ e->name = (*cur)->m_name;
+
+ //
+ // Now find the end of the text part of the section name, and
+ // calculate the numeral (if any) at the end
+ //
+
+ _ASSERTE(strlen(e->name) < UCHAR_MAX);
+ const char *p = e->name + strlen(e->name);
+ int index = 0; // numeral at the end of the section name
+ int placeValue = 1;
+ if (isdigit(p[-1]))
+ {
+ while (--p > e->name)
+ {
+ if (!isdigit(*p))
+ break;
+ index += ((*p - '0') * placeValue);
+ placeValue *= 10;
+ }
+ p++;
+
+ //
+ // Special case: put "xxx" after "xxx0" and before "xxx1"
+ //
+
+ if (index == 0)
+ index = -1;
+ }
+
+ _ASSERTE(index == -1 || index == atoi(p));
+
+ e->nameLength = (unsigned char)(p - e->name);
+ e->index = index;
+ e->arrayIndex = (unsigned short)(cur - getSectStart());
+ e++;
+ }
+
+ //
+ // Sort the entries according to alphabetical + numerical order
+ //
+
+ SectionNameSorter sorter(entries, getSectStart(), int(e - entries), m_iSeedSections);
+ *piUniqueSections = sorter.SortSections();
+
+ *piEntries = unsigned(e - entries);
+
+ return S_OK;
+}
+
+class HeaderSorter : public CQuickSort<IMAGE_SECTION_HEADER>
+{
+ public:
+ HeaderSorter(IMAGE_SECTION_HEADER *headers, int count)
+ : CQuickSort<IMAGE_SECTION_HEADER>(headers, count) {}
+
+ int Compare(IMAGE_SECTION_HEADER *first, IMAGE_SECTION_HEADER *second)
+ {
+ // IMAGE_SECTION_HEADER::VirtualAddress/SectionIndex contains the
+ // index of the section
+ return VAL32(first->SectionIndex) - VAL32(second->SectionIndex);
+ }
+};
+
+HRESULT PEWriter::linkSortHeaders(entry * entries, unsigned iEntries, unsigned iUniqueSections)
+{
+ if (headers != NULL)
+ delete [] headers;
+
+ // 1 extra for .reloc
+ S_UINT32 cUniqueSectionsAllocated = S_UINT32(iUniqueSections) + S_UINT32(1);
+ if (cUniqueSectionsAllocated.IsOverflow())
+ {
+ return COR_E_OVERFLOW;
+ }
+ headers = new (nothrow) IMAGE_SECTION_HEADER[cUniqueSectionsAllocated.Value()];
+ TESTANDRETURNMEMORY(headers);
+
+ memset(headers, 0, sizeof(*headers) * cUniqueSectionsAllocated.Value());
+
+ entry *ePrev = NULL;
+ IMAGE_SECTION_HEADER *h = headers - 1;
+
+ //
+ // Store the sorting index
+ //
+
+ entry * entriesEnd = entries + iEntries;
+
+ for (entry * e = entries ; e < entriesEnd; e++)
+ {
+ if (ePrev != NULL
+ && !getSectStart()[ePrev->arrayIndex]->isSeedSection()
+ && e->nameLength == ePrev->nameLength
+ && strncmp(e->name, ePrev->name, e->nameLength) == 0)
+ {
+ //
+ // This section has the same name as the previous section, and
+ // will be collapsed with the previous section.
+ // Just update the (common) header information
+ //
+
+ if (e->arrayIndex < ePrev->arrayIndex)
+ {
+ //
+ // Use the smaller of the indices of e and ePrev
+ //
+ h->SectionIndex = VAL32(VAL32(h->SectionIndex) - (e->arrayIndex - ePrev->arrayIndex));
+ }
+
+ // Store an approximation of the size of the section temporarily
+ h->Misc.VirtualSize = VAL32(VAL32(h->Misc.VirtualSize) + getSectStart()[e->arrayIndex]->dataLen());
+ }
+ else
+ {
+ // Grab a new header
+
+ h++;
+
+ strncpy_s((char *) h->Name, sizeof(h->Name), e->name, e->nameLength);
+
+ setSectionIndex(h, e->arrayIndex);
+
+ // Store the entry index in this field temporarily
+ h->FirstEntryIndex = VAL32((DWORD)(e - entries));
+
+ // Store an approximation of the size of the section temporarily
+ h->Misc.VirtualSize = VAL32(getSectStart()[e->arrayIndex]->dataLen());
+ }
+ ePrev = e;
+ }
+
+ headersEnd = ++h;
+
+ _ASSERTE(headers + iUniqueSections == headersEnd);
+
+ //
+ // Sort the entries according to alphabetical + numerical order
+ //
+
+ HeaderSorter headerSorter(headers, int(iUniqueSections));
+
+ headerSorter.Sort();
+
+ return S_OK;
+} // PEWriter::linkSortHeaders
+
+HRESULT PEWriter::linkPlaceSections(entry * entries, unsigned iEntries)
+{
+ entry * entriesEnd = entries + iEntries;
+
+ for (IMAGE_SECTION_HEADER * h = headers; h < headersEnd; h++)
+ {
+ // Get to the first entry corresponding to this section header
+
+ entry * e = entries + VAL32(h->FirstEntryIndex);
+ PEWriterSection *s = getSectStart()[e->arrayIndex];
+
+ if (s->isSeedSection()) {
+ virtualPos = s->getBaseRVA();
+ }
+
+ h->VirtualAddress = VAL32(virtualPos);
+ h->PointerToRawData = VAL32(filePos);
+
+ s->m_baseRVA = virtualPos;
+ s->m_filePos = filePos;
+ s->m_header = h;
+ h->Characteristics = VAL32(s->m_flags);
+
+#ifdef LOGGING
+ LOG((LF_ZAP, LL_INFO10,
+ " Section %-7s RVA=%08x, Length=%08x, FilePos=%08x\n",
+ s->m_name, s->m_baseRVA, s->dataLen(), s->m_filePos));
+#endif
+
+ unsigned dataSize = s->dataLen();
+
+ // Find all the other entries corresponding to this section header
+
+ PEWriterSection *sPrev = s;
+ entry * ePrev = e;
+ while (++e < entriesEnd)
+ {
+ if (e->nameLength != ePrev->nameLength
+ || strncmp(e->name, ePrev->name, e->nameLength) != 0)
+ break;
+
+ s = getSectStart()[e->arrayIndex];
+ _ASSERTE(s->m_flags == VAL32(h->Characteristics));
+
+ sPrev->m_filePad = padLen(dataSize, SUBSECTION_ALIGN);
+ dataSize = roundUp(dataSize, SUBSECTION_ALIGN);
+
+ s->m_baseRVA = virtualPos + dataSize;
+ s->m_filePos = filePos + dataSize;
+ s->m_header = h;
+ sPrev = s;
+
+ dataSize += s->dataLen();
+
+#ifdef LOGGING
+ LOG((LF_ZAP, LL_INFO10,
+ " Section %-7s RVA=%08x, Length=%08x, FilePos=%08x\n",
+ s->m_name, s->m_baseRVA, s->dataLen(), s->m_filePos));
+#endif
+
+ ePrev = e;
+ }
+
+ h->Misc.VirtualSize = VAL32(dataSize);
+
+ sPrev->m_filePad = padLen(dataSize, VAL32(m_ntHeaders->OptionalHeader.FileAlignment));
+ dataSize = roundUp(dataSize, VAL32(m_ntHeaders->OptionalHeader.FileAlignment));
+ h->SizeOfRawData = VAL32(dataSize);
+ filePos += dataSize;
+
+ dataSize = roundUp(dataSize, VAL32(m_ntHeaders->OptionalHeader.SectionAlignment));
+ virtualPos += dataSize;
+ }
+
+ return S_OK;
+}
+
+void PEWriter::setSectionIndex(IMAGE_SECTION_HEADER * h, unsigned sectionIndex) {
+
+ if (getSectStart()[sectionIndex]->isSeedSection()) {
+ h->SectionIndex = VAL32(sectionIndex);
+ return;
+ }
+
+ //
+ // Reserve some dummy "array index" values for special sections
+ // at the start of the image (after the seed sections)
+ //
+
+ static const char * const SpecialNames[] = { ".text", ".cormeta", NULL };
+ enum { SPECIAL_NAMES_COUNT = NumItems(SpecialNames) };
+
+ for (const char * const * s = SpecialNames; /**/; s++)
+ {
+ if (*s == 0)
+ {
+ h->SectionIndex = VAL32(sectionIndex + SPECIAL_NAMES_COUNT);
+ break;
+ }
+ else if (strcmp((char *) h->Name, *s) == 0)
+ {
+ h->SectionIndex = VAL32(m_iSeedSections + DWORD(s - SpecialNames));
+ break;
+ }
+ }
+
+}
+
+
+HRESULT PEWriter::link() {
+
+ //
+ // NOTE:
+ // link() can be called more than once! This is because at least one compiler
+ // (the prejitter) needs to know the base addresses of some segments before it
+ // builds others. It's up to the caller to insure the layout remains the same
+ // after changes are made, though.
+ //
+
+ //
+ // Assign base addresses to all sections, and layout & merge PE sections
+ //
+
+ bool ExeOrDll = isExeOrDll(m_ntHeaders);
+
+ //
+ // Collate by name & sort by index
+ //
+
+ // First collect all information into entries[]
+
+ int sectCount = getSectCount();
+ entry *entries = (entry *) _alloca(sizeof(entry) * sectCount);
+
+ unsigned iUniqueSections, iEntries;
+ HRESULT hr;
+ IfFailRet(linkSortSections(entries, &iEntries, &iUniqueSections));
+
+ //
+ // Now, allocate a header for each unique section name.
+ // Also record the minimum section index for each section
+ // so we can preserve order as much as possible.
+ //
+
+ IfFailRet(linkSortHeaders(entries, iEntries, iUniqueSections));
+
+ //
+ // If file alignment is not zero, it must have been set through
+ // setFileAlignment(), in which case we leave it untouched
+ //
+
+ if( VAL32(0) == m_ntHeaders->OptionalHeader.FileAlignment )
+ {
+ //
+ // Figure out what file alignment to use.
+ //
+
+ unsigned RoundUpVal;
+
+ if (ExeOrDll)
+ {
+ RoundUpVal = 0x0200;
+ }
+ else
+ {
+ // Don't bother padding for objs
+ RoundUpVal = 4;
+ }
+
+ m_ntHeaders->OptionalHeader.FileAlignment = VAL32(RoundUpVal);
+ }
+
+ //
+ // Now, assign a section header & location to each section
+ //
+
+ if (ExeOrDll)
+ {
+ iUniqueSections++; // One more for .reloc
+ filePos = sizeof(IMAGE_DOS_HEADER)+sizeof(x86StubPgm) + m_ntHeadersSize;
+ }
+ else
+ {
+ filePos = sizeof(IMAGE_FILE_HEADER);
+ }
+
+ m_ntHeaders->FileHeader.NumberOfSections = VAL16(iUniqueSections);
+
+ filePos += iUniqueSections * sizeof(IMAGE_SECTION_HEADER);
+ filePos = roundUp(filePos, VAL32(m_ntHeaders->OptionalHeader.FileAlignment));
+
+ m_ntHeaders->OptionalHeader.SizeOfHeaders = VAL32(filePos);
+
+ virtualPos = roundUp(filePos, VAL32(m_ntHeaders->OptionalHeader.SectionAlignment));
+
+ if (m_hSeedFile != INVALID_HANDLE_VALUE) {
+ // We do not support relocating/sliding down the seed sections
+ if (filePos > VAL32(m_pSeedSections->VirtualAddress) ||
+ virtualPos > VAL32(m_pSeedSections->VirtualAddress))
+ return E_FAIL;
+
+ if (virtualPos < VAL32(m_pSeedSections->VirtualAddress)) {
+ virtualPos = VAL32(m_pSeedSections->VirtualAddress);
+ }
+ }
+
+ // Now finally assign RVAs to the sections
+
+ IfFailRet(linkPlaceSections(entries, iEntries));
+
+ return S_OK;
+}
+
+#undef SectionIndex
+#undef FirstEntryIndex
+
+
+class SectionRVASorter : public CQuickSort<PEWriterSection*>
+{
+ public:
+ SectionRVASorter(PEWriterSection **elts, SSIZE_T count)
+ : CQuickSort<PEWriterSection*>(elts, count) {}
+
+ int Compare(PEWriterSection **e1, PEWriterSection **e2)
+ {
+ return (*e1)->getBaseRVA() - (*e2)->getBaseRVA();
+ }
+};
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT PEWriter::fixup(CeeGenTokenMapper *pMapper)
+{
+ HRESULT hr;
+
+ bool ExeOrDll = isExeOrDll(m_ntHeaders);
+ const unsigned RoundUpVal = VAL32(m_ntHeaders->OptionalHeader.FileAlignment);
+
+ if(ExeOrDll)
+ {
+ //
+ // Apply manual relocation for entry point field
+ //
+
+ PESection *textSection;
+ IfFailRet(getSectionCreate(".text", 0, &textSection));
+
+ if (m_ntHeaders->OptionalHeader.AddressOfEntryPoint != VAL32(0))
+ m_ntHeaders->OptionalHeader.AddressOfEntryPoint = VAL32(VAL32(m_ntHeaders->OptionalHeader.AddressOfEntryPoint) + textSection->m_baseRVA);
+
+ //
+ // Apply normal relocs
+ //
+
+ IfFailRet(getSectionCreate(".reloc", sdReadOnly | IMAGE_SCN_MEM_DISCARDABLE,
+ (PESection **) &reloc));
+ reloc->m_baseRVA = virtualPos;
+ reloc->m_filePos = filePos;
+ reloc->m_header = headersEnd++;
+ strcpy_s((char *)reloc->m_header->Name, sizeof(reloc->m_header->Name),
+ ".reloc");
+ reloc->m_header->Characteristics = VAL32(reloc->m_flags);
+ reloc->m_header->VirtualAddress = VAL32(virtualPos);
+ reloc->m_header->PointerToRawData = VAL32(filePos);
+
+#ifdef _DEBUG
+ if (m_encMode)
+ printf("Applying relocs for .rdata section with RVA %x\n", m_rdataRvaBase);
+#endif
+
+ //
+ // Sort the sections by RVA
+ //
+
+ CQuickArray<PEWriterSection *> sections;
+
+ SIZE_T count = getSectCur() - getSectStart();
+ IfFailRet(sections.ReSizeNoThrow(count));
+ UINT i = 0;
+ PEWriterSection **cur;
+ for(cur = getSectStart(); cur < getSectCur(); cur++, i++)
+ sections[i] = *cur;
+
+ SectionRVASorter sorter(sections.Ptr(), sections.Size());
+
+ sorter.Sort();
+
+ PERelocSection relocSection(reloc);
+
+ cur = sections.Ptr();
+ PEWriterSection **curEnd = cur + sections.Size();
+ while (cur < curEnd)
+ {
+ IfFailRet((*cur)->applyRelocs(m_ntHeaders,
+ &relocSection,
+ pMapper,
+ m_dataRvaBase,
+ m_rdataRvaBase,
+ m_codeRvaBase));
+ cur++;
+ }
+
+ relocSection.Finish(isPE32());
+ reloc->m_header->Misc.VirtualSize = VAL32(reloc->dataLen());
+
+ // Strip the reloc section if the flag is set
+ if (m_ntHeaders->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED))
+ {
+ reloc->m_header->Misc.VirtualSize = VAL32(0);
+ }
+
+ reloc->m_header->SizeOfRawData = VAL32(roundUp(VAL32(reloc->m_header->Misc.VirtualSize), RoundUpVal));
+ reloc->m_filePad = padLen(VAL32(reloc->m_header->Misc.VirtualSize), RoundUpVal);
+ filePos += VAL32(reloc->m_header->SizeOfRawData);
+ virtualPos += roundUp(VAL32(reloc->m_header->Misc.VirtualSize),
+ VAL32(m_ntHeaders->OptionalHeader.SectionAlignment));
+
+ if (reloc->m_header->Misc.VirtualSize == VAL32(0))
+ {
+ //
+ // Omit reloc section from section list. (It will
+ // still be there but the loader won't see it - this
+ // only works because we've allocated it as the last
+ // section.)
+ //
+ m_ntHeaders->FileHeader.NumberOfSections = VAL16(VAL16(m_ntHeaders->FileHeader.NumberOfSections) - 1);
+ }
+ else
+ {
+ IMAGE_DATA_DIRECTORY * pRelocDataDirectory;
+ //
+ // Put reloc address in header
+ //
+ if (isPE32())
+ {
+ pRelocDataDirectory = &(ntHeaders32()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+ }
+ else
+ {
+ pRelocDataDirectory = &(ntHeaders64()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+ }
+
+ pRelocDataDirectory->VirtualAddress = reloc->m_header->VirtualAddress;
+ pRelocDataDirectory->Size = reloc->m_header->Misc.VirtualSize;
+ }
+
+ // compute ntHeader fields that depend on the sizes of other things
+ for(IMAGE_SECTION_HEADER *h = headersEnd-1; h >= headers; h--) { // go backwards, so first entry takes precedence
+ if (h->Characteristics & VAL32(IMAGE_SCN_CNT_CODE)) {
+ m_ntHeaders->OptionalHeader.BaseOfCode = h->VirtualAddress;
+ m_ntHeaders->OptionalHeader.SizeOfCode =
+ VAL32(VAL32(m_ntHeaders->OptionalHeader.SizeOfCode) + VAL32(h->SizeOfRawData));
+ }
+ if (h->Characteristics & VAL32(IMAGE_SCN_CNT_INITIALIZED_DATA)) {
+ if (isPE32())
+ {
+ ntHeaders32()->OptionalHeader.BaseOfData = h->VirtualAddress;
+ }
+ m_ntHeaders->OptionalHeader.SizeOfInitializedData =
+ VAL32(VAL32(m_ntHeaders->OptionalHeader.SizeOfInitializedData) + VAL32(h->SizeOfRawData));
+ }
+ if (h->Characteristics & VAL32(IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
+ m_ntHeaders->OptionalHeader.SizeOfUninitializedData =
+ VAL32(VAL32(m_ntHeaders->OptionalHeader.SizeOfUninitializedData) + VAL32(h->SizeOfRawData));
+ }
+ }
+
+ int index;
+ IMAGE_DATA_DIRECTORY * pCurDataDirectory;
+
+ // go backwards, so first entry takes precedence
+ for(cur = getSectCur()-1; getSectStart() <= cur; --cur)
+ {
+ index = (*cur)->getDirEntry();
+
+ // Is this a valid directory entry
+ if (index > 0)
+ {
+ if (isPE32())
+ {
+ _ASSERTE((unsigned)(index) < VAL32(ntHeaders32()->OptionalHeader.NumberOfRvaAndSizes));
+
+ pCurDataDirectory = &(ntHeaders32()->OptionalHeader.DataDirectory[index]);
+ }
+ else
+ {
+ _ASSERTE((unsigned)(index) < VAL32(ntHeaders64()->OptionalHeader.NumberOfRvaAndSizes));
+
+ pCurDataDirectory = &(ntHeaders64()->OptionalHeader.DataDirectory[index]);
+ }
+
+ pCurDataDirectory->VirtualAddress = VAL32((*cur)->m_baseRVA);
+ pCurDataDirectory->Size = VAL32((*cur)->dataLen());
+ }
+ }
+
+ // handle the directory entries specified using the file.
+ for (index=0; index < cEntries; index++)
+ {
+ if (pEntries[index].section)
+ {
+ PEWriterSection *section = pEntries[index].section;
+ _ASSERTE(pEntries[index].offset < section->dataLen());
+
+ if (isPE32())
+ pCurDataDirectory = &(ntHeaders32()->OptionalHeader.DataDirectory[index]);
+ else
+ pCurDataDirectory = &(ntHeaders64()->OptionalHeader.DataDirectory[index]);
+
+ pCurDataDirectory->VirtualAddress = VAL32(section->m_baseRVA + pEntries[index].offset);
+ pCurDataDirectory->Size = VAL32(pEntries[index].size);
+ }
+ }
+
+ m_ntHeaders->OptionalHeader.SizeOfImage = VAL32(virtualPos);
+ } // end if(ExeOrDll)
+ else //i.e., if OBJ
+ {
+ //
+ // Clean up note:
+ // I've cleaned up the executable linking path, but the .obj linking
+ // is still a bit strange, what with a "extra" reloc & strtab sections
+ // which are created after the linking step and get treated specially.
+ //
+ reloc = new (nothrow) PEWriterSection(".reloc",
+ sdReadOnly | IMAGE_SCN_MEM_DISCARDABLE, 0x4000, 0);
+ if(reloc == NULL) return E_OUTOFMEMORY;
+ strtab = new (nothrow) PEWriterSection(".strtab",
+ sdReadOnly | IMAGE_SCN_MEM_DISCARDABLE, 0x4000, 0); //string table (if any)
+ if(strtab == NULL) return E_OUTOFMEMORY;
+
+ DWORD* TokInSymbolTable = new (nothrow) DWORD[16386];
+ if (TokInSymbolTable == NULL) return E_OUTOFMEMORY;
+
+ m_ntHeaders->FileHeader.SizeOfOptionalHeader = 0;
+ //For each section set VirtualAddress to 0
+ PEWriterSection **cur;
+ for(cur = getSectStart(); cur < getSectCur(); cur++)
+ {
+ IMAGE_SECTION_HEADER* header = (*cur)->m_header;
+ header->VirtualAddress = VAL32(0);
+ }
+ // Go over section relocations and build the Symbol Table, use .reloc section as buffer:
+ DWORD tk=0, rva=0, NumberOfSymbols=0;
+ BOOL ToRelocTable = FALSE;
+ IMAGE_SYMBOL is;
+ IMAGE_RELOCATION ir;
+ ULONG StrTableLen = 4; //size itself only
+ char* szSymbolName = NULL;
+ char* pch;
+
+ PESection *textSection;
+ getSectionCreate(".text", 0, &textSection);
+
+ for(PESectionReloc* rcur = textSection->m_relocStart; rcur < textSection->m_relocCur; rcur++)
+ {
+ switch((int)rcur->type)
+ {
+ case 0x7FFA: // Ptr to symbol name
+#ifdef _WIN64
+ _ASSERTE(!"this is probably broken!!");
+#endif // _WIN64
+ szSymbolName = (char*)(UINT_PTR)(rcur->offset);
+ break;
+
+ case 0x7FFC: // Ptr to file name
+ TokInSymbolTable[NumberOfSymbols++] = 0;
+ memset(&is,0,sizeof(IMAGE_SYMBOL));
+ memcpy(is.N.ShortName,".file\0\0\0",8);
+ is.Value = 0;
+ is.SectionNumber = VAL16(IMAGE_SYM_DEBUG);
+ is.Type = VAL16(IMAGE_SYM_DTYPE_NULL);
+ is.StorageClass = IMAGE_SYM_CLASS_FILE;
+ is.NumberOfAuxSymbols = 1;
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,&is,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+ TokInSymbolTable[NumberOfSymbols++] = 0;
+ memset(&is,0,sizeof(IMAGE_SYMBOL));
+#ifdef _WIN64
+ _ASSERTE(!"this is probably broken!!");
+#endif // _WIN64
+ strcpy_s((char*)&is,sizeof(is),(char*)(UINT_PTR)(rcur->offset));
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,&is,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+#ifdef _WIN64
+ _ASSERTE(!"this is probably broken!!");
+#endif // _WIN64
+ delete (char*)(UINT_PTR)(rcur->offset);
+ ToRelocTable = FALSE;
+ tk = 0;
+ szSymbolName = NULL;
+ break;
+
+ case 0x7FFB: // compid value
+ TokInSymbolTable[NumberOfSymbols++] = 0;
+ memset(&is,0,sizeof(IMAGE_SYMBOL));
+ memcpy(is.N.ShortName,"@comp.id",8);
+ is.Value = VAL32(rcur->offset);
+ is.SectionNumber = VAL16(IMAGE_SYM_ABSOLUTE);
+ is.Type = VAL16(IMAGE_SYM_DTYPE_NULL);
+ is.StorageClass = IMAGE_SYM_CLASS_STATIC;
+ is.NumberOfAuxSymbols = 0;
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,&is,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+ ToRelocTable = FALSE;
+ tk = 0;
+ szSymbolName = NULL;
+ break;
+
+ case 0x7FFF: // Token value, def
+ tk = rcur->offset;
+ ToRelocTable = FALSE;
+ break;
+
+ case 0x7FFE: //Token value, ref
+ tk = rcur->offset;
+ ToRelocTable = TRUE;
+ break;
+
+ case 0x7FFD: //RVA value
+ rva = rcur->offset;
+ if(tk)
+ {
+ // Add to SymbolTable
+ DWORD i;
+ for(i = 0; (i < NumberOfSymbols)&&(tk != TokInSymbolTable[i]); i++);
+ if(i == NumberOfSymbols)
+ {
+ if(szSymbolName && *szSymbolName) // Add "extern" symbol and string table entry
+ {
+ TokInSymbolTable[NumberOfSymbols++] = 0;
+ memset(&is,0,sizeof(IMAGE_SYMBOL));
+ i++; // so reloc record (if generated) points to COM token symbol
+ is.N.Name.Long = VAL32(StrTableLen);
+ is.SectionNumber = VAL16(1); //textSection is the first one
+ is.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+ is.NumberOfAuxSymbols = 0;
+ is.Value = VAL32(rva);
+ if(TypeFromToken(tk) == mdtMethodDef)
+ {
+ is.Type = VAL16(0x20); //IMAGE_SYM_DTYPE_FUNCTION;
+ }
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,&is,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+ DWORD l = (DWORD)(strlen(szSymbolName)+1); // don't forget zero terminator!
+ if((pch = reloc->getBlock(1)))
+ memcpy(pch,szSymbolName,1);
+ else return E_OUTOFMEMORY;
+ delete szSymbolName;
+ StrTableLen += l;
+ }
+ TokInSymbolTable[NumberOfSymbols++] = tk;
+ memset(&is,0,sizeof(IMAGE_SYMBOL));
+ sprintf_s((char*)is.N.ShortName,sizeof(is.N.ShortName),"%08X",tk);
+ is.SectionNumber = VAL16(1); //textSection is the first one
+ is.StorageClass = 0x6B; //IMAGE_SYM_CLASS_COM_TOKEN;
+ is.Value = VAL32(rva);
+ if(TypeFromToken(tk) == mdtMethodDef)
+ {
+ is.Type = VAL16(0x20); //IMAGE_SYM_DTYPE_FUNCTION;
+ //is.NumberOfAuxSymbols = 1;
+ }
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,&is,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+ if(is.NumberOfAuxSymbols == 1)
+ {
+ BYTE dummy[sizeof(IMAGE_SYMBOL)];
+ memset(dummy,0,sizeof(IMAGE_SYMBOL));
+ dummy[0] = dummy[2] = 1;
+ if((pch = reloc->getBlock(sizeof(IMAGE_SYMBOL))))
+ memcpy(pch,dummy,sizeof(IMAGE_SYMBOL));
+ else return E_OUTOFMEMORY;
+ TokInSymbolTable[NumberOfSymbols++] = 0;
+ }
+ }
+ if(ToRelocTable)
+ {
+ IMAGE_SECTION_HEADER* phdr = textSection->m_header;
+ // Add to reloc table
+ ir.VirtualAddress = VAL32(rva);
+ ir.SymbolTableIndex = VAL32(i);
+ ir.Type = VAL16(IMAGE_REL_I386_SECREL);
+ if(phdr->PointerToRelocations == 0)
+ phdr->PointerToRelocations = VAL32(VAL32(phdr->PointerToRawData) + VAL32(phdr->SizeOfRawData));
+ phdr->NumberOfRelocations = VAL32(VAL32(phdr->NumberOfRelocations) + 1);
+ if((pch = reloc->getBlock(sizeof(IMAGE_RELOCATION))))
+ memcpy(pch,&is,sizeof(IMAGE_RELOCATION));
+ else return E_OUTOFMEMORY;
+ }
+ }
+ ToRelocTable = FALSE;
+ tk = 0;
+ szSymbolName = NULL;
+ break;
+
+ default:
+ break;
+ } //end switch(cur->type)
+ } // end for all relocs
+ // Add string table counter:
+ if((pch = reloc->getBlock(sizeof(ULONG))))
+ memcpy(pch,&StrTableLen,sizeof(ULONG));
+ else return E_OUTOFMEMORY;
+ reloc->m_header->Misc.VirtualSize = VAL32(reloc->dataLen());
+ if(NumberOfSymbols)
+ {
+ // recompute the actual sizes and positions of all the sections
+ filePos = roundUp(VAL16(m_ntHeaders->FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER)+
+ sizeof(IMAGE_FILE_HEADER), RoundUpVal);
+ for(cur = getSectStart(); cur < getSectCur(); cur++)
+ {
+ IMAGE_SECTION_HEADER* header = (*cur)->m_header;
+ header->Misc.VirtualSize = VAL32((*cur)->dataLen());
+ header->VirtualAddress = VAL32(0);
+ header->SizeOfRawData = VAL32(roundUp(VAL32(header->Misc.VirtualSize), RoundUpVal));
+ header->PointerToRawData = VAL32(filePos);
+
+ filePos += VAL32(header->SizeOfRawData);
+ }
+ m_ntHeaders->FileHeader.Machine = VAL16(0xC0EE); //COM+ EE
+ m_ntHeaders->FileHeader.PointerToSymbolTable = VAL32(filePos);
+ m_ntHeaders->FileHeader.NumberOfSymbols = VAL32(NumberOfSymbols);
+ filePos += roundUp(VAL32(reloc->m_header->Misc.VirtualSize)+strtab->dataLen(),RoundUpVal);
+ }
+ delete[] TokInSymbolTable;
+ } //end if OBJ
+
+ const unsigned headerOffset = (unsigned) (ExeOrDll ? sizeof(IMAGE_DOS_HEADER) + sizeof(x86StubPgm) : 0);
+
+ memset(&m_dosHeader, 0, sizeof(IMAGE_DOS_HEADER));
+ m_dosHeader.e_magic = VAL16(IMAGE_DOS_SIGNATURE);
+ m_dosHeader.e_cblp = VAL16(0x90); // bytes in last page
+ m_dosHeader.e_cp = VAL16(3); // pages in file
+ m_dosHeader.e_cparhdr = VAL16(4); // size of header in paragraphs
+ m_dosHeader.e_maxalloc = VAL16(0xFFFF); // maximum extra mem needed
+ m_dosHeader.e_sp = VAL16(0xB8); // initial SP value
+ m_dosHeader.e_lfarlc = VAL16(0x40); // file offset of relocations
+ m_dosHeader.e_lfanew = VAL32(headerOffset); // file offset of NT header!
+
+ return(S_OK); // SUCCESS
+}
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+HRESULT PEWriter::Open(__in LPCWSTR fileName)
+{
+ _ASSERTE(m_file == INVALID_HANDLE_VALUE);
+ HRESULT hr = NOERROR;
+
+ m_file = WszCreateFile(fileName,
+ GENERIC_WRITE,
+ 0, // No sharing. Was: FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if (m_file == INVALID_HANDLE_VALUE)
+ hr = HRESULT_FROM_GetLastErrorNA();
+
+ return hr;
+}
+
+HRESULT PEWriter::Seek(int offset)
+{
+ _ASSERTE(m_file != INVALID_HANDLE_VALUE);
+ if (SetFilePointer(m_file, offset, 0, FILE_BEGIN))
+ return S_OK;
+ else
+ return HRESULT_FROM_GetLastError();
+}
+
+HRESULT PEWriter::Write(const void *data, int size)
+{
+ _ASSERTE(m_file != INVALID_HANDLE_VALUE);
+
+ HRESULT hr = S_OK;
+ DWORD dwWritten = 0;
+ if (size)
+ {
+ CQuickBytes zero;
+ if (data == NULL)
+ {
+ hr = zero.ReSizeNoThrow(size);
+ if (SUCCEEDED(hr))
+ {
+ ZeroMemory(zero.Ptr(), size);
+ data = zero.Ptr();
+ }
+ }
+
+ if (WriteFile(m_file, data, size, &dwWritten, NULL))
+ {
+ _ASSERTE(dwWritten == (DWORD)size);
+ }
+ else
+ hr = HRESULT_FROM_GetLastError();
+ }
+
+ return hr;
+}
+
+HRESULT PEWriter::Pad(int align)
+{
+ DWORD offset = SetFilePointer(m_file, 0, NULL, FILE_CURRENT);
+ int pad = padLen(offset, align);
+ if (pad > 0)
+ return Write(NULL, pad);
+ else
+ return S_FALSE;
+}
+
+HRESULT PEWriter::Close()
+{
+ if (m_file == INVALID_HANDLE_VALUE)
+ return S_OK;
+
+ HRESULT hr;
+ if (CloseHandle(m_file))
+ hr = S_OK;
+ else
+ hr = HRESULT_FROM_GetLastError();
+
+ m_file = INVALID_HANDLE_VALUE;
+
+ return hr;
+}
+
+/******************************************************************/
+HRESULT PEWriter::write(__in LPCWSTR fileName) {
+
+ HRESULT hr;
+
+#ifdef ENC_DELTA_HACK
+ PathString szFileName;
+ DWORD len = WszGetEnvironmentVariable(L"COMP_ENC_EMIT", szFileName);
+ _ASSERTE(len < sizeof(szFileName));
+ if (len > 0)
+ {
+ _ASSERTE(!m_pSeedFileDecoder);
+ szFileName.Append(L".dil");
+
+ HANDLE pDelta = WszCreateFile(szFileName,
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if (pDelta == INVALID_HANDLE_VALUE) {
+ hr = HRESULT_FROM_GetLastError();
+ _ASSERTE(!"failure so open .dil file");
+ goto ErrExit;
+ }
+
+ // write the actual data
+ for (PEWriterSection **cur = getSectStart(); cur < getSectCur(); cur++) {
+ if (strcmp((*cur)->m_name, ".text") == 0)
+ {
+ hr = (*cur)->write(pDelta);
+ CloseHandle(pDelta);
+ pDelta = NULL;
+ if (FAILED(hr))
+ {
+ _ASSERT(!"failure to write to .dil file");
+ goto ErrExit;
+ }
+ break;
+ }
+ }
+ PREFIX_ASSUME(!pDelta);
+ return S_OK;
+ }
+#endif
+
+ bool ExeOrDll;
+ unsigned RoundUpVal;
+ ExeOrDll = isExeOrDll(m_ntHeaders);
+ RoundUpVal = VAL32(m_ntHeaders->OptionalHeader.FileAlignment);
+
+ IfFailGo(Open(fileName));
+
+ if(ExeOrDll)
+ {
+ // write the PE headers
+ IfFailGo(Write(&m_dosHeader, sizeof(IMAGE_DOS_HEADER)));
+ IfFailGo(Write(x86StubPgm, sizeof(x86StubPgm)));
+ IfFailGo(Write(m_ntHeaders, m_ntHeadersSize));
+ }
+ else
+ {
+ // write the object file header
+ IfFailGo(Write(&(m_ntHeaders->FileHeader),sizeof(IMAGE_FILE_HEADER)));
+ }
+
+ IfFailGo(Write(headers, (int)(sizeof(IMAGE_SECTION_HEADER)*(headersEnd-headers))));
+
+ IfFailGo(Pad(RoundUpVal));
+
+ // write the actual data
+ for (PEWriterSection **cur = getSectStart(); cur < getSectCur(); cur++) {
+ if ((*cur)->m_header != NULL) {
+ IfFailGo(Seek((*cur)->m_filePos));
+ IfFailGo((*cur)->write(m_file));
+ IfFailGo(Write(NULL, (*cur)->m_filePad));
+ }
+ }
+
+ // writes for an object file
+ if (!ExeOrDll)
+ {
+ // write the relocs section (Does nothing if relocs section is empty)
+ IfFailGo(reloc->write(m_file));
+ //write string table (obj only, empty for exe or dll)
+ IfFailGo(strtab->write(m_file));
+ int lena = padLen(VAL32(reloc->m_header->Misc.VirtualSize)+strtab->dataLen(), RoundUpVal);
+ if (lena > 0)
+ IfFailGo(Write(NULL, lena));
+ }
+
+ return Close();
+
+ ErrExit:
+ Close();
+
+ return hr;
+}
+
+HRESULT PEWriter::write(void ** ppImage)
+{
+ bool ExeOrDll = isExeOrDll(m_ntHeaders);
+ const unsigned RoundUpVal = VAL32(m_ntHeaders->OptionalHeader.FileAlignment);
+ char *pad = (char *) _alloca(RoundUpVal);
+ memset(pad, 0, RoundUpVal);
+
+ size_t lSize = filePos;
+ if (!ExeOrDll)
+ {
+ lSize += reloc->dataLen();
+ lSize += strtab->dataLen();
+ lSize += padLen(VAL32(reloc->m_header->Misc.VirtualSize)+strtab->dataLen(),
+ RoundUpVal);
+ }
+
+ // allocate the block we are handing back to the caller
+ void * pImage = (void *) ::CoTaskMemAlloc(lSize);
+ if (NULL == pImage)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // zero the memory
+ ::memset(pImage, 0, lSize);
+
+ char *pCur = (char *)pImage;
+
+ if(ExeOrDll)
+ {
+ // PE Header
+ COPY_AND_ADVANCE(pCur, &m_dosHeader, sizeof(IMAGE_DOS_HEADER));
+ COPY_AND_ADVANCE(pCur, x86StubPgm, sizeof(x86StubPgm));
+ COPY_AND_ADVANCE(pCur, m_ntHeaders, m_ntHeadersSize);
+ }
+ else
+ {
+ COPY_AND_ADVANCE(pCur, &(m_ntHeaders->FileHeader), sizeof(IMAGE_FILE_HEADER));
+ }
+
+ COPY_AND_ADVANCE(pCur, headers, sizeof(*headers)*(headersEnd - headers));
+
+ // now the sections
+ // write the actual data
+ for (PEWriterSection **cur = getSectStart(); cur < getSectCur(); cur++) {
+ if ((*cur)->m_header != NULL) {
+ unsigned len;
+ pCur = (char*)pImage + (*cur)->m_filePos;
+ len = (*cur)->writeMem((void**)&pCur);
+ _ASSERTE(len == (*cur)->dataLen());
+ COPY_AND_ADVANCE(pCur, pad, (*cur)->m_filePad);
+ }
+ }
+
+ // !!! Need to jump to the right place...
+
+ if (!ExeOrDll)
+ {
+ // now the relocs (exe, dll) or symbol table (obj) (if any)
+ // write the relocs section (Does nothing if relocs section is empty)
+ reloc->writeMem((void **)&pCur);
+
+ //write string table (obj only, empty for exe or dll)
+ strtab->writeMem((void **)&pCur);
+
+ // final pad
+ size_t len = padLen(VAL32(reloc->m_header->Misc.VirtualSize)+strtab->dataLen(), RoundUpVal);
+ if (len > 0)
+ {
+ // WARNING: macro - must enclose in curly braces
+ COPY_AND_ADVANCE(pCur, pad, len);
+ }
+ }
+
+ // make sure we wrote the exact numbmer of bytes expected
+ _ASSERTE(lSize == (size_t) (pCur - (char *)pImage));
+
+ // give pointer to memory image back to caller (who must free with ::CoTaskMemFree())
+ *ppImage = pImage;
+
+ // all done
+ return S_OK;
+}
+
+HRESULT PEWriter::getFileTimeStamp(DWORD *pTimeStamp)
+{
+ if (pTimeStamp)
+ *pTimeStamp = m_peFileTimeStamp;
+
+ return S_OK;
+}
+
+DWORD PEWriter::getImageBase32()
+{
+ _ASSERTE(isPE32());
+ return VAL32(ntHeaders32()->OptionalHeader.ImageBase);
+}
+
+UINT64 PEWriter::getImageBase64()
+{
+ _ASSERTE(!isPE32());
+ return VAL64(ntHeaders64()->OptionalHeader.ImageBase);
+}
+
+void PEWriter::setImageBase32(DWORD imageBase)
+{
+ _ASSERTE(m_hSeedFile == INVALID_HANDLE_VALUE);
+
+ _ASSERTE(isPE32());
+ ntHeaders32()->OptionalHeader.ImageBase = VAL32(imageBase);
+}
+
+void PEWriter::setImageBase64(UINT64 imageBase)
+{
+ _ASSERTE(!isPE32());
+ ntHeaders64()->OptionalHeader.ImageBase = VAL64(imageBase);
+}
+
+void PEWriter::getHeaderInfo(PIMAGE_NT_HEADERS *ppNtHeaders, PIMAGE_SECTION_HEADER *ppSections, ULONG *pNumSections)
+{
+ *ppNtHeaders = m_ntHeaders;
+ *ppSections = headers;
+ *pNumSections = (ULONG)(headersEnd - headers);
+}
diff --git a/src/dlls/mscorpe/pewriter.h b/src/dlls/mscorpe/pewriter.h
new file mode 100644
index 0000000000..3a4a4fd647
--- /dev/null
+++ b/src/dlls/mscorpe/pewriter.h
@@ -0,0 +1,337 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#ifndef PEWriter_H
+#define PEWriter_H
+
+#include <crtwrap.h>
+
+#include <windows.h>
+
+#include "ceegen.h"
+
+#include "pesectionman.h"
+
+class PEWriter;
+class PEWriterSection;
+class PEDecoder;
+struct entry;
+struct _IMAGE_SECTION_HEADER;
+
+#define SUBSECTION_ALIGN 16
+
+/***************************************************************/
+// PEWriter is derived from PESectionManager. While the base class just
+// manages the sections, PEWriter can actually write them out.
+
+class PEWriter : public PESectionMan
+{
+public:
+
+ // See ICeeFileGen.h for definition of createFlags
+ HRESULT Init(PESectionMan *pFrom, DWORD createFlags, LPCWSTR seedFileName = NULL);
+ HRESULT Cleanup();
+
+ // Finds section with given name. returns 0 if not found
+ virtual PESection* getSection(const char* name);
+
+ // Create a new section
+ virtual HRESULT newSection(const char* name, PESection **section,
+ unsigned flags=sdNone, unsigned estSize=0x10000,
+ unsigned estRelocs=0x100);
+
+ HRESULT link();
+ HRESULT fixup(CeeGenTokenMapper *pMapper);
+ HRESULT write(__in LPCWSTR fileName);
+ HRESULT write(void **ppImage);
+
+ // calling these functions is optional
+ DWORD getSectionAlignment();
+ void setSectionAlignment(DWORD);
+ DWORD getFileAlignment();
+ void setFileAlignment(DWORD);
+ DWORD getImageBase32();
+ void setImageBase32(DWORD);
+ UINT64 getImageBase64();
+ void setImageBase64(UINT64);
+ void stripRelocations(bool val); // default = false
+
+ void getHeaderInfo(PIMAGE_NT_HEADERS *ppNtHeaders, PIMAGE_SECTION_HEADER *ppSections, ULONG *pNumSections);
+
+ // these affect the charactertics in the NT file header
+ void setCharacteristics(unsigned mask);
+ void clearCharacteristics(unsigned mask);
+
+ // these affect the charactertics in the NT optional header
+ void setDllCharacteristics(unsigned mask);
+ void clearDllCharacteristics(unsigned mask);
+
+ // sets the SubSystem field in the optional header
+ void setSubsystem(unsigned subsystem, unsigned major, unsigned minor);
+
+ // specify the entry point as an offset into the text section. The
+ // method will convert into an RVA from the base
+ void setEntryPointTextOffset(unsigned entryPoint);
+
+ HRESULT setDirectoryEntry(PEWriterSection *section, ULONG entry, ULONG size, ULONG offset=0);
+
+
+ // get the RVA for the IL section
+ ULONG getIlRva();
+
+ // set the RVA for the IL section by supplying offset to the IL section
+ void setIlRva(DWORD offset);
+
+ unsigned getSubsystem();
+
+ size_t getImageBase();
+
+ void setEnCRvaBase(ULONG dataBase, ULONG rdataBase);
+
+ HRESULT getFileTimeStamp(DWORD *pTimeStamp);
+
+ IMAGE_NT_HEADERS32* ntHeaders32() { return (IMAGE_NT_HEADERS32*) m_ntHeaders; }
+ IMAGE_NT_HEADERS64* ntHeaders64() { return (IMAGE_NT_HEADERS64*) m_ntHeaders; }
+
+ bool isPE32() // true -> created a PE 32-bit PE file
+ // false -> created a PE+ 64-bit PE file
+ { return (m_ntHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)); }
+
+ bool isI386() // true -> target machine is i386
+ { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386)); }
+
+ bool isIA64() // true -> target machine is ia64
+ { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_IA64)); }
+
+ bool isAMD64() // true -> target machine is ia64
+ { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_AMD64)); }
+
+ bool isARM() // true -> target machine is ARM
+ { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_ARMNT)); }
+
+ bool createCorMainStub() // do we need the CorExeMain/CorDllMain stubs?
+ { return m_createCorMainStub; }
+
+private:
+ DWORD m_ilRVA;
+ BOOL m_encMode;
+ ULONG m_dataRvaBase;
+ ULONG m_rdataRvaBase;
+ ULONG m_codeRvaBase;
+ DWORD m_peFileTimeStamp;
+
+ HANDLE m_file;
+
+ // "Seed" file information. The new file data will be "appended" to the seed file
+ // These are valid only if m_hSeedFile is valid
+
+ HANDLE m_hSeedFile;
+ HANDLE m_hSeedFileMap;
+ PEDecoder * m_pSeedFileDecoder;
+ IMAGE_NT_HEADERS * m_pSeedFileNTHeaders;
+ unsigned m_iSeedSections;
+ IMAGE_SECTION_HEADER*m_pSeedSections;
+ IMAGE_SECTION_HEADER*m_pSeedSectionToAdd; // used only by newSection()
+
+ PEWriterSection **getSectStart() {
+ return (PEWriterSection**)sectStart;
+ }
+
+ PEWriterSection **getSectCur() {
+ return (PEWriterSection**)sectCur;
+ }
+
+ COUNT_T getSectCount() {
+ return COUNT_T(sectCur - sectStart);
+ }
+
+
+ IMAGE_DOS_HEADER m_dosHeader;
+ IMAGE_NT_HEADERS * m_ntHeaders;
+ DWORD m_ntHeadersSize; // Size of IMAGE_NT_HEADERS (not including section headers)
+
+ unsigned virtualPos;
+ unsigned filePos;
+
+ PEWriterSection * reloc;
+ PEWriterSection * strtab;
+
+ IMAGE_SECTION_HEADER *headers, *headersEnd;
+
+ struct directoryEntry {
+ PEWriterSection *section;
+ ULONG offset;
+ ULONG size;
+ };
+
+ // Directory entries in the file header
+ directoryEntry * pEntries;
+ USHORT cEntries;
+
+ bool m_createCorMainStub;
+
+ // Helpers for link()
+ HRESULT linkSortSections(entry * entries,
+ unsigned * piEntries, // OUT
+ unsigned * piUniqueSections); // OUT
+ HRESULT linkSortHeaders(entry * entries, unsigned iEntries, unsigned iUniqueSections);
+ HRESULT linkPlaceSections(entry * entries, unsigned iEntries);
+ void setSectionIndex(IMAGE_SECTION_HEADER * h, unsigned sectionIndex);
+
+ HRESULT Open(__in LPCWSTR fileName);
+ HRESULT Write(const void *data, int size);
+ HRESULT Seek(int offset);
+ HRESULT Pad(int align);
+ HRESULT Close();
+};
+
+// This class encapsulates emitting the base relocs into the
+// .reloc section of the PE file, for the case where the image
+// does not get loaded at its preferred base address.
+
+class PERelocSection
+{
+ private:
+ PEWriterSection * section;
+ unsigned relocPage;
+ unsigned relocSize;
+ DWORD * relocSizeAddr;
+ unsigned pages;
+
+#ifdef _DEBUG
+ unsigned lastRVA;
+#endif
+
+ public:
+ PERelocSection(PEWriterSection *pBaseReloc);
+ void AddBaseReloc(unsigned rva, int type, unsigned short highAdj=0);
+ void Finish(bool isPE32);
+};
+
+class PEWriterSection : public PESection {
+
+public:
+
+ PEWriterSection(const char* name, unsigned flags,
+ unsigned estSize, unsigned estRelocs)
+ : PESection(name, flags, estSize, estRelocs) {}
+
+ virtual HRESULT applyRelocs(IMAGE_NT_HEADERS * pNtHeaders,
+ PERelocSection * relocSection,
+ CeeGenTokenMapper * pTokenMapper,
+ DWORD rdataRvaBase,
+ DWORD dataRvaBase,
+ DWORD textRvaBase);
+
+ virtual HRESULT write (HANDLE file);
+ virtual unsigned writeMem (void ** pMem);
+ virtual bool isSeedSection() { return false; }
+
+};
+
+// This is for sections from the seed file. Their order needs to be maintained and
+// they need to be written to the output file.
+
+class PESeedSection : public PEWriterSection {
+
+public:
+
+ PESeedSection(PEDecoder * peDecoder, IMAGE_SECTION_HEADER * seedSection);
+
+ // PESection methods
+
+ unsigned dataLen() { return m_pSeedSectionHeader->SizeOfRawData; }
+ HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper) { return S_OK; }
+ char* getBlock(unsigned len, unsigned align) { _ASSERTE(!"PESeedSection"); return NULL; }
+ HRESULT truncate(unsigned newLen) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+ void writeSectReloc(unsigned val, CeeSection& relativeTo,
+ CeeSectionRelocType reloc,
+ CeeSectionRelocExtra *extra) { _ASSERTE(!"PESeedSection"); return; }
+ HRESULT addSectReloc(unsigned offset, CeeSection& relativeTo,
+ CeeSectionRelocType reloc,
+ CeeSectionRelocExtra *extra) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+ HRESULT addSectReloc(unsigned offset, PESection *relativeTo,
+ CeeSectionRelocType reloc,
+ CeeSectionRelocExtra *extra) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+ HRESULT addBaseReloc(unsigned offset, CeeSectionRelocType reloc,
+ CeeSectionRelocExtra *extra) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+// unsigned char *name();
+// unsigned flags();
+// unsigned getBaseRVA();
+ int getDirEntry() { _ASSERTE(!"PESeedSection"); return 0; }
+ HRESULT directoryEntry(unsigned num) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+ char * computePointer(unsigned offset) const { _ASSERTE(!"PESeedSection"); return NULL; }
+ BOOL containsPointer(__in char *ptr) const { _ASSERTE(!"PESeedSection"); return FALSE; }
+ unsigned computeOffset(__in char *ptr) const { _ASSERTE(!"PESeedSection"); return 0; }
+ HRESULT cloneInstance(PESection *destination) { _ASSERTE(!"PESeedSection"); return E_FAIL; }
+
+ // PEWriterSection
+
+ HRESULT applyRelocs(IMAGE_NT_HEADERS * pNtHeaders,
+ PERelocSection * relocSection,
+ CeeGenTokenMapper * pTokenMapper,
+ DWORD rdataRvaBase,
+ DWORD dataRvaBase,
+ DWORD textRvaBase) { return S_OK; }
+
+ HRESULT write(HANDLE file);
+ unsigned writeMem(void ** pMem);
+ bool isSeedSection() { return true; }
+
+protected:
+
+ PEDecoder * m_pSeedFileDecoder;
+ IMAGE_SECTION_HEADER * m_pSeedSectionHeader;
+
+};
+
+inline DWORD PEWriter::getSectionAlignment() {
+ return VAL32(m_ntHeaders->OptionalHeader.FileAlignment);
+}
+
+inline void PEWriter::setSectionAlignment(DWORD SectionAlignment) {
+
+ _ASSERTE(m_hSeedFile == INVALID_HANDLE_VALUE);
+ m_ntHeaders->OptionalHeader.SectionAlignment = VAL32(SectionAlignment);
+}
+
+inline DWORD PEWriter::getFileAlignment() {
+ return m_ntHeaders->OptionalHeader.FileAlignment;
+}
+
+inline void PEWriter::setFileAlignment(DWORD fileAlignment) {
+ _ASSERTE(m_hSeedFile == INVALID_HANDLE_VALUE);
+ m_ntHeaders->OptionalHeader.FileAlignment = VAL32(fileAlignment);
+}
+
+inline unsigned PEWriter::getSubsystem() {
+ return VAL16(m_ntHeaders->OptionalHeader.Subsystem);
+}
+
+inline void PEWriter::setSubsystem(unsigned subsystem, unsigned major, unsigned minor) {
+ m_ntHeaders->OptionalHeader.Subsystem = VAL16(subsystem);
+ m_ntHeaders->OptionalHeader.MajorSubsystemVersion = VAL16(major);
+ m_ntHeaders->OptionalHeader.MinorSubsystemVersion = VAL16(minor);
+}
+
+inline void PEWriter::setCharacteristics(unsigned mask) {
+ m_ntHeaders->FileHeader.Characteristics |= VAL16(mask);
+}
+
+inline void PEWriter::clearCharacteristics(unsigned mask) {
+ m_ntHeaders->FileHeader.Characteristics &= VAL16(~mask);
+}
+
+inline void PEWriter::setDllCharacteristics(unsigned mask) {
+ m_ntHeaders->OptionalHeader.DllCharacteristics |= VAL16(mask);
+}
+
+inline void PEWriter::clearDllCharacteristics(unsigned mask) {
+ m_ntHeaders->OptionalHeader.DllCharacteristics &= VAL16(~mask);
+}
+
+inline void PEWriter::setEntryPointTextOffset(unsigned offset) {
+ m_ntHeaders->OptionalHeader.AddressOfEntryPoint = VAL32(offset);
+}
+
+#endif
diff --git a/src/dlls/mscorpe/stdafx.cpp b/src/dlls/mscorpe/stdafx.cpp
new file mode 100644
index 0000000000..6321e11d12
--- /dev/null
+++ b/src/dlls/mscorpe/stdafx.cpp
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// stdafx.cpp
+//
+// Host for precompiled header.
+//
+//*****************************************************************************
+#include "stdafx.h" // Precompiled header key.
diff --git a/src/dlls/mscorpe/stdafx.h b/src/dlls/mscorpe/stdafx.h
new file mode 100644
index 0000000000..c97b552cdd
--- /dev/null
+++ b/src/dlls/mscorpe/stdafx.h
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// stdafx.h
+//
+// Common include file for utility code.
+//*****************************************************************************
+#include <stdlib.h> // for qsort
+#include <windows.h>
+#include <time.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#define FEATURE_NO_HOST // Do not use host interface
+#include <utilcode.h>
+
+#include <corpriv.h>
+
+#include "pewriter.h"
+#include "ceegen.h"
+#include "ceefilegenwriter.h"
+#include "ceesectionstring.h"
diff --git a/src/dlls/mscorpe/stubs.h b/src/dlls/mscorpe/stubs.h
new file mode 100644
index 0000000000..70ebed4d14
--- /dev/null
+++ b/src/dlls/mscorpe/stubs.h
@@ -0,0 +1,169 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// Stubs.h
+//
+// This file contains a template for the default entry point stubs of a COM+
+// IL only program. One can emit these stubs (with some fix-ups) and make
+// the code supplied the entry point value for the image. The fix-ups will
+// in turn cause mscoree.dll to be loaded and the correct entry point to be
+// called.
+//
+// Note: Although these stubs contain x86 specific code, they are used
+// for all platforms
+//
+//*****************************************************************************
+#ifndef __STUBS_H__
+#define __STUBS_H__
+
+//*****************************************************************************
+// This stub is designed for a x86 Windows application. It will call the
+// _CorExeMain function in mscoree.dll. This entry point will in turn load
+// and run the IL program.
+//
+// jump _CorExeMain();
+//
+// The code jumps to the imported function _CorExeMain using the iat.
+// The address in the template is address of the iat entry which is
+// fixed up by the loader when the image is paged in.
+//*****************************************************************************
+
+SELECTANY const BYTE ExeMainX86Template[] =
+{
+ // Jump through IAT to _CorExeMain
+ 0xFF, 0x25, // jmp [iat:_CorDllMain entry]
+ 0x00, 0x00, 0x00, 0x00, // address to replace
+
+};
+
+#define ExeMainX86TemplateSize sizeof(ExeMainX86Template)
+#define CorExeMainX86IATOffset 2
+
+//*****************************************************************************
+// This stub is designed for a x86 Windows application. It will call the
+// _CorDllMain function in mscoree.dll with with the base entry point for
+// the loaded DLL. This entry point will in turn load and run the IL program.
+//
+// jump _CorDllMain
+//
+// The code jumps to the imported function _CorExeMain using the iat.
+// The address in the template is address of the iat entry which is
+// fixed up by the loader when the image is paged in.
+//*****************************************************************************
+
+SELECTANY const BYTE DllMainX86Template[] =
+{
+ // Jump through IAT to CorDllMain
+ 0xFF, 0x25, // jmp [iat:_CorDllMain entry]
+ 0x00, 0x00, 0x00, 0x00, // address to replace
+};
+
+#define DllMainX86TemplateSize sizeof(DllMainX86Template)
+#define CorDllMainX86IATOffset 2
+
+//*****************************************************************************
+// This stub is designed for a AMD64 Windows application. It will call the
+// _CorExeMain function in mscoree.dll. This entry point will in turn load
+// and run the IL program.
+//
+// mov rax, _CorExeMain();
+// jmp [rax]
+//
+// The code jumps to the imported function _CorExeMain using the iat.
+// The address in the template is address of the iat entry which is
+// fixed up by the loader when the image is paged in.
+//*****************************************************************************
+
+SELECTANY const BYTE ExeMainAMD64Template[] =
+{
+ // Jump through IAT to _CorExeMain
+ 0x48, 0xA1, // rex.w rex.b mov rax,[following address]
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//address of iat:_CorExeMain entry
+ 0xFF, 0xE0 // jmp [rax]
+};
+
+#define ExeMainAMD64TemplateSize sizeof(ExeMainAMD64Template)
+#define CorExeMainAMD64IATOffset 2
+
+//*****************************************************************************
+// This stub is designed for a AMD64 Windows application. It will call the
+// _CorDllMain function in mscoree.dll with with the base entry point for
+// the loaded DLL. This entry point will in turn load and run the IL program.
+//
+// mov rax, _CorDllMain();
+// jmp [rax]
+//
+// The code jumps to the imported function _CorDllMain using the iat.
+// The address in the template is address of the iat entry which is
+// fixed up by the loader when the image is paged in.
+//*****************************************************************************
+
+SELECTANY const BYTE DllMainAMD64Template[] =
+{
+ // Jump through IAT to CorDllMain
+ 0x48, 0xA1, // rex.w rex.b mov rax,[following address]
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//address of iat:_CorDllMain entry
+ 0xFF, 0xE0 // jmp [rax]
+};
+
+#define DllMainAMD64TemplateSize sizeof(DllMainAMD64Template)
+#define CorDllMainAMD64IATOffset 2
+
+//*****************************************************************************
+// This stub is designed for an ia64 Windows application. It will call the
+// _CorExeMain function in mscoree.dll. This entry point will in turn load
+// and run the IL program.
+//
+// jump _CorExeMain();
+//
+// The code jumps to the imported function _CorExeMain using the iat.
+// We set the value of gp to point at the iat table entry for _CorExeMain
+//*****************************************************************************
+
+SELECTANY const BYTE ExeMainIA64Template[] =
+{
+ // ld8 r9 = [gp] ;;
+ // ld8 r10 = [r9],8
+ // nop.i ;;
+ // ld8 gp = [r9]
+ // mov b6 = r10
+ // br.cond.sptk.few b6
+ //
+ 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40,
+ 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50,
+ 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
+};
+
+#define ExeMainIA64TemplateSize sizeof(ExeMainIA64Template)
+
+//*****************************************************************************
+// This stub is designed for an ia64 Windows application. It will call the
+// _CorDllMain function in mscoree.dll with with the base entry point for
+// the loaded DLL. This entry point will in turn load and run the IL program.
+//
+// jump _CorDllMain
+//
+// The code jumps to the imported function _CorExeMain using the iat.
+// We set the value of gp to point at the iat table entry for _CorExeMain
+//*****************************************************************************
+
+SELECTANY const BYTE DllMainIA64Template[] =
+{
+ // ld8 r9 = [gp] ;;
+ // ld8 r10 = [r9],8
+ // nop.i ;;
+ // ld8 gp = [r9]
+ // mov b6 = r10
+ // br.cond.sptk.few b6
+ //
+ 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40,
+ 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50,
+ 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
+};
+
+#define DllMainIA64TemplateSize sizeof(DllMainIA64Template)
+
+#endif // __STUBS_H__
diff --git a/src/dlls/mscorpe/utilcodeinit.cpp b/src/dlls/mscorpe/utilcodeinit.cpp
new file mode 100644
index 0000000000..0e9fab9860
--- /dev/null
+++ b/src/dlls/mscorpe/utilcodeinit.cpp
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "stdafx.h"
+#include <utilcode.h>
+
+EXTERN_C void __stdcall InitializeSxS(CoreClrCallbacks const & callbacks)
+{
+ InitUtilcode(callbacks);
+}