size_t OffsetWithinPage(off_t addr)
{
- return addr & (GetVirtualPageSize() - 1);
+ // use here getpagesize because GetVirtualPageSize needs PAL
+ _ASSERTE(GetVirtualPageSize() == (size_t)getpagesize());
+ return addr & ((size_t)getpagesize() - 1);
}
static size_t RoundToPage(size_t size, off_t offset)
return result;
}
+static PAL_ERROR
+MAPRecordMapping(
+ IPalObject *pMappingObject,
+ void *pPEBaseAddress,
+ void *addr,
+ size_t len,
+ int prot,
+ off_t offset
+ )
+{
+ return MAPRecordMapping(pMappingObject, pPEBaseAddress, static_cast<char *>(addr) - OffsetWithinPage(offset), len, prot);
+}
+
// Do the actual mmap() call, and record the mapping in the MappedViewList list.
// This call assumes the mapping_critsec has already been taken.
static PAL_ERROR
}
/*++
+ MAPUnmapPreloadedPEFile -
+
+ Unmap a PE file
+
+Parameters:
+ IN addr - address of mapped file
+ IN size - virtual size
+
+Return value:
+ returns TRUE if successful, FALSE otherwise
+--*/
+
+BOOL MAPUnmapPreloadedPEFile(void *addr, size_t size)
+{
+ if (munmap(addr, size) == -1)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Do the actual mprotect call with aligned lpAddress
+static bool MAPProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, SIZE_T dwPageSize)
+{
+ UINT_PTR StartBoundary = (UINT_PTR)ALIGN_DOWN(lpAddress, dwPageSize);
+ SIZE_T MemSize = ALIGN_UP((UINT_PTR)lpAddress + dwSize, dwPageSize) - StartBoundary;
+ INT nProtect = W32toUnixAccessControl(flNewProtect);
+ if (nProtect == 0)
+ {
+ return false;
+ }
+
+ return mprotect((void *)StartBoundary, MemSize, nProtect) == 0;
+}
+
+static IMAGE_SECTION_HEADER *RvaToSection(void *base, DWORD rva)
+{
+ IMAGE_SECTION_HEADER *pSection = NULL;
+ IMAGE_NT_HEADERS *imageNTHeaders = (IMAGE_NT_HEADERS *) ((uintptr_t)base + VAL32(((IMAGE_DOS_HEADER *) base)->e_lfanew));
+ IMAGE_SECTION_HEADER *firstSection = (IMAGE_SECTION_HEADER *)
+ ((uintptr_t)(imageNTHeaders) +
+ offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
+ VAL16(imageNTHeaders->FileHeader.SizeOfOptionalHeader));
+
+ IMAGE_SECTION_HEADER *section = firstSection;
+ IMAGE_SECTION_HEADER *sectionEnd = section + VAL16(imageNTHeaders->FileHeader.NumberOfSections);
+
+ while (section < sectionEnd)
+ {
+ UINT value = (UINT)VAL32(section->Misc.VirtualSize);
+ UINT alignment = (UINT)VAL32(imageNTHeaders->OptionalHeader.SectionAlignment);
+ if (rva < (VAL32(section->VirtualAddress) + ALIGN_UP(value, alignment)))
+ {
+ if (rva < VAL32(section->VirtualAddress))
+ {
+ break;
+ }
+ else
+ {
+ pSection = section;
+ break;
+ }
+ }
+
+ section++;
+ }
+
+ return pSection;
+}
+
+static DWORD SectionCharacteristicsToPageProtection(UINT characteristics)
+{
+ DWORD pageProtection;
+
+ if ((characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
+ {
+ if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
+ {
+ pageProtection = PAGE_EXECUTE_READWRITE;
+ }
+ else
+ {
+ pageProtection = PAGE_READWRITE;
+ }
+ }
+ else
+ {
+ if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
+ {
+ pageProtection = PAGE_EXECUTE_READ;
+ }
+ else
+ {
+ pageProtection = PAGE_READONLY;
+ }
+ }
+
+ return pageProtection;
+}
+
+/*++
+ MAPApplyBaseRelocationsPreloadedPEFile -
+
+ Apply base relocations to preloaded image
+
+ Note:
+ This function must be an exact copy of PEImageLayout::ApplyBaseRelocations with some other functions inlined.
+ The main idea is that MAPApplyBaseRelocationsPreloadedPEFile doesn't use PAL,
+ because it is invoked before PAL is initialized.
+ Asserts and ThrowLastError are converted to if(isfalse)return;.
+
+ Currently, next functions are inlined:
+ - PEDecoder::GetBase
+ - PEDecodor::GetPreferredBase
+ - PEDecoder::Has32BitNTHeaders
+ - PEDecoder::GetNTHeaders32
+ - PEDecoder::GetNTHeaders64
+ - PEDecoder::FindNTHeaders
+ - PEDecoder::GetDirectoryEntryData
+ - PEDecoder::GetDirectoryEntry
+ - PEDecoder::GetDirectoryData
+ - PEDecoder::GetRvaData
+ - ClrVirtualProtect
+ - GetThumb2Mov32
+ - PutThumb2Mov32
+ - GetThumb2Imm16
+ - PutThumb2Imm16
+ - SectionCharacteristicsToPageProtection
+ - PEDecoder::RvaToSection
+ - PEDecoder::FindFirstSection
+
+Parameters:
+ IN mappedImage - base address of preloaded image
+ IN virtualSize - virtual size of preloaded image
+
+Return value:
+ true - if relocations were applied successfully
+ false - otherwise
+--*/
+
+bool
+MAPApplyBaseRelocationsPreloadedPEFile(void *mappedImage, size_t virtualSize)
+{
+ void *base = mappedImage;
+ void *preferredBase;
+ IMAGE_NT_HEADERS *imageNTHeaders = (IMAGE_NT_HEADERS *) ((uintptr_t)base + VAL32(((IMAGE_DOS_HEADER *) base)->e_lfanew));
+ bool has32BitNTHeaders = imageNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
+ if (has32BitNTHeaders)
+ {
+ preferredBase = (void *) (SIZE_T) VAL32(((IMAGE_NT_HEADERS32 *)imageNTHeaders)->OptionalHeader.ImageBase);
+ }
+ else
+ {
+ preferredBase = (void *) (SIZE_T) VAL64(((IMAGE_NT_HEADERS64 *)imageNTHeaders)->OptionalHeader.ImageBase);
+ }
+
+ SSIZE_T delta = (SIZE_T) base - (SIZE_T) preferredBase;
+
+ // Nothing to do - image is loaded at preferred base
+ if (delta == 0)
+ return true;
+
+ IMAGE_DATA_DIRECTORY *pDir;
+ if (has32BitNTHeaders)
+ {
+ pDir = (IMAGE_DATA_DIRECTORY *) ((uintptr_t)((IMAGE_NT_HEADERS32 *)imageNTHeaders) +
+ offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory) +
+ IMAGE_DIRECTORY_ENTRY_BASERELOC * sizeof(IMAGE_DATA_DIRECTORY));
+ }
+ else
+ {
+ pDir = (IMAGE_DATA_DIRECTORY *) ((uintptr_t)((IMAGE_NT_HEADERS64 *)imageNTHeaders) +
+ offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory) +
+ IMAGE_DIRECTORY_ENTRY_BASERELOC * sizeof(IMAGE_DATA_DIRECTORY));
+ }
+
+ UINT32 dirSize = VAL32(pDir->Size);
+ DWORD rva = VAL32(pDir->VirtualAddress);
+ uintptr_t dir = (uintptr_t) (rva == 0 ? (uintptr_t)NULL : (uintptr_t)base + rva);
+
+ // Minimize number of calls to VirtualProtect by keeping a whole section unprotected at a time.
+ BYTE * pWriteableRegion = NULL;
+ SIZE_T cbWriteableRegion = 0;
+ DWORD dwOldProtection = 0;
+
+ const SIZE_T cbPageSize = 4096;
+
+ UINT32 dirPos = 0;
+
+ while (dirPos < dirSize)
+ {
+ IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)(dir + dirPos);
+
+ UINT32 fixupsSize = VAL32(r->SizeOfBlock);
+
+ USHORT *fixups = (USHORT *) (r + 1);
+
+ if (fixupsSize <= sizeof(IMAGE_BASE_RELOCATION)
+ || (fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) % 2 != 0)
+ {
+ return false;
+ }
+
+ UINT32 fixupsCount = (fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) / 2;
+
+ if ((BYTE *)(fixups + fixupsCount) > (BYTE *)(dir + dirSize))
+ {
+ return false;
+ }
+
+ DWORD rva = VAL32(r->VirtualAddress);
+
+ BYTE * pageAddress = (BYTE *) base + rva;
+
+ // Check whether the page is outside the unprotected region
+ if ((SIZE_T)(pageAddress - pWriteableRegion) >= cbWriteableRegion)
+ {
+ // Restore the protection
+ if (dwOldProtection != 0)
+ {
+ BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
+
+ if (!MAPProtect(pWriteableRegion, cbWriteableRegion, dwOldProtection, cbPageSize))
+ {
+ return false;
+ }
+
+ dwOldProtection = 0;
+ }
+
+ USHORT fixup = VAL16(fixups[0]);
+
+ IMAGE_SECTION_HEADER *pSection = RvaToSection(base, rva + (fixup & 0xfff));
+ if (pSection == NULL)
+ {
+ return false;
+ }
+
+ DWORD rvaSect = VAL32(pSection->VirtualAddress);
+ pWriteableRegion = (BYTE*) (rvaSect == 0 ? (uintptr_t)NULL : (uintptr_t)base + rvaSect);
+ cbWriteableRegion = VAL32(pSection->SizeOfRawData);
+
+ // Unprotect the section if it is not writable
+ if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0))
+ {
+ DWORD dwNewProtection = PAGE_READWRITE;
+ if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0))
+ {
+ // On SELinux, we cannot change protection that doesn't have execute access rights
+ // to one that has it, so we need to set the protection to RWX instead of RW
+ dwNewProtection = PAGE_EXECUTE_READWRITE;
+ }
+
+ if (!MAPProtect(pWriteableRegion, cbWriteableRegion, dwNewProtection, cbPageSize))
+ {
+ return false;
+ }
+
+ if ((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_READ)) == 0)
+ {
+ return false;
+ }
+
+ dwOldProtection = SectionCharacteristicsToPageProtection(pSection->Characteristics);
+ }
+ }
+
+ for (UINT32 fixupIndex = 0; fixupIndex < fixupsCount; fixupIndex++)
+ {
+ USHORT fixup = VAL16(fixups[fixupIndex]);
+
+ BYTE * address = pageAddress + (fixup & 0xfff);
+
+#ifdef TARGET_64BIT
+#define IMAGE_REL_BASED_PTR IMAGE_REL_BASED_DIR64
+#else // !TARGET_64BIT
+#define IMAGE_REL_BASED_PTR IMAGE_REL_BASED_HIGHLOW
+#endif // !TARGET_64BIT
+ switch (fixup>>12)
+ {
+ case IMAGE_REL_BASED_PTR:
+ {
+ *(uintptr_t *)address += delta;
+ break;
+ }
+
+#ifdef TARGET_ARM
+ case IMAGE_REL_BASED_THUMB_MOV32:
+ {
+ // Make sure we are decoding movw/movt sequence
+ UINT16 *p = (UINT16 *)address;
+ if ((*(p+0) & 0xFBF0) != 0xF240 || (*(p+2) & 0xFBF0) != 0xF2C0)
+ {
+ return false;
+ }
+
+#define GET_THUMB2_IMM16(p) ((((p)[0] << 12) & 0xf000) | \
+ (((p)[0] << 1) & 0x0800) | \
+ (((p)[1] >> 4) & 0x0700) | \
+ (((p)[1] >> 0) & 0x00ff))
+#define PUT_THUMB2_IMM16(p,imm16) \
+ { \
+ USHORT Opcode0 = (p)[0]; \
+ USHORT Opcode1 = (p)[1]; \
+ Opcode0 &= ~((0xf000 >> 12) | (0x0800 >> 1)); \
+ Opcode1 &= ~((0x0700 << 4) | (0x00ff << 0)); \
+ Opcode0 |= ((imm16) & 0xf000) >> 12; \
+ Opcode0 |= ((imm16) & 0x0800) >> 1; \
+ Opcode1 |= ((imm16) & 0x0700) << 4; \
+ Opcode1 |= ((imm16) & 0x00ff) << 0; \
+ (p)[0] = Opcode0; \
+ (p)[1] = Opcode1; \
+ }
+
+ UINT32 imm32 = (UINT32)GET_THUMB2_IMM16(p) + ((UINT32)GET_THUMB2_IMM16(p + 2) << 16) + delta;
+
+ PUT_THUMB2_IMM16(p, (UINT16)imm32);
+ PUT_THUMB2_IMM16(p + 2, (UINT16)(imm32 >> 16));
+
+#undef GET_THUMB2_IMM16
+#undef PUT_THUMB2_IMM16
+
+ break;
+ }
+#endif
+
+ case IMAGE_REL_BASED_ABSOLUTE:
+ {
+ //no adjustment
+ break;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+#undef IMAGE_REL_BASED_PTR
+ }
+
+ dirPos += fixupsSize;
+ }
+ if (dirSize != dirPos)
+ {
+ return false;
+ }
+
+ if (dwOldProtection != 0)
+ {
+ if (!MAPProtect(pWriteableRegion, cbWriteableRegion, dwOldProtection, cbPageSize))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*++
MAPMapPEFile -
Map a PE format file into memory like Windows LoadLibrary() would do.
Doesn't apply base relocations if the function is relocated.
+ There are two scenarios:
+
+ - image could be preloaded and then MAPMapPEFile is called for it
+ - image is loaded with MAPMapPEFile
+
+ In the first scenario, hFile and lpPreloadedBase are supposed to be NULL, and szPath and size - non-NULL.
+ In the second scenario, hFile and lpPreloadedBase are supposed to be non-NULL, and szPath and size - NULL.
+
+ See coreclr_preload_assembly for further details.
+
Parameters:
IN hFile - file to map
IN offset - offset within hFile where the PE "file" is located
+ IN szPath - path to mapped file
+ OUT size - mapped virtual size
+ IN lpPreloadedBase - previously loaded base
Return value:
non-NULL - the base address of the mapped image
NULL - error, with last error set.
--*/
-void * MAPMapPEFile(HANDLE hFile, off_t offset)
+void * MAPMapPEFile(HANDLE hFile, off_t offset, LPCSTR szPath, SIZE_T *size, LPVOID lpPreloadedBase)
{
PAL_ERROR palError = 0;
IPalObject *pFileObject = NULL;
IDataLock *pLocalDataLock = NULL;
CFileProcessLocalData *pLocalData = NULL;
- CPalThread *pThread = InternalGetCurrentThread();
- void * loadedBase = NULL;
+ CPalThread *pThread;
+
+ bool doPreload = hFile == NULL;
+
IMAGE_DOS_HEADER * loadedHeader = NULL;
void * retval;
#if _DEBUG
bool forceRelocs = false;
char* envVar;
#endif
+
+ size_t headerSize;
+ void * loadedBase = lpPreloadedBase;
+ bool isPreloaded = loadedBase != NULL;
+ bool arePreloadParametersCorrect = lpPreloadedBase == NULL && hFile == NULL && szPath != NULL && size != NULL && offset == 0;
+ bool areNonPreloadParametersCorrect = hFile != NULL && szPath == NULL && size == NULL;
+ bool areParametersCorrect = (doPreload && arePreloadParametersCorrect)
+ || (!doPreload && areNonPreloadParametersCorrect);
+
SIZE_T reserveSize = 0;
bool forceOveralign = false;
int readWriteFlags = MAP_FILE|MAP_PRIVATE|MAP_FIXED;
int readOnlyFlags = readWriteFlags;
- ENTRY("MAPMapPEFile (hFile=%p offset=%zx)\n", hFile, offset);
+ int fd;
- //Step 0: Verify values, find internal pal data structures.
- if (INVALID_HANDLE_VALUE == hFile)
+ if (!areParametersCorrect
+ || (isPreloaded && offset != 0))
{
- ERROR_(LOADER)( "Invalid file handle\n" );
- palError = ERROR_INVALID_HANDLE;
+ palError = ERROR_INVALID_PARAMETER;
goto done;
}
- palError = g_pObjectManager->ReferenceObjectByHandle(
- pThread,
- hFile,
- &aotFile,
- &pFileObject
- );
- if (NO_ERROR != palError)
+ if (doPreload)
{
- ERROR_(LOADER)( "ReferenceObjectByHandle failed\n" );
- goto done;
- }
+ fd = InternalOpen(szPath, O_RDONLY);
- palError = pFileObject->GetProcessLocalData(
- pThread,
- ReadLock,
- &pLocalDataLock,
- reinterpret_cast<void**>(&pLocalData)
- );
- if (NO_ERROR != palError)
+ if (fd == -1)
+ {
+ palError = ERROR_INVALID_NAME;
+ goto done;
+ }
+ }
+ else
{
- ERROR_(LOADER)( "GetProcessLocalData failed\n" );
- goto done;
+ pThread = InternalGetCurrentThread();
+
+ ENTRY("MAPMapPEFile (hFile=%p offset=%zx)\n", hFile, offset);
+
+ //Step 0: Verify values, find internal pal data structures.
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR_(LOADER)( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ &pFileObject
+ );
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "ReferenceObjectByHandle failed\n" );
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "GetProcessLocalData failed\n" );
+ goto done;
+ }
+
+ fd = pLocalData->unix_fd;
}
- int fd;
- fd = pLocalData->unix_fd;
//Step 1: Read the PE headers and reserve enough space for the whole image somewhere.
IMAGE_DOS_HEADER dosHeader;
IMAGE_NT_HEADERS ntHeader;
}
#if _DEBUG
- envVar = EnvironGetenv("PAL_ForceRelocs");
- if (envVar)
+ if (!doPreload && !isPreloaded)
{
- if (strlen(envVar) > 0)
+ envVar = EnvironGetenv("PAL_ForceRelocs");
+ if (envVar)
{
- forceRelocs = true;
- TRACE_(LOADER)("Forcing rebase of image\n");
- }
+ if (strlen(envVar) > 0)
+ {
+ forceRelocs = true;
+ TRACE_(LOADER)("Forcing rebase of image\n");
+ }
- free(envVar);
+ free(envVar);
+ }
}
void * pForceRelocBase;
pForceRelocBase = NULL;
- if (forceRelocs)
+ if (!doPreload && !isPreloaded && forceRelocs)
{
//if we're forcing relocs, create an anonymous mapping at the preferred base. Only create the
//mapping if we can create it at the specified address.
// and each of the sections, as well as all the space between them that we give PROT_NONE protections.
// We're going to start adding mappings to the mapping list, so take the critical section
- InternalEnterCriticalSection(pThread, &mapping_critsec);
+ if (!doPreload)
+ {
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+ }
reserveSize = RoundToPage(virtualSize, offset);
- if ((ntHeader.OptionalHeader.SectionAlignment) > GetVirtualPageSize())
+ // use here getpagesize because GetVirtualPageSize needs PAL
+ _ASSERTE(GetVirtualPageSize() == (size_t)getpagesize());
+ if ((ntHeader.OptionalHeader.SectionAlignment) > (size_t)getpagesize())
{
+ if (doPreload || isPreloaded)
+ {
+ // Preload doesn't support such files
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+
reserveSize += ntHeader.OptionalHeader.SectionAlignment;
forceOveralign = true;
}
// more efficient code (by avoiding usage of jump stubs). Alignment to a 64 KB granularity should
// not be necessary (alignment to page size should be sufficient), but see
// ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done.
- loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(reserveSize, VIRTUAL_64KB));
+ if (!doPreload && loadedBase == NULL)
+ {
+ loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(reserveSize, VIRTUAL_64KB));
+ }
#endif // HOST_64BIT
- if (loadedBase == NULL)
+ if (doPreload || loadedBase == NULL)
{
void *usedBaseAddr = NULL;
#ifdef FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION
// All subsequent mappings of the PE file will be in the range [loadedBase, loadedBase + virtualSize)
#if _DEBUG
- if (forceRelocs)
- {
- _ASSERTE(((SIZE_T)loadedBase) != preferredBase);
- munmap(pForceRelocBase, GetVirtualPageSize()); // now that we've forced relocation, let the original address mapping go
- }
- if (((SIZE_T)loadedBase) != preferredBase)
+ if (!doPreload && !isPreloaded)
{
- TRACE_(LOADER)("Image rebased from preferredBase of %p to loadedBase of %p\n", preferredBase, loadedBase);
- }
- else
- {
- TRACE_(LOADER)("Image loaded at preferred base %p\n", loadedBase);
+ if (forceRelocs)
+ {
+ _ASSERTE(((SIZE_T)loadedBase) != preferredBase);
+ munmap(pForceRelocBase, GetVirtualPageSize()); // now that we've forced relocation, let the original address mapping go
+ }
+ if (((SIZE_T)loadedBase) != preferredBase)
+ {
+ TRACE_(LOADER)("Image rebased from preferredBase of %p to loadedBase of %p\n", preferredBase, loadedBase);
+ }
+ else
+ {
+ TRACE_(LOADER)("Image loaded at preferred base %p\n", loadedBase);
+ }
}
#endif // _DEBUG
- size_t headerSize;
- headerSize = GetVirtualPageSize(); // if there are lots of sections, this could be wrong
+ // use here getpagesize because GetVirtualPageSize needs PAL
+ _ASSERTE(GetVirtualPageSize() == (size_t)getpagesize());
+ headerSize = (size_t)getpagesize(); // if there are lots of sections, this could be wrong
if (forceOveralign)
{
+ _ASSERTE(!doPreload && !isPreloaded);
+
loadedBase = ALIGN_UP(loadedBase, ntHeader.OptionalHeader.SectionAlignment);
headerSize = ntHeader.OptionalHeader.SectionAlignment;
char *mapAsShared = EnvironGetenv("PAL_MAP_READONLY_PE_HUGE_PAGE_AS_SHARED");
// initialize this on a separate line to prevent a false error about the goto done; jumping over this
loadedHeaderBase = NULL;
- _ASSERTE(OffsetWithinPage(offset) == OffsetWithinPage((off_t)loadedHeader));
- palError = MAPmmapAndRecord(pFileObject, loadedBase,
- (LPVOID)loadedHeader, headerSize, PROT_READ, readOnlyFlags, fd, offset,
- &loadedHeaderBase);
- if (NO_ERROR != palError)
+ off_t adjust;
+ // initialize this on a separate line to prevent a false error about the goto done; jumping over this
+ adjust = OffsetWithinPage(offset);
+ _ASSERTE(adjust == OffsetWithinPage((off_t)loadedHeader));
+
+ if (!doPreload)
{
- ERROR_(LOADER)( "mmap of PE header failed\n" );
- goto doneReleaseMappingCriticalSection;
+ if (!isPreloaded)
+ {
+ palError = MAPmmapAndRecord(pFileObject, loadedBase,
+ (LPVOID)loadedHeader, headerSize, PROT_READ, readOnlyFlags, fd, offset,
+ &loadedHeaderBase);
+ }
+ else
+ {
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ (LPVOID)loadedHeader,
+ headerSize,
+ PROT_READ,
+ offset);
+ loadedHeaderBase = (LPVOID) (static_cast<char *>((LPVOID)loadedHeader) - adjust);
+ }
+
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "mmap of PE header failed\n" );
+ goto doneReleaseMappingCriticalSection;
+ }
+
+ TRACE_(LOADER)("PE header loaded @ %p\n", loadedHeader);
+ _ASSERTE(loadedHeaderBase == loadedBase); // we already preallocated the space, and we used MAP_FIXED, so we should have gotten this address
+ }
+ else
+ {
+ LPVOID base = (LPVOID) (static_cast<char *>((LPVOID)loadedHeader) - adjust);
+ loadedHeaderBase = (LPVOID) mmap(base, headerSize + adjust, PROT_READ, readOnlyFlags, fd, offset - adjust);
+
+ if (loadedHeaderBase == MAP_FAILED)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+ if (base != loadedHeaderBase)
+ {
+ munmap(loadedHeaderBase, headerSize + adjust);
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
}
- TRACE_(LOADER)("PE header loaded @ %p\n", loadedHeader);
- _ASSERTE(loadedHeaderBase == loadedBase); // we already preallocated the space, and we used MAP_FIXED, so we should have gotten this address
IMAGE_SECTION_HEADER * firstSection;
firstSection = (IMAGE_SECTION_HEADER*)(((char *)loadedHeader)
+ loadedHeader->e_lfanew
IMAGE_SECTION_HEADER ¤tHeader = firstSection[i];
void* sectionBase = (char*)loadedHeader + currentHeader.VirtualAddress;
- void* sectionBaseAligned = ALIGN_DOWN(sectionBase, GetVirtualPageSize());
+ void* sectionBaseAligned;
+
+ _ASSERTE(GetVirtualPageSize() == (size_t)getpagesize());
+ sectionBaseAligned = (void*) ALIGN_DOWN((size_t)sectionBase, (size_t)getpagesize());
// Validate the section header
if ( (sectionBase < loadedHeader) // Did computing the section base overflow?
goto doneReleaseMappingCriticalSection;
}
- // Is there space between the previous section and this one? If so, add a PROT_NONE mapping to cover it.
- if (prevSectionEnd < sectionBaseAligned)
+ if (!doPreload)
{
- palError = MAPRecordMapping(pFileObject,
- loadedBase,
- prevSectionEnd,
- (char*)sectionBaseAligned - (char*)prevSectionEnd,
- PROT_NONE);
- if (NO_ERROR != palError)
+ // Is there space between the previous section and this one? If so, add a PROT_NONE mapping to cover it.
+ if (prevSectionEnd < sectionBaseAligned)
{
- ERROR_(LOADER)( "recording gap section before section %d failed\n", i );
- goto doneReleaseMappingCriticalSection;
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ prevSectionEnd,
+ (char*)sectionBaseAligned - (char*)prevSectionEnd,
+ PROT_NONE);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "recording gap section before section %d failed\n", i );
+ goto doneReleaseMappingCriticalSection;
+ }
}
}
flags = readWriteFlags;
}
- palError = MAPmmapAndRecord(pFileObject, loadedBase,
- sectionBase,
- currentHeader.SizeOfRawData,
- prot,
- flags,
- fd,
- offset + currentHeader.PointerToRawData,
- §ionData);
- if (NO_ERROR != palError)
+ off_t adjust = OffsetWithinPage(offset + currentHeader.PointerToRawData);
+
+ if (!doPreload)
{
- ERROR_(LOADER)( "mmap of section %d failed\n", i );
- goto doneReleaseMappingCriticalSection;
+ if (!isPreloaded)
+ {
+ palError = MAPmmapAndRecord(pFileObject, loadedBase,
+ sectionBase,
+ currentHeader.SizeOfRawData,
+ prot,
+ flags,
+ fd,
+ offset + currentHeader.PointerToRawData,
+ §ionData);
+ }
+ else
+ {
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ sectionBase,
+ currentHeader.SizeOfRawData,
+ prot,
+ offset + currentHeader.PointerToRawData);
+ sectionData = (void *) (static_cast<char *>(sectionBase) - adjust);
+ }
+
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "mmap of section %d failed\n", i );
+ goto doneReleaseMappingCriticalSection;
+ }
+ }
+ else
+ {
+ LPVOID base = (LPVOID) (static_cast<char *>(sectionBase) - adjust);
+ sectionData = mmap(base, currentHeader.SizeOfRawData + adjust,
+ prot, flags, fd, offset + currentHeader.PointerToRawData - adjust);
+
+ if (sectionData == MAP_FAILED)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+ if (sectionData != base)
+ {
+ munmap(sectionData, currentHeader.SizeOfRawData + adjust);
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
}
#if _DEBUG
+ if (!doPreload)
{
// Ensure null termination of section name (which is allowed to not be null terminated if exactly 8 characters long)
char sectionName[9];
}
#endif // _DEBUG
- prevSectionEnd = ALIGN_UP((char*)sectionBase + currentHeader.SizeOfRawData, GetVirtualPageSize()); // round up to page boundary
+ _ASSERTE(GetVirtualPageSize() == (size_t)getpagesize());
+ prevSectionEnd = (void*) ALIGN_UP((size_t)((char*)sectionBase + currentHeader.SizeOfRawData), (size_t)getpagesize()); // round up to page boundary
}
- // Is there space after the last section and before the end of the mapped image? If so, add a PROT_NONE mapping to cover it.
- char* imageEnd;
- imageEnd = (char*)loadedBase + virtualSize; // actually, points just after the mapped end
- if (prevSectionEnd < imageEnd)
+ if (!doPreload)
{
- palError = MAPRecordMapping(pFileObject,
- loadedBase,
- prevSectionEnd,
- offset + (char*)imageEnd - (char*)prevSectionEnd,
- PROT_NONE);
- if (NO_ERROR != palError)
+ // Is there space after the last section and before the end of the mapped image? If so, add a PROT_NONE mapping to cover it.
+ char* imageEnd;
+ imageEnd = (char*)loadedBase + virtualSize; // actually, points just after the mapped end
+ if (prevSectionEnd < imageEnd)
{
- ERROR_(LOADER)( "recording end of image gap section failed\n" );
- goto doneReleaseMappingCriticalSection;
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ prevSectionEnd,
+ offset + (char*)imageEnd - (char*)prevSectionEnd,
+ PROT_NONE);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "recording end of image gap section failed\n" );
+ goto doneReleaseMappingCriticalSection;
+ }
}
}
+ else
+ {
+ *size = reserveSize;
+ }
palError = ERROR_SUCCESS;
doneReleaseMappingCriticalSection:
- InternalLeaveCriticalSection(pThread, &mapping_critsec);
+ if (!doPreload)
+ {
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+ }
done:
LOGEXIT("MAPMapPEFile error: %d\n", palError);
// If we had an error, and had mapped anything, we need to unmap it
- if (loadedBase != NULL)
+ if (!doPreload && loadedBase != NULL && !isPreloaded)
{
MAPUnmapPEFile(loadedBase);
}
+ else if (doPreload && loadedBase != NULL)
+ {
+ munmap(loadedBase, virtualSize);
+ }
}
return retval;
}
//To force base relocation on Vista (which uses ASLR), unmask IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
//(0x40) for OptionalHeader.DllCharacteristics
-void PEImageLayout::ApplyBaseRelocations()
+//
+//NOTE: MAPApplyBaseRelocationsPreloadedPEFile should match this function exactly!
+void PEImageLayout::ApplyBaseRelocations(BOOL isRelocated)
{
STANDARD_VM_CONTRACT;
BYTE * pageAddress = (BYTE *)GetBase() + rva;
- // Check whether the page is outside the unprotected region
- if ((SIZE_T)(pageAddress - pWriteableRegion) >= cbWriteableRegion)
+ if (!isRelocated)
{
- // Restore the protection
- if (dwOldProtection != 0)
+ // Check whether the page is outside the unprotected region
+ if ((SIZE_T)(pageAddress - pWriteableRegion) >= cbWriteableRegion)
{
- BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
- PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
+ // Restore the protection
+ if (dwOldProtection != 0)
+ {
+ BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
- if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
- dwOldProtection, &dwOldProtection))
- ThrowLastError();
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
- dwOldProtection = 0;
- }
+ dwOldProtection = 0;
+ }
- USHORT fixup = VAL16(fixups[0]);
+ USHORT fixup = VAL16(fixups[0]);
- IMAGE_SECTION_HEADER *pSection = RvaToSection(rva + (fixup & 0xfff));
- PREFIX_ASSUME(pSection != NULL);
+ IMAGE_SECTION_HEADER *pSection = RvaToSection(rva + (fixup & 0xfff));
+ PREFIX_ASSUME(pSection != NULL);
- pWriteableRegion = (BYTE*)GetRvaData(VAL32(pSection->VirtualAddress));
- cbWriteableRegion = VAL32(pSection->SizeOfRawData);
+ pWriteableRegion = (BYTE*)GetRvaData(VAL32(pSection->VirtualAddress));
+ cbWriteableRegion = VAL32(pSection->SizeOfRawData);
- // Unprotect the section if it is not writable
- if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0))
- {
- DWORD dwNewProtection = PAGE_READWRITE;
-#if defined(TARGET_UNIX) && !defined(CROSSGEN_COMPILE)
- if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0))
+ // Unprotect the section if it is not writable
+ if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0))
{
- // On SELinux, we cannot change protection that doesn't have execute access rights
- // to one that has it, so we need to set the protection to RWX instead of RW
- dwNewProtection = PAGE_EXECUTE_READWRITE;
- }
+ DWORD dwNewProtection = PAGE_READWRITE;
+#if defined(TARGET_UNIX) && !defined(CROSSGEN_COMPILE)
+ if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0))
+ {
+ // On SELinux, we cannot change protection that doesn't have execute access rights
+ // to one that has it, so we need to set the protection to RWX instead of RW
+ dwNewProtection = PAGE_EXECUTE_READWRITE;
+ }
#endif // TARGET_UNIX && !CROSSGEN_COMPILE
- if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
- dwNewProtection, &dwOldProtection))
- ThrowLastError();
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwNewProtection, &dwOldProtection))
+ ThrowLastError();
#ifdef TARGET_UNIX
- dwOldProtection = SectionCharacteristicsToPageProtection(pSection->Characteristics);
+ dwOldProtection = SectionCharacteristicsToPageProtection(pSection->Characteristics);
#endif // TARGET_UNIX
+ }
}
}
switch (fixup>>12)
{
case IMAGE_REL_BASED_PTR:
- *(TADDR *)address += delta;
+ if (!isRelocated)
+ {
+ *(TADDR *)address += delta;
+ }
pEndAddressToFlush = max(pEndAddressToFlush, address + sizeof(TADDR));
break;
#ifdef TARGET_ARM
case IMAGE_REL_BASED_THUMB_MOV32:
- PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + (INT32)delta);
+ if (!isRelocated)
+ {
+ PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + (INT32)delta);
+ }
pEndAddressToFlush = max(pEndAddressToFlush, address + 8);
break;
#endif
_ASSERTE(dirSize == dirPos);
#ifndef CROSSGEN_COMPILE
- if (dwOldProtection != 0)
+ if (!isRelocated)
{
- BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
- PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
-
- // Restore the protection
- if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
- dwOldProtection, &dwOldProtection))
- ThrowLastError();
+ if (dwOldProtection != 0)
+ {
+ // Restore the protection
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
+ }
}
#ifdef TARGET_UNIX
PAL_LOADMarkSectionAsNotNeeded((void*)dir);
#if defined(CROSSGEN_COMPILE)
if (HasNativeHeader())
{
- ApplyBaseRelocations();
+ ApplyBaseRelocations(FALSE);
}
#else
// Do base relocation for PE, if necessary.
// otherwise R2R will be disabled for this image.
- ApplyBaseRelocations();
+ ApplyBaseRelocations(FALSE);
// Check if there is a static function table and install it. (Windows only, except x86)
#if !defined(TARGET_UNIX) && !defined(TARGET_X86)
if (!IsNativeMachineFormat())
ThrowHR(COR_E_BADIMAGEFORMAT);
- ApplyBaseRelocations();
+ ApplyBaseRelocations(FALSE);
}
}
else
#else //!TARGET_UNIX
#ifndef CROSSGEN_COMPILE
- m_LoadedFile = PAL_LOADLoadPEFile(hFile, offset);
+ BOOL isPreloaded;
+ m_LoadedFile = PAL_LOADLoadPEFile(hFile, offset, (LPCWSTR) GetPath(), &isPreloaded);
if (m_LoadedFile == NULL)
{
if (!IsNativeMachineFormat())
ThrowHR(COR_E_BADIMAGEFORMAT);
- ApplyBaseRelocations();
+ ApplyBaseRelocations(isPreloaded);
SetRelocated();
}
NativeImageLayout::NativeImageLayout(LPCWSTR fullPath)
{
PVOID loadedImage;
+ BOOL isPreloaded;
#if TARGET_UNIX
{
ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
ThrowLastError();
}
- loadedImage = PAL_LOADLoadPEFile(fileHandle, 0);
+ loadedImage = PAL_LOADLoadPEFile(fileHandle, 0, (LPCWSTR) GetPath(), &isPreloaded);
}
#else
loadedImage = CLRLoadLibraryEx(fullPath, NULL, GetLoadWithAlteredSearchPathFlag());
#if TARGET_UNIX
PEDecoder::Init(loadedImage, /* relocated */ false);
- ApplyBaseRelocations();
+ ApplyBaseRelocations(isPreloaded);
SetRelocated();
#else // TARGET_UNIX
PEDecoder::Init(loadedImage, /* relocated */ true);