mirror of https://github.com/UMSKT/xpmgr.git
310 lines
12 KiB
C++
310 lines
12 KiB
C++
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
// See code:EEStartup#TableOfContents for EE overview
|
|
/****************************************************************************
|
|
** **
|
|
** Corhlpr.h - signature helpers. **
|
|
** **
|
|
****************************************************************************/
|
|
#ifndef SOS_INCLUDE
|
|
|
|
#ifdef _BLD_CLR
|
|
#include "utilcode.h"
|
|
#endif
|
|
#include "corhlpr.h"
|
|
#include <stdlib.h>
|
|
|
|
#endif // !SOS_INCLUDE
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//***** File format helper classes
|
|
//
|
|
//*****************************************************************************
|
|
|
|
extern "C" {
|
|
|
|
/***************************************************************************/
|
|
/* Note that this construtor does not set the LocalSig, but has the
|
|
advantage that it does not have any dependancy on EE structures.
|
|
inside the EE use the FunctionDesc constructor */
|
|
|
|
void __stdcall DecoderInit(void *pThis, COR_ILMETHOD *header)
|
|
{
|
|
COR_ILMETHOD_DECODER *decoder = (COR_ILMETHOD_DECODER *)pThis;
|
|
|
|
memset(decoder, 0, sizeof(COR_ILMETHOD_DECODER));
|
|
if (header->Tiny.IsTiny())
|
|
{
|
|
decoder->SetMaxStack(header->Tiny.GetMaxStack());
|
|
decoder->Code = header->Tiny.GetCode();
|
|
decoder->SetCodeSize(header->Tiny.GetCodeSize());
|
|
decoder->SetFlags(CorILMethod_TinyFormat);
|
|
return;
|
|
}
|
|
if (header->Fat.IsFat())
|
|
{
|
|
#ifdef _WIN64
|
|
if((((size_t) header) & 3) == 0) // header is aligned
|
|
#else
|
|
_ASSERTE((((size_t) header) & 3) == 0); // header is aligned
|
|
#endif
|
|
{
|
|
*((COR_ILMETHOD_FAT *)decoder) = header->Fat;
|
|
decoder->Code = header->Fat.GetCode();
|
|
if (header->Fat.GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4)) // Size if valid
|
|
{
|
|
decoder->Sect = header->Fat.GetSect();
|
|
if ((decoder->Sect != NULL) && (decoder->Sect->Kind() == CorILMethod_Sect_EHTable))
|
|
{
|
|
decoder->EH = (COR_ILMETHOD_SECT_EH *)decoder->Sect;
|
|
decoder->Sect = decoder->Sect->Next();
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
} // DecoderInit
|
|
|
|
// Calculate the total method size. First get address of end of code. If there are no sections, then
|
|
// the end of code addr marks end of COR_ILMETHOD. Otherwise find addr of end of last section and use it
|
|
// to mark end of COR_ILMETHOD. Assumes that the code is directly followed
|
|
// by each section in the on-disk format
|
|
int __stdcall DecoderGetOnDiskSize(void * pThis, COR_ILMETHOD* header)
|
|
{
|
|
COR_ILMETHOD_DECODER* decoder = (COR_ILMETHOD_DECODER*)pThis;
|
|
|
|
if (decoder->Code == NULL)
|
|
return 0;
|
|
|
|
BYTE *lastAddr = (BYTE*)decoder->Code + decoder->GetCodeSize(); // addr of end of code
|
|
const COR_ILMETHOD_SECT *sect = decoder->EH;
|
|
if (sect != 0 && sect->Next() == 0)
|
|
{
|
|
lastAddr = (BYTE *)sect + sect->DataSize();
|
|
}
|
|
else
|
|
{
|
|
const COR_ILMETHOD_SECT *nextSect;
|
|
for (sect = decoder->Sect; sect; sect = nextSect)
|
|
{
|
|
nextSect = sect->Next();
|
|
if (nextSect == 0)
|
|
{
|
|
// sect points to the last section, so set lastAddr
|
|
lastAddr = (BYTE *)sect + sect->DataSize();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (int)(lastAddr - (BYTE*)header);
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* APIs for emitting sections etc */
|
|
|
|
unsigned __stdcall IlmethodSize(COR_ILMETHOD_FAT* header, BOOL moreSections)
|
|
{
|
|
if (header->GetMaxStack() <= 8 && (header->GetFlags() & ~CorILMethod_FormatMask) == 0
|
|
&& header->GetLocalVarSigTok() == 0 && header->GetCodeSize() < 64 && !moreSections)
|
|
return(sizeof(COR_ILMETHOD_TINY));
|
|
|
|
return(sizeof(COR_ILMETHOD_FAT));
|
|
}
|
|
|
|
/*********************************************************************/
|
|
// emit the header (bestFormat) return amount emitted
|
|
unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* header,
|
|
BOOL moreSections, BYTE* outBuff)
|
|
{
|
|
#ifndef SOS_INCLUDE
|
|
#ifdef _DEBUG
|
|
BYTE* origBuff = outBuff;
|
|
#endif
|
|
#endif // !SOS_INCLUDE
|
|
if (size == 1) {
|
|
// Tiny format
|
|
*outBuff++ = (BYTE) (CorILMethod_TinyFormat | (header->GetCodeSize() << 2));
|
|
}
|
|
else {
|
|
// Fat format
|
|
_ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned
|
|
COR_ILMETHOD_FAT* fatHeader = (COR_ILMETHOD_FAT*) outBuff;
|
|
outBuff += sizeof(COR_ILMETHOD_FAT);
|
|
*fatHeader = *header;
|
|
fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_FatFormat);
|
|
_ASSERTE((fatHeader->GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat);
|
|
if (moreSections)
|
|
fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_MoreSects);
|
|
fatHeader->SetSize(sizeof(COR_ILMETHOD_FAT) / 4);
|
|
}
|
|
#ifndef SOS_INCLUDE
|
|
_ASSERTE(&origBuff[size] == outBuff);
|
|
#endif // !SOS_INCLUDE
|
|
return(size);
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* static */
|
|
IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* __stdcall SectEH_EHClause(void *pSectEH, unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff)
|
|
{
|
|
if (((COR_ILMETHOD_SECT_EH *)pSectEH)->IsFat())
|
|
return(&(((COR_ILMETHOD_SECT_EH *)pSectEH)->Fat.Clauses[idx]));
|
|
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)buff;
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&((COR_ILMETHOD_SECT_EH *)pSectEH)->Small.Clauses[idx];
|
|
|
|
// mask to remove sign extension - cast just wouldn't work
|
|
fatClause->SetFlags((CorExceptionFlag)(smallClause->GetFlags()&0x0000ffff));
|
|
fatClause->SetClassToken(smallClause->GetClassToken());
|
|
fatClause->SetTryOffset(smallClause->GetTryOffset());
|
|
fatClause->SetTryLength(smallClause->GetTryLength());
|
|
fatClause->SetHandlerLength(smallClause->GetHandlerLength());
|
|
fatClause->SetHandlerOffset(smallClause->GetHandlerOffset());
|
|
return(buff);
|
|
}
|
|
/*********************************************************************/
|
|
// compute the size of the section (best format)
|
|
// codeSize is the size of the method
|
|
// deprecated
|
|
unsigned __stdcall SectEH_SizeWithCode(unsigned ehCount, unsigned codeSize)
|
|
{
|
|
return((ehCount)? SectEH_SizeWorst(ehCount) : 0);
|
|
}
|
|
|
|
// will return worse-case size and then Emit will return actual size
|
|
unsigned __stdcall SectEH_SizeWorst(unsigned ehCount)
|
|
{
|
|
return((ehCount)? (COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)) : 0);
|
|
}
|
|
|
|
// will return exact size which will match the size returned by Emit
|
|
unsigned __stdcall SectEH_SizeExact(unsigned ehCount, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses)
|
|
{
|
|
if (ehCount == 0)
|
|
return(0);
|
|
|
|
unsigned smallSize = COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount);
|
|
if (smallSize > COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE)
|
|
return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount));
|
|
for (unsigned i = 0; i < ehCount; i++) {
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i];
|
|
if (fatClause->GetTryOffset() > 0xFFFF ||
|
|
fatClause->GetTryLength() > 0xFF ||
|
|
fatClause->GetHandlerOffset() > 0xFFFF ||
|
|
fatClause->GetHandlerLength() > 0xFF) {
|
|
return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount));
|
|
}
|
|
}
|
|
return smallSize;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
// emit the section (best format);
|
|
unsigned __stdcall SectEH_Emit(unsigned size, unsigned ehCount,
|
|
IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses,
|
|
BOOL moreSections, BYTE* outBuff,
|
|
ULONG* ehTypeOffsets)
|
|
{
|
|
if (size == 0)
|
|
return(0);
|
|
|
|
_ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned
|
|
BYTE* origBuff = outBuff;
|
|
if (ehCount <= 0)
|
|
return 0;
|
|
|
|
// Initialize the ehTypeOffsets array.
|
|
if (ehTypeOffsets)
|
|
{
|
|
for (unsigned int i = 0; i < ehCount; i++)
|
|
ehTypeOffsets[i] = (ULONG) -1;
|
|
}
|
|
|
|
if (COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount) < COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) {
|
|
COR_ILMETHOD_SECT_EH_SMALL* EHSect = (COR_ILMETHOD_SECT_EH_SMALL*) outBuff;
|
|
unsigned i;
|
|
for (i = 0; i < ehCount; i++) {
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i];
|
|
if (fatClause->GetTryOffset() > 0xFFFF ||
|
|
fatClause->GetTryLength() > 0xFF ||
|
|
fatClause->GetHandlerOffset() > 0xFFFF ||
|
|
fatClause->GetHandlerLength() > 0xFF) {
|
|
break; // fall through and generate as FAT
|
|
}
|
|
_ASSERTE((fatClause->GetFlags() & ~0xFFFF) == 0);
|
|
_ASSERTE((fatClause->GetTryOffset() & ~0xFFFF) == 0);
|
|
_ASSERTE((fatClause->GetTryLength() & ~0xFF) == 0);
|
|
_ASSERTE((fatClause->GetHandlerOffset() & ~0xFFFF) == 0);
|
|
_ASSERTE((fatClause->GetHandlerLength() & ~0xFF) == 0);
|
|
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i];
|
|
smallClause->SetFlags((CorExceptionFlag) fatClause->GetFlags());
|
|
smallClause->SetTryOffset(fatClause->GetTryOffset());
|
|
smallClause->SetTryLength(fatClause->GetTryLength());
|
|
smallClause->SetHandlerOffset(fatClause->GetHandlerOffset());
|
|
smallClause->SetHandlerLength(fatClause->GetHandlerLength());
|
|
smallClause->SetClassToken(fatClause->GetClassToken());
|
|
}
|
|
if (i >= ehCount) {
|
|
// if actually got through all the clauses and they are small enough
|
|
EHSect->Kind = CorILMethod_Sect_EHTable;
|
|
if (moreSections)
|
|
EHSect->Kind |= CorILMethod_Sect_MoreSects;
|
|
#ifndef SOS_INCLUDE
|
|
EHSect->DataSize = EHSect->Size(ehCount);
|
|
#else
|
|
EHSect->DataSize = (BYTE) EHSect->Size(ehCount);
|
|
#endif // !SOS_INCLUDE
|
|
EHSect->Reserved = 0;
|
|
_ASSERTE(EHSect->DataSize == EHSect->Size(ehCount)); // make sure didn't overflow
|
|
outBuff = (BYTE*) &EHSect->Clauses[ehCount];
|
|
// Set the offsets for the exception type tokens.
|
|
if (ehTypeOffsets)
|
|
{
|
|
for (i = 0; i < ehCount; i++) {
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i];
|
|
if (smallClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE)
|
|
{
|
|
_ASSERTE(! IsNilToken(smallClause->GetClassToken()));
|
|
ehTypeOffsets[i] = (ULONG)((BYTE *)&smallClause->ClassToken - origBuff);
|
|
}
|
|
}
|
|
}
|
|
return(size);
|
|
}
|
|
}
|
|
// either total size too big or one of constituent elements too big (eg. offset or length)
|
|
COR_ILMETHOD_SECT_EH_FAT* EHSect = (COR_ILMETHOD_SECT_EH_FAT*) outBuff;
|
|
EHSect->SetKind(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
|
|
if (moreSections)
|
|
EHSect->SetKind(EHSect->GetKind() | CorILMethod_Sect_MoreSects);
|
|
|
|
EHSect->SetDataSize(EHSect->Size(ehCount));
|
|
memcpy(EHSect->Clauses, clauses, ehCount * sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
|
|
outBuff = (BYTE*) &EHSect->Clauses[ehCount];
|
|
_ASSERTE(&origBuff[size] == outBuff);
|
|
// Set the offsets for the exception type tokens.
|
|
if (ehTypeOffsets)
|
|
{
|
|
for (unsigned int i = 0; i < ehCount; i++) {
|
|
COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&EHSect->Clauses[i];
|
|
if (fatClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE)
|
|
{
|
|
_ASSERTE(! IsNilToken(fatClause->GetClassToken()));
|
|
ehTypeOffsets[i] = (ULONG)((BYTE *)&fatClause->ClassToken - origBuff);
|
|
}
|
|
}
|
|
}
|
|
return(size);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
|