summaryrefslogtreecommitdiff
path: root/src/dlls/mscorpe/pewriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dlls/mscorpe/pewriter.cpp')
-rw-r--r--src/dlls/mscorpe/pewriter.cpp2401
1 files changed, 2401 insertions, 0 deletions
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);
+}