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/*****************************************************************/
11HRESULT 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 = &sectStart[initNumSections];
19
20 return S_OK;
21}
22
23/*****************************************************************/
24HRESULT 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>
37void 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
67HRESULT 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/*****************************************************************/
80PESection* 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/******************************************************************/
102HRESULT 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 = &sectStart[curLen];
126 sectEnd = &sectStart[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/******************************************************************/
140HRESULT 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
153HRESULT 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//*****************************************************************************
193PESection::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/******************************************************************/
222PESection::~PESection() {
223 delete [] m_relocStart;
224}
225
226
227/******************************************************************/
228void PESection::writeSectReloc(unsigned val, CeeSection& relativeTo, CeeSectionRelocType reloc, CeeSectionRelocExtra *extra)
229{
230 addSectReloc(dataLen(), relativeTo, reloc, extra);
231 unsigned* ptr = (unsigned*) getBlock(4);
232 *ptr = val;
233}
234
235/******************************************************************/
236HRESULT PESection::addSectReloc(unsigned offset, CeeSection& relativeToIn,
237 CeeSectionRelocType reloc, CeeSectionRelocExtra *extra)
238{
239 return addSectReloc(offset,
240 (PESection *)&relativeToIn.getImpl(), reloc, extra);
241}
242
243/******************************************************************/
244HRESULT PESection::addSectReloc(unsigned offset, PESection *relativeTo,
245 CeeSectionRelocType reloc, CeeSectionRelocExtra *extra)
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)
279char * PESection::computePointer(unsigned offset) const // virtual
280{
281 return m_blobFetcher.ComputePointer(offset);
282}
283
284/******************************************************************/
285BOOL PESection::containsPointer(__in char *ptr) const // virtual
286{
287 return m_blobFetcher.ContainsPointer(ptr);
288}
289
290/******************************************************************/
291// Compute an offset (wrap blobfetcher)
292unsigned PESection::computeOffset(__in char *ptr) const // virtual
293{
294 return m_blobFetcher.ComputeOffset(ptr);
295}
296
297
298/******************************************************************/
299HRESULT PESection::addBaseReloc(unsigned offset, CeeSectionRelocType reloc,
300 CeeSectionRelocExtra *extra)
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
337char* PESection::getBlock(unsigned len, unsigned align)
338{
339 return m_blobFetcher.MakeNewBlock(len, align);
340}
341
342unsigned 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
353HRESULT 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
384HRESULT 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 }
421ErrExit:
422 return hr;
423}
424
425void PESection::SetInitialGrowth(unsigned growth)
426{
427 m_blobFetcher.SetInitialGrowth(growth);
428}
429