// 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.
// PESectionMan implementation
//
#include "stdafx.h"
/*****************************************************************/
HRESULT PESectionMan::Init()
{
const int initNumSections = 16;
sectStart = new (nothrow) PESection*[initNumSections];
if (!sectStart)
return E_OUTOFMEMORY;
sectCur = sectStart;
sectEnd = §Start[initNumSections];
return S_OK;
}
/*****************************************************************/
HRESULT PESectionMan::Cleanup()
{
for (PESection** ptr = sectStart; ptr < sectCur; ptr++)
delete *ptr;
delete [] sectStart;
return S_OK;
}
/*****************************************************************/
// this class is located in it's own DLL (MsCorXvt.dll)
// Since DLL allocates, The DLL must delete; we can't simply delete from
// the client (This is a bug in VC, see knowledge base Q122675)
void PESectionMan::sectionDestroy(PESection **section)
{
// check if this section is referenced in other sections' relocs
for(PESection** ptr = sectStart; ptr < sectCur; ptr++)
{
if(ptr != section)
{
for(PESectionReloc* cur = (*ptr)->m_relocStart; cur < (*ptr)->m_relocCur; cur++)
{
if(cur->section == *section) // here it is! Delete the reference
{
for(PESectionReloc* tmp = cur; tmp < (*ptr)->m_relocCur; tmp++)
{
memcpy(tmp,(tmp+1),sizeof(PESectionReloc));
}
(*ptr)->m_relocCur--;
cur--; // no position shift this time
}
}
}
}
delete *section;
*section = NULL;
}
/*****************************************************************/
/******************************************************************/
// Apply the relocs for all the sections
// Called by: ClassConverter after loading up during an in-memory conversion,
HRESULT PESectionMan::applyRelocs(CeeGenTokenMapper *pTokenMapper)
{
HRESULT hr;
// Cycle through each of the sections
for(PESection ** ppCurSection = sectStart; ppCurSection < sectCur; ppCurSection++) {
IfFailRet((*ppCurSection)->applyRelocs(pTokenMapper));
} // End sections
return S_OK;
}
/*****************************************************************/
PESection* PESectionMan::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));
for(PESection** cur = sectStart; 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 PESectionMan::getSectionCreate(const char* name, unsigned flags,
PESection **section)
{
PESection* ret = getSection(name);
// If there is an existing section with the given name, return that
if (ret != NULL) {
*section = ret;
return(S_OK);
}
// Check if there is space for a new section
if (sectCur >= sectEnd) {
unsigned curLen = (unsigned)(sectCur-sectStart);
unsigned newLen = (curLen * 2) + 1;
PESection** sectNew = new (nothrow) PESection*[newLen];
if (sectNew == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(sectNew, sectStart, sizeof(PESection*)*curLen);
delete [] sectStart;
sectStart = sectNew;
sectCur = §Start[curLen];
sectEnd = §Start[newLen];
}
HRESULT hr;
IfFailRet(newSection(name, &ret, flags));
// dbPrintf(("MAKING NEW %s SECTION data starts at 0x%x\n", name, ret->dataStart));
*sectCur++ = ret;
_ASSERTE(sectCur <= sectEnd);
*section = ret;
return(S_OK);
}
/******************************************************************/
HRESULT PESectionMan::newSection(const char* name, PESection **section,
unsigned flags, unsigned estSize, unsigned estRelocs)
{
PESection * ret = new (nothrow) PESection(name, flags, estSize, estRelocs);
if (ret == NULL)
{
return E_OUTOFMEMORY;
}
*section = ret;
return S_OK;
}
//Clone each of our sections. This will cause a deep copy of the sections
HRESULT PESectionMan::cloneInstance(PESectionMan *destination) {
_ASSERTE(destination);
PESection *pSection;
PESection **destPtr;
HRESULT hr = NOERROR;
//Copy each of the sections
for (PESection** ptr = sectStart; ptr < sectCur; ptr++) {
destPtr = destination->sectStart;
pSection = NULL;
// try to find the matching section by name
for (; destPtr < destination->sectCur; destPtr++)
{
if (strcmp((*destPtr)->m_name, (*ptr)->m_name) == 0)
{
pSection = *destPtr;
break;
}
}
if (destPtr >= destination->sectCur)
{
// cannot find a section in the destination with matching name
// so create one!
IfFailRet( destination->getSectionCreate((*ptr)->m_name,
(*ptr)->flags(),
&pSection) );
}
if (pSection)
IfFailRet( (*ptr)->cloneInstance(pSection) );
}
//destination->sectEnd=destination->sectStart + (sectEnd-sectStart);
return S_OK;
}
//*****************************************************************************
// Implementation for PESection
//*****************************************************************************
PESection::PESection(const char *name, unsigned flags,
unsigned estSize, unsigned estRelocs)
{
dirEntry = -1;
// No init needed for CBlobFectcher m_pIndex
m_relocStart = new (nothrow) PESectionReloc[estRelocs];
if (m_relocStart == NULL)
{
// Can't report an error out of here - just initialize
// as if estRelocs was 0 (all three m_reloc pointers will be NULL).
// We'll lazily grow as needed.
estRelocs = 0;
}
m_relocCur = m_relocStart;
m_relocEnd = &m_relocStart[estRelocs];
m_header = NULL;
m_baseRVA = 0;
m_filePos = 0;
m_filePad = 0;
m_flags = flags;
_ASSERTE(strlen(name)m_name, offset, relativeTo->m_name, *((unsigned*) dataStart + offset))); */
_ASSERTE(offset < dataLen());
if (m_relocCur >= m_relocEnd) {
unsigned curLen = (unsigned)(m_relocCur-m_relocStart);
unsigned newLen = curLen * 2 + 1;
PESectionReloc* relocNew = new (nothrow) PESectionReloc[newLen];
if (relocNew == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(relocNew, m_relocStart, sizeof(PESectionReloc)*curLen);
delete m_relocStart;
m_relocStart = relocNew;
m_relocCur = &m_relocStart[curLen];
m_relocEnd = &m_relocStart[newLen];
}
m_relocCur->type = reloc;
m_relocCur->offset = offset;
m_relocCur->section = relativeTo;
if (extra)
m_relocCur->extra = *extra;
m_relocCur++;
assert(m_relocCur <= m_relocEnd);
return S_OK;
}
/******************************************************************/
// Compute a pointer (wrap blobfetcher)
char * PESection::computePointer(unsigned offset) const // virtual
{
return m_blobFetcher.ComputePointer(offset);
}
/******************************************************************/
BOOL PESection::containsPointer(__in char *ptr) const // virtual
{
return m_blobFetcher.ContainsPointer(ptr);
}
/******************************************************************/
// Compute an offset (wrap blobfetcher)
unsigned PESection::computeOffset(__in char *ptr) const // virtual
{
return m_blobFetcher.ComputeOffset(ptr);
}
/******************************************************************/
HRESULT PESection::addBaseReloc(unsigned offset, CeeSectionRelocType reloc,
CeeSectionRelocExtra *extra)
{
HRESULT hr = E_FAIL;
// Use for fixing up pointers pointing outside of the module.
//
// We only record base relocs for cross module pc-rel pointers
//
switch (reloc)
{
#ifdef _WIN64
case srRelocDir64Ptr:
#endif
case srRelocAbsolutePtr:
case srRelocHighLowPtr:
// For non pc-rel pointers we don't need to record a section reloc
hr = S_OK;
break;
#if defined (_TARGET_X86_) || defined (_TARGET_AMD64_)
case srRelocRelativePtr:
case srRelocRelative:
hr = addSectReloc(offset, NULL, reloc, extra);
break;
#endif
default:
_ASSERTE(!"unhandled reloc in PESection::addBaseReloc");
break;
}
return hr;
}
/******************************************************************/
// Dynamic mem allocation, but we can't move old blocks (since others
// have pointers to them), so we need a fancy way to grow
char* PESection::getBlock(unsigned len, unsigned align)
{
return m_blobFetcher.MakeNewBlock(len, align);
}
unsigned PESection::dataLen()
{
return m_blobFetcher.GetDataLen();
}
// Apply all the relocs for in memory conversion
// @FUTURE: Currently, our VM is rather inefficient in dealing with in-memory RVA.
// @FUTURE: VM is given an index to memory pool and a helper will return the memory pointer given the index.
// @FUTURE: We will consider having the coverter resolve RVAs into addresses.
HRESULT PESection::applyRelocs(CeeGenTokenMapper *pTokenMapper)
{
// For each section, go through each of its relocs
for(PESectionReloc* pCurReloc = m_relocStart; pCurReloc < m_relocCur; pCurReloc++) {
if (pCurReloc->type == srRelocMapToken) {
unsigned * pos = (unsigned*)
m_blobFetcher.ComputePointer(pCurReloc->offset);
mdToken newToken;
PREFIX_ASSUME(pos != NULL);
if (pTokenMapper->HasTokenMoved(*pos, newToken)) {
// we have a mapped token
*pos = newToken;
}
}
#if 0
_ASSERTE(pCurReloc->offset + 4 <= CurSection.m_blobFetcher.GetDataLen());
unsigned * pAddr = (unsigned *)
CurSection.m_blobFetcher.ComputePointer(pCurReloc->offset);
_ASSERTE(pCurReloc->type == srRelocAbsolute);
// Current contents contain an offset into pCurReloc->section
// computePointer() is like pCurReloc-section + *pAddr, but for non-linear section
// This will resolve *pAddr to be a complete address
*pAddr = (unsigned) pCurReloc->section->computePointer(*pAddr);
#endif
} // End relocs
return S_OK;
}
HRESULT PESection::cloneInstance(PESection *destination) {
PESectionReloc *cur;
INT32 newSize;
HRESULT hr = NOERROR;
_ASSERTE(destination);
destination->dirEntry = dirEntry;
//Merge the information currently in the BlobFetcher into
//out current blob fetcher
m_blobFetcher.Merge(&(destination->m_blobFetcher));
//Copy the name.
strncpy_s(destination->m_name, sizeof(destination->m_name), m_name, sizeof(m_name) - 1);
//Clone the relocs
//If the arrays aren't the same size, reallocate as necessary.
//@FUTURE: Make this a ref-counted structure and don't copy it.
newSize = (INT32)(m_relocCur-m_relocStart);
if (newSize>(destination->m_relocEnd - destination->m_relocStart)) {
delete destination->m_relocStart;
destination->m_relocStart = new (nothrow) PESectionReloc[newSize];
if (destination->m_relocStart == NULL)
IfFailGo( E_OUTOFMEMORY );
destination->m_relocEnd = destination->m_relocStart+(newSize);
}
//copy the correct data over into our new array.
memcpy(destination->m_relocStart, m_relocStart, sizeof(PESectionReloc)*(newSize));
destination->m_relocCur = destination->m_relocStart + (newSize);
for (cur=destination->m_relocStart; curm_relocCur; cur++) {
cur->section=destination;
}
ErrExit:
return hr;
}
void PESection::SetInitialGrowth(unsigned growth)
{
m_blobFetcher.SetInitialGrowth(growth);
}