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 | |