| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /**************************************************************************** |
| 6 | ** ** |
| 7 | ** Corhlpr.h - signature helpers. ** |
| 8 | ** ** |
| 9 | ****************************************************************************/ |
| 10 | #ifndef SOS_INCLUDE |
| 11 | |
| 12 | #ifdef _BLD_CLR |
| 13 | #include "utilcode.h" |
| 14 | #endif |
| 15 | #include "corhlpr.h" |
| 16 | #include <stdlib.h> |
| 17 | |
| 18 | #endif // !SOS_INCLUDE |
| 19 | |
| 20 | |
| 21 | //***************************************************************************** |
| 22 | // |
| 23 | //***** File format helper classes |
| 24 | // |
| 25 | //***************************************************************************** |
| 26 | |
| 27 | extern "C" { |
| 28 | |
| 29 | /***************************************************************************/ |
| 30 | /* Note that this construtor does not set the LocalSig, but has the |
| 31 | advantage that it does not have any dependancy on EE structures. |
| 32 | inside the EE use the FunctionDesc constructor */ |
| 33 | |
| 34 | void __stdcall DecoderInit(void *pThis, COR_ILMETHOD *) |
| 35 | { |
| 36 | COR_ILMETHOD_DECODER *decoder = (COR_ILMETHOD_DECODER *)pThis; |
| 37 | |
| 38 | memset(decoder, 0, sizeof(COR_ILMETHOD_DECODER)); |
| 39 | if (header->Tiny.IsTiny()) |
| 40 | { |
| 41 | decoder->SetMaxStack(header->Tiny.GetMaxStack()); |
| 42 | decoder->Code = header->Tiny.GetCode(); |
| 43 | decoder->SetCodeSize(header->Tiny.GetCodeSize()); |
| 44 | decoder->SetFlags(CorILMethod_TinyFormat); |
| 45 | return; |
| 46 | } |
| 47 | if (header->Fat.IsFat()) |
| 48 | { |
| 49 | #ifdef _WIN64 |
| 50 | if((((size_t) header) & 3) == 0) // header is aligned |
| 51 | #else |
| 52 | _ASSERTE((((size_t) header) & 3) == 0); // header is aligned |
| 53 | #endif |
| 54 | { |
| 55 | *((COR_ILMETHOD_FAT *)decoder) = header->Fat; |
| 56 | decoder->Code = header->Fat.GetCode(); |
| 57 | if (header->Fat.GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4)) // Size if valid |
| 58 | { |
| 59 | decoder->Sect = header->Fat.GetSect(); |
| 60 | if ((decoder->Sect != NULL) && (decoder->Sect->Kind() == CorILMethod_Sect_EHTable)) |
| 61 | { |
| 62 | decoder->EH = (COR_ILMETHOD_SECT_EH *)decoder->Sect; |
| 63 | decoder->Sect = decoder->Sect->Next(); |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | return; |
| 68 | } |
| 69 | } // DecoderInit |
| 70 | |
| 71 | // Calculate the total method size. First get address of end of code. If there are no sections, then |
| 72 | // the end of code addr marks end of COR_ILMETHOD. Otherwise find addr of end of last section and use it |
| 73 | // to mark end of COR_ILMETHOD. Assumes that the code is directly followed |
| 74 | // by each section in the on-disk format |
| 75 | int __stdcall DecoderGetOnDiskSize(void * pThis, COR_ILMETHOD* ) |
| 76 | { |
| 77 | COR_ILMETHOD_DECODER* decoder = (COR_ILMETHOD_DECODER*)pThis; |
| 78 | |
| 79 | if (decoder->Code == NULL) |
| 80 | return 0; |
| 81 | |
| 82 | BYTE *lastAddr = (BYTE*)decoder->Code + decoder->GetCodeSize(); // addr of end of code |
| 83 | const COR_ILMETHOD_SECT *sect = decoder->EH; |
| 84 | if (sect != 0 && sect->Next() == 0) |
| 85 | { |
| 86 | lastAddr = (BYTE *)sect + sect->DataSize(); |
| 87 | } |
| 88 | else |
| 89 | { |
| 90 | const COR_ILMETHOD_SECT *nextSect; |
| 91 | for (sect = decoder->Sect; sect; sect = nextSect) |
| 92 | { |
| 93 | nextSect = sect->Next(); |
| 94 | if (nextSect == 0) |
| 95 | { |
| 96 | // sect points to the last section, so set lastAddr |
| 97 | lastAddr = (BYTE *)sect + sect->DataSize(); |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | return (int)(lastAddr - (BYTE*)header); |
| 103 | } |
| 104 | |
| 105 | /*********************************************************************/ |
| 106 | /* APIs for emitting sections etc */ |
| 107 | |
| 108 | unsigned __stdcall IlmethodSize(COR_ILMETHOD_FAT* , BOOL moreSections) |
| 109 | { |
| 110 | if (header->GetMaxStack() <= 8 && (header->GetFlags() & ~CorILMethod_FormatMask) == 0 |
| 111 | && header->GetLocalVarSigTok() == 0 && header->GetCodeSize() < 64 && !moreSections) |
| 112 | return(sizeof(COR_ILMETHOD_TINY)); |
| 113 | |
| 114 | return(sizeof(COR_ILMETHOD_FAT)); |
| 115 | } |
| 116 | |
| 117 | /*********************************************************************/ |
| 118 | // emit the header (bestFormat) return amount emitted |
| 119 | unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* , |
| 120 | BOOL moreSections, BYTE* outBuff) |
| 121 | { |
| 122 | #ifndef SOS_INCLUDE |
| 123 | #ifdef _DEBUG |
| 124 | BYTE* origBuff = outBuff; |
| 125 | #endif |
| 126 | #endif // !SOS_INCLUDE |
| 127 | if (size == 1) { |
| 128 | // Tiny format |
| 129 | *outBuff++ = (BYTE) (CorILMethod_TinyFormat | (header->GetCodeSize() << 2)); |
| 130 | } |
| 131 | else { |
| 132 | // Fat format |
| 133 | _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned |
| 134 | COR_ILMETHOD_FAT* = (COR_ILMETHOD_FAT*) outBuff; |
| 135 | outBuff += sizeof(COR_ILMETHOD_FAT); |
| 136 | *fatHeader = *header; |
| 137 | fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_FatFormat); |
| 138 | _ASSERTE((fatHeader->GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat); |
| 139 | if (moreSections) |
| 140 | fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_MoreSects); |
| 141 | fatHeader->SetSize(sizeof(COR_ILMETHOD_FAT) / 4); |
| 142 | } |
| 143 | #ifndef SOS_INCLUDE |
| 144 | _ASSERTE(&origBuff[size] == outBuff); |
| 145 | #endif // !SOS_INCLUDE |
| 146 | return(size); |
| 147 | } |
| 148 | |
| 149 | /*********************************************************************/ |
| 150 | /* static */ |
| 151 | IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* __stdcall SectEH_EHClause(void *pSectEH, unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff) |
| 152 | { |
| 153 | if (((COR_ILMETHOD_SECT_EH *)pSectEH)->IsFat()) |
| 154 | return(&(((COR_ILMETHOD_SECT_EH *)pSectEH)->Fat.Clauses[idx])); |
| 155 | |
| 156 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)buff; |
| 157 | COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&((COR_ILMETHOD_SECT_EH *)pSectEH)->Small.Clauses[idx]; |
| 158 | |
| 159 | // mask to remove sign extension - cast just wouldn't work |
| 160 | fatClause->SetFlags((CorExceptionFlag)(smallClause->GetFlags()&0x0000ffff)); |
| 161 | fatClause->SetClassToken(smallClause->GetClassToken()); |
| 162 | fatClause->SetTryOffset(smallClause->GetTryOffset()); |
| 163 | fatClause->SetTryLength(smallClause->GetTryLength()); |
| 164 | fatClause->SetHandlerLength(smallClause->GetHandlerLength()); |
| 165 | fatClause->SetHandlerOffset(smallClause->GetHandlerOffset()); |
| 166 | return(buff); |
| 167 | } |
| 168 | /*********************************************************************/ |
| 169 | // compute the size of the section (best format) |
| 170 | // codeSize is the size of the method |
| 171 | // deprecated |
| 172 | unsigned __stdcall SectEH_SizeWithCode(unsigned ehCount, unsigned codeSize) |
| 173 | { |
| 174 | return((ehCount)? SectEH_SizeWorst(ehCount) : 0); |
| 175 | } |
| 176 | |
| 177 | // will return worse-case size and then Emit will return actual size |
| 178 | unsigned __stdcall SectEH_SizeWorst(unsigned ehCount) |
| 179 | { |
| 180 | return((ehCount)? (COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)) : 0); |
| 181 | } |
| 182 | |
| 183 | // will return exact size which will match the size returned by Emit |
| 184 | unsigned __stdcall SectEH_SizeExact(unsigned ehCount, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses) |
| 185 | { |
| 186 | if (ehCount == 0) |
| 187 | return(0); |
| 188 | |
| 189 | unsigned smallSize = COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount); |
| 190 | if (smallSize > COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) |
| 191 | return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)); |
| 192 | for (unsigned i = 0; i < ehCount; i++) { |
| 193 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i]; |
| 194 | if (fatClause->GetTryOffset() > 0xFFFF || |
| 195 | fatClause->GetTryLength() > 0xFF || |
| 196 | fatClause->GetHandlerOffset() > 0xFFFF || |
| 197 | fatClause->GetHandlerLength() > 0xFF) { |
| 198 | return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)); |
| 199 | } |
| 200 | } |
| 201 | return smallSize; |
| 202 | } |
| 203 | |
| 204 | /*********************************************************************/ |
| 205 | |
| 206 | // emit the section (best format); |
| 207 | unsigned __stdcall SectEH_Emit(unsigned size, unsigned ehCount, |
| 208 | IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses, |
| 209 | BOOL moreSections, BYTE* outBuff, |
| 210 | ULONG* ehTypeOffsets) |
| 211 | { |
| 212 | if (size == 0) |
| 213 | return(0); |
| 214 | |
| 215 | _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned |
| 216 | BYTE* origBuff = outBuff; |
| 217 | if (ehCount <= 0) |
| 218 | return 0; |
| 219 | |
| 220 | // Initialize the ehTypeOffsets array. |
| 221 | if (ehTypeOffsets) |
| 222 | { |
| 223 | for (unsigned int i = 0; i < ehCount; i++) |
| 224 | ehTypeOffsets[i] = (ULONG) -1; |
| 225 | } |
| 226 | |
| 227 | if (COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount) < COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) { |
| 228 | COR_ILMETHOD_SECT_EH_SMALL* EHSect = (COR_ILMETHOD_SECT_EH_SMALL*) outBuff; |
| 229 | unsigned i; |
| 230 | for (i = 0; i < ehCount; i++) { |
| 231 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i]; |
| 232 | if (fatClause->GetTryOffset() > 0xFFFF || |
| 233 | fatClause->GetTryLength() > 0xFF || |
| 234 | fatClause->GetHandlerOffset() > 0xFFFF || |
| 235 | fatClause->GetHandlerLength() > 0xFF) { |
| 236 | break; // fall through and generate as FAT |
| 237 | } |
| 238 | _ASSERTE((fatClause->GetFlags() & ~0xFFFF) == 0); |
| 239 | _ASSERTE((fatClause->GetTryOffset() & ~0xFFFF) == 0); |
| 240 | _ASSERTE((fatClause->GetTryLength() & ~0xFF) == 0); |
| 241 | _ASSERTE((fatClause->GetHandlerOffset() & ~0xFFFF) == 0); |
| 242 | _ASSERTE((fatClause->GetHandlerLength() & ~0xFF) == 0); |
| 243 | |
| 244 | COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i]; |
| 245 | smallClause->SetFlags((CorExceptionFlag) fatClause->GetFlags()); |
| 246 | smallClause->SetTryOffset(fatClause->GetTryOffset()); |
| 247 | smallClause->SetTryLength(fatClause->GetTryLength()); |
| 248 | smallClause->SetHandlerOffset(fatClause->GetHandlerOffset()); |
| 249 | smallClause->SetHandlerLength(fatClause->GetHandlerLength()); |
| 250 | smallClause->SetClassToken(fatClause->GetClassToken()); |
| 251 | } |
| 252 | if (i >= ehCount) { |
| 253 | // if actually got through all the clauses and they are small enough |
| 254 | EHSect->Kind = CorILMethod_Sect_EHTable; |
| 255 | if (moreSections) |
| 256 | EHSect->Kind |= CorILMethod_Sect_MoreSects; |
| 257 | #ifndef SOS_INCLUDE |
| 258 | EHSect->DataSize = EHSect->Size(ehCount); |
| 259 | #else |
| 260 | EHSect->DataSize = (BYTE) EHSect->Size(ehCount); |
| 261 | #endif // !SOS_INCLUDE |
| 262 | EHSect->Reserved = 0; |
| 263 | _ASSERTE(EHSect->DataSize == EHSect->Size(ehCount)); // make sure didn't overflow |
| 264 | outBuff = (BYTE*) &EHSect->Clauses[ehCount]; |
| 265 | // Set the offsets for the exception type tokens. |
| 266 | if (ehTypeOffsets) |
| 267 | { |
| 268 | for (i = 0; i < ehCount; i++) { |
| 269 | COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i]; |
| 270 | if (smallClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE) |
| 271 | { |
| 272 | _ASSERTE(! IsNilToken(smallClause->GetClassToken())); |
| 273 | ehTypeOffsets[i] = (ULONG)((BYTE *)&smallClause->ClassToken - origBuff); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | return(size); |
| 278 | } |
| 279 | } |
| 280 | // either total size too big or one of constituent elements too big (eg. offset or length) |
| 281 | COR_ILMETHOD_SECT_EH_FAT* EHSect = (COR_ILMETHOD_SECT_EH_FAT*) outBuff; |
| 282 | EHSect->SetKind(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat); |
| 283 | if (moreSections) |
| 284 | EHSect->SetKind(EHSect->GetKind() | CorILMethod_Sect_MoreSects); |
| 285 | |
| 286 | EHSect->SetDataSize(EHSect->Size(ehCount)); |
| 287 | memcpy(EHSect->Clauses, clauses, ehCount * sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT)); |
| 288 | outBuff = (BYTE*) &EHSect->Clauses[ehCount]; |
| 289 | _ASSERTE(&origBuff[size] == outBuff); |
| 290 | // Set the offsets for the exception type tokens. |
| 291 | if (ehTypeOffsets) |
| 292 | { |
| 293 | for (unsigned int i = 0; i < ehCount; i++) { |
| 294 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&EHSect->Clauses[i]; |
| 295 | if (fatClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE) |
| 296 | { |
| 297 | _ASSERTE(! IsNilToken(fatClause->GetClassToken())); |
| 298 | ehTypeOffsets[i] = (ULONG)((BYTE *)&fatClause->ClassToken - origBuff); |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | return(size); |
| 303 | } |
| 304 | |
| 305 | } // extern "C" |
| 306 | |
| 307 | |
| 308 | |