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 | // PESectionMan implementation |
5 | // |
6 | |
7 | |
8 | #include "stdafx.h" |
9 | |
10 | /*****************************************************************/ |
11 | HRESULT PESectionMan::Init() |
12 | { |
13 | const int initNumSections = 16; |
14 | sectStart = new (nothrow) PESection*[initNumSections]; |
15 | if (!sectStart) |
16 | return E_OUTOFMEMORY; |
17 | sectCur = sectStart; |
18 | sectEnd = §Start[initNumSections]; |
19 | |
20 | return S_OK; |
21 | } |
22 | |
23 | /*****************************************************************/ |
24 | HRESULT PESectionMan::Cleanup() |
25 | { |
26 | for (PESection** ptr = sectStart; ptr < sectCur; ptr++) |
27 | delete *ptr; |
28 | delete [] sectStart; |
29 | |
30 | return S_OK; |
31 | } |
32 | |
33 | /*****************************************************************/ |
34 | // <REVISIT_TODO>this class is located in it's own DLL (MsCorXvt.dll) |
35 | // Since DLL allocates, The DLL must delete; we can't simply delete from |
36 | // the client (This is a bug in VC, see knowledge base Q122675)</REVISIT_TODO> |
37 | void PESectionMan::sectionDestroy(PESection **section) |
38 | { |
39 | // check if this section is referenced in other sections' relocs |
40 | for(PESection** ptr = sectStart; ptr < sectCur; ptr++) |
41 | { |
42 | if(ptr != section) |
43 | { |
44 | for(PESectionReloc* cur = (*ptr)->m_relocStart; cur < (*ptr)->m_relocCur; cur++) |
45 | { |
46 | if(cur->section == *section) // here it is! Delete the reference |
47 | { |
48 | for(PESectionReloc* tmp = cur; tmp < (*ptr)->m_relocCur; tmp++) |
49 | { |
50 | memcpy(tmp,(tmp+1),sizeof(PESectionReloc)); |
51 | } |
52 | (*ptr)->m_relocCur--; |
53 | cur--; // no position shift this time |
54 | } |
55 | } |
56 | } |
57 | } |
58 | delete *section; |
59 | *section = NULL; |
60 | } |
61 | /*****************************************************************/ |
62 | |
63 | /******************************************************************/ |
64 | // Apply the relocs for all the sections |
65 | // Called by: ClassConverter after loading up during an in-memory conversion, |
66 | |
67 | HRESULT PESectionMan::applyRelocs(CeeGenTokenMapper *pTokenMapper) |
68 | { |
69 | HRESULT hr; |
70 | |
71 | // Cycle through each of the sections |
72 | for(PESection ** ppCurSection = sectStart; ppCurSection < sectCur; ppCurSection++) { |
73 | IfFailRet((*ppCurSection)->applyRelocs(pTokenMapper)); |
74 | } // End sections |
75 | return S_OK; |
76 | } |
77 | |
78 | |
79 | /*****************************************************************/ |
80 | PESection* PESectionMan::getSection(const char* name) |
81 | { |
82 | int len = (int)strlen(name); |
83 | |
84 | // the section name can be at most 8 characters including the null. |
85 | if (len < 8) |
86 | len++; |
87 | else |
88 | len = 8; |
89 | |
90 | // dbPrintf(("looking for section %s\n", name)); |
91 | for(PESection** cur = sectStart; cur < sectCur; cur++) { |
92 | // dbPrintf(("searching section %s\n", (*cur)->m_ame)); |
93 | if (strncmp((*cur)->m_name, name, len) == 0) { |
94 | // dbPrintf(("found section %s\n", (*cur)->m_name)); |
95 | return(*cur); |
96 | } |
97 | } |
98 | return(0); |
99 | } |
100 | |
101 | /******************************************************************/ |
102 | HRESULT PESectionMan::getSectionCreate(const char* name, unsigned flags, |
103 | PESection **section) |
104 | { |
105 | PESection* ret = getSection(name); |
106 | |
107 | // If there is an existing section with the given name, return that |
108 | if (ret != NULL) { |
109 | *section = ret; |
110 | return(S_OK); |
111 | } |
112 | |
113 | // Check if there is space for a new section |
114 | if (sectCur >= sectEnd) { |
115 | unsigned curLen = (unsigned)(sectCur-sectStart); |
116 | unsigned newLen = (curLen * 2) + 1; |
117 | PESection** sectNew = new (nothrow) PESection*[newLen]; |
118 | if (sectNew == NULL) |
119 | { |
120 | return E_OUTOFMEMORY; |
121 | } |
122 | memcpy(sectNew, sectStart, sizeof(PESection*)*curLen); |
123 | delete [] sectStart; |
124 | sectStart = sectNew; |
125 | sectCur = §Start[curLen]; |
126 | sectEnd = §Start[newLen]; |
127 | } |
128 | |
129 | HRESULT hr; |
130 | IfFailRet(newSection(name, &ret, flags)); |
131 | |
132 | // dbPrintf(("MAKING NEW %s SECTION data starts at 0x%x\n", name, ret->dataStart)); |
133 | *sectCur++ = ret; |
134 | _ASSERTE(sectCur <= sectEnd); |
135 | *section = ret; |
136 | return(S_OK); |
137 | } |
138 | |
139 | /******************************************************************/ |
140 | HRESULT PESectionMan::newSection(const char* name, PESection **section, |
141 | unsigned flags, unsigned estSize, unsigned estRelocs) |
142 | { |
143 | PESection * ret = new (nothrow) PESection(name, flags, estSize, estRelocs); |
144 | if (ret == NULL) |
145 | { |
146 | return E_OUTOFMEMORY; |
147 | } |
148 | *section = ret; |
149 | return S_OK; |
150 | } |
151 | |
152 | //Clone each of our sections. This will cause a deep copy of the sections |
153 | HRESULT PESectionMan::cloneInstance(PESectionMan *destination) { |
154 | _ASSERTE(destination); |
155 | PESection *pSection; |
156 | PESection **destPtr; |
157 | HRESULT hr = NOERROR; |
158 | |
159 | //Copy each of the sections |
160 | for (PESection** ptr = sectStart; ptr < sectCur; ptr++) { |
161 | destPtr = destination->sectStart; |
162 | pSection = NULL; |
163 | |
164 | // try to find the matching section by name |
165 | for (; destPtr < destination->sectCur; destPtr++) |
166 | { |
167 | if (strcmp((*destPtr)->m_name, (*ptr)->m_name) == 0) |
168 | { |
169 | pSection = *destPtr; |
170 | break; |
171 | } |
172 | } |
173 | if (destPtr >= destination->sectCur) |
174 | { |
175 | // cannot find a section in the destination with matching name |
176 | // so create one! |
177 | IfFailRet( destination->getSectionCreate((*ptr)->m_name, |
178 | (*ptr)->flags(), |
179 | &pSection) ); |
180 | } |
181 | if (pSection) |
182 | IfFailRet( (*ptr)->cloneInstance(pSection) ); |
183 | } |
184 | |
185 | //destination->sectEnd=destination->sectStart + (sectEnd-sectStart); |
186 | return S_OK; |
187 | } |
188 | |
189 | |
190 | //***************************************************************************** |
191 | // Implementation for PESection |
192 | //***************************************************************************** |
193 | PESection::PESection(const char *name, unsigned flags, |
194 | unsigned estSize, unsigned estRelocs) |
195 | { |
196 | dirEntry = -1; |
197 | |
198 | // No init needed for CBlobFectcher m_pIndex |
199 | |
200 | m_relocStart = new (nothrow) PESectionReloc[estRelocs]; |
201 | if (m_relocStart == NULL) |
202 | { |
203 | // Can't report an error out of here - just initialize |
204 | // as if estRelocs was 0 (all three m_reloc pointers will be NULL). |
205 | // We'll lazily grow as needed. |
206 | estRelocs = 0; |
207 | } |
208 | m_relocCur = m_relocStart; |
209 | m_relocEnd = &m_relocStart[estRelocs]; |
210 | m_header = NULL; |
211 | m_baseRVA = 0; |
212 | m_filePos = 0; |
213 | m_filePad = 0; |
214 | m_flags = flags; |
215 | |
216 | _ASSERTE(strlen(name)<sizeof(m_name)); |
217 | strncpy_s(m_name, sizeof(m_name), name, strlen(name)); |
218 | } |
219 | |
220 | |
221 | /******************************************************************/ |
222 | PESection::~PESection() { |
223 | delete [] m_relocStart; |
224 | } |
225 | |
226 | |
227 | /******************************************************************/ |
228 | void PESection::(unsigned val, CeeSection& relativeTo, CeeSectionRelocType reloc, CeeSectionRelocExtra *) |
229 | { |
230 | addSectReloc(dataLen(), relativeTo, reloc, extra); |
231 | unsigned* ptr = (unsigned*) getBlock(4); |
232 | *ptr = val; |
233 | } |
234 | |
235 | /******************************************************************/ |
236 | HRESULT PESection::(unsigned offset, CeeSection& relativeToIn, |
237 | CeeSectionRelocType reloc, CeeSectionRelocExtra *) |
238 | { |
239 | return addSectReloc(offset, |
240 | (PESection *)&relativeToIn.getImpl(), reloc, extra); |
241 | } |
242 | |
243 | /******************************************************************/ |
244 | HRESULT PESection::(unsigned offset, PESection *relativeTo, |
245 | CeeSectionRelocType reloc, CeeSectionRelocExtra *) |
246 | { |
247 | /* dbPrintf(("******** GOT a section reloc for section %s offset 0x%x to section %x offset 0x%x\n", |
248 | header->m_name, offset, relativeTo->m_name, *((unsigned*) dataStart + offset))); */ |
249 | _ASSERTE(offset < dataLen()); |
250 | |
251 | if (m_relocCur >= m_relocEnd) { |
252 | unsigned curLen = (unsigned)(m_relocCur-m_relocStart); |
253 | unsigned newLen = curLen * 2 + 1; |
254 | PESectionReloc* relocNew = new (nothrow) PESectionReloc[newLen]; |
255 | if (relocNew == NULL) |
256 | { |
257 | return E_OUTOFMEMORY; |
258 | } |
259 | |
260 | memcpy(relocNew, m_relocStart, sizeof(PESectionReloc)*curLen); |
261 | delete m_relocStart; |
262 | m_relocStart = relocNew; |
263 | m_relocCur = &m_relocStart[curLen]; |
264 | m_relocEnd = &m_relocStart[newLen]; |
265 | } |
266 | |
267 | m_relocCur->type = reloc; |
268 | m_relocCur->offset = offset; |
269 | m_relocCur->section = relativeTo; |
270 | if (extra) |
271 | m_relocCur->extra = *extra; |
272 | m_relocCur++; |
273 | assert(m_relocCur <= m_relocEnd); |
274 | return S_OK; |
275 | } |
276 | |
277 | /******************************************************************/ |
278 | // Compute a pointer (wrap blobfetcher) |
279 | char * PESection::computePointer(unsigned offset) const // virtual |
280 | { |
281 | return m_blobFetcher.ComputePointer(offset); |
282 | } |
283 | |
284 | /******************************************************************/ |
285 | BOOL PESection::containsPointer(__in char *ptr) const // virtual |
286 | { |
287 | return m_blobFetcher.ContainsPointer(ptr); |
288 | } |
289 | |
290 | /******************************************************************/ |
291 | // Compute an offset (wrap blobfetcher) |
292 | unsigned PESection::computeOffset(__in char *ptr) const // virtual |
293 | { |
294 | return m_blobFetcher.ComputeOffset(ptr); |
295 | } |
296 | |
297 | |
298 | /******************************************************************/ |
299 | HRESULT PESection::(unsigned offset, CeeSectionRelocType reloc, |
300 | CeeSectionRelocExtra *) |
301 | { |
302 | HRESULT hr = E_FAIL; |
303 | |
304 | // Use for fixing up pointers pointing outside of the module. |
305 | // |
306 | // We only record base relocs for cross module pc-rel pointers |
307 | // |
308 | |
309 | switch (reloc) |
310 | { |
311 | #ifdef _WIN64 |
312 | case srRelocDir64Ptr: |
313 | #endif |
314 | case srRelocAbsolutePtr: |
315 | case srRelocHighLowPtr: |
316 | // For non pc-rel pointers we don't need to record a section reloc |
317 | hr = S_OK; |
318 | break; |
319 | |
320 | #if defined (_TARGET_X86_) || defined (_TARGET_AMD64_) |
321 | case srRelocRelativePtr: |
322 | case srRelocRelative: |
323 | hr = addSectReloc(offset, NULL, reloc, extra); |
324 | break; |
325 | #endif |
326 | |
327 | default: |
328 | _ASSERTE(!"unhandled reloc in PESection::addBaseReloc" ); |
329 | break; |
330 | } |
331 | return hr; |
332 | } |
333 | |
334 | /******************************************************************/ |
335 | // Dynamic mem allocation, but we can't move old blocks (since others |
336 | // have pointers to them), so we need a fancy way to grow |
337 | char* PESection::getBlock(unsigned len, unsigned align) |
338 | { |
339 | return m_blobFetcher.MakeNewBlock(len, align); |
340 | } |
341 | |
342 | unsigned PESection::dataLen() |
343 | { |
344 | return m_blobFetcher.GetDataLen(); |
345 | } |
346 | |
347 | // Apply all the relocs for in memory conversion |
348 | |
349 | // <REVISIT_TODO>@FUTURE: Currently, our VM is rather inefficient in dealing with in-memory RVA. |
350 | // @FUTURE: VM is given an index to memory pool and a helper will return the memory pointer given the index. |
351 | // @FUTURE: We will consider having the coverter resolve RVAs into addresses.</REVISIT_TODO> |
352 | |
353 | HRESULT PESection::applyRelocs(CeeGenTokenMapper *pTokenMapper) |
354 | { |
355 | // For each section, go through each of its relocs |
356 | for(PESectionReloc* pCurReloc = m_relocStart; pCurReloc < m_relocCur; pCurReloc++) { |
357 | if (pCurReloc->type == srRelocMapToken) { |
358 | unsigned * pos = (unsigned*) |
359 | m_blobFetcher.ComputePointer(pCurReloc->offset); |
360 | mdToken newToken; |
361 | PREFIX_ASSUME(pos != NULL); |
362 | if (pTokenMapper->HasTokenMoved(*pos, newToken)) { |
363 | // we have a mapped token |
364 | *pos = newToken; |
365 | } |
366 | } |
367 | |
368 | #if 0 |
369 | _ASSERTE(pCurReloc->offset + 4 <= CurSection.m_blobFetcher.GetDataLen()); |
370 | unsigned * pAddr = (unsigned *) |
371 | CurSection.m_blobFetcher.ComputePointer(pCurReloc->offset); |
372 | _ASSERTE(pCurReloc->type == srRelocAbsolute); |
373 | |
374 | // Current contents contain an offset into pCurReloc->section |
375 | // computePointer() is like pCurReloc-section + *pAddr, but for non-linear section |
376 | // This will resolve *pAddr to be a complete address |
377 | *pAddr = (unsigned) pCurReloc->section->computePointer(*pAddr); |
378 | #endif |
379 | |
380 | } // End relocs |
381 | return S_OK; |
382 | } |
383 | |
384 | HRESULT PESection::cloneInstance(PESection *destination) { |
385 | PESectionReloc *cur; |
386 | INT32 newSize; |
387 | HRESULT hr = NOERROR; |
388 | |
389 | _ASSERTE(destination); |
390 | |
391 | destination->dirEntry = dirEntry; |
392 | |
393 | //Merge the information currently in the BlobFetcher into |
394 | //out current blob fetcher |
395 | m_blobFetcher.Merge(&(destination->m_blobFetcher)); |
396 | |
397 | //Copy the name. |
398 | strncpy_s(destination->m_name, sizeof(destination->m_name), m_name, sizeof(m_name) - 1); |
399 | |
400 | //Clone the relocs |
401 | //If the arrays aren't the same size, reallocate as necessary. |
402 | //<REVISIT_TODO>@FUTURE: Make this a ref-counted structure and don't copy it.</REVISIT_TODO> |
403 | |
404 | newSize = (INT32)(m_relocCur-m_relocStart); |
405 | |
406 | if (newSize>(destination->m_relocEnd - destination->m_relocStart)) { |
407 | delete destination->m_relocStart; |
408 | |
409 | destination->m_relocStart = new (nothrow) PESectionReloc[newSize]; |
410 | if (destination->m_relocStart == NULL) |
411 | IfFailGo( E_OUTOFMEMORY ); |
412 | destination->m_relocEnd = destination->m_relocStart+(newSize); |
413 | } |
414 | |
415 | //copy the correct data over into our new array. |
416 | memcpy(destination->m_relocStart, m_relocStart, sizeof(PESectionReloc)*(newSize)); |
417 | destination->m_relocCur = destination->m_relocStart + (newSize); |
418 | for (cur=destination->m_relocStart; cur<destination->m_relocCur; cur++) { |
419 | cur->section=destination; |
420 | } |
421 | ErrExit: |
422 | return hr; |
423 | } |
424 | |
425 | void PESection::SetInitialGrowth(unsigned growth) |
426 | { |
427 | m_blobFetcher.SetInitialGrowth(growth); |
428 | } |
429 | |