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 | |
8 | #include "stdafx.h" |
9 | |
10 | #include "corerror.h" |
11 | |
12 | #ifdef EnC_SUPPORTED |
13 | #define ENC_DELTA_HACK |
14 | #endif |
15 | |
16 | |
17 | //***************************************************************************** |
18 | // Creation for new CCeeGen instances |
19 | // |
20 | // Both allocate and call virtual Init() (Can't call v-func in a ctor, |
21 | // but we want to create in 1 call); |
22 | //***************************************************************************** |
23 | |
24 | HRESULT STDMETHODCALLTYPE CreateICeeGen(REFIID riid, void **pCeeGen) |
25 | { |
26 | if (riid != IID_ICeeGen) |
27 | return E_NOTIMPL; |
28 | if (!pCeeGen) |
29 | return E_POINTER; |
30 | CCeeGen *pCeeFileGen; |
31 | HRESULT hr = CCeeGen::CreateNewInstance(pCeeFileGen); |
32 | if (FAILED(hr)) |
33 | return hr; |
34 | pCeeFileGen->AddRef(); |
35 | *(CCeeGen**)pCeeGen = pCeeFileGen; |
36 | return S_OK; |
37 | } |
38 | |
39 | HRESULT CCeeGen::CreateNewInstance(CCeeGen* & pGen) // static, public |
40 | { |
41 | NewHolder<CCeeGen> pGenHolder(new CCeeGen()); |
42 | _ASSERTE(pGenHolder != NULL); |
43 | TESTANDRETURNMEMORY(pGenHolder); |
44 | |
45 | pGenHolder->m_peSectionMan = new PESectionMan; |
46 | _ASSERTE(pGenHolder->m_peSectionMan != NULL); |
47 | TESTANDRETURNMEMORY(pGenHolder->m_peSectionMan); |
48 | |
49 | HRESULT hr = pGenHolder->m_peSectionMan->Init(); |
50 | if (FAILED(hr)) |
51 | { |
52 | pGenHolder->Cleanup(); |
53 | return hr; |
54 | } |
55 | |
56 | hr = pGenHolder->Init(); |
57 | if (FAILED(hr)) |
58 | { |
59 | // Init() calls Cleanup() on failure |
60 | return hr; |
61 | } |
62 | |
63 | pGen = pGenHolder.Extract(); |
64 | return hr; |
65 | } |
66 | |
67 | STDMETHODIMP CCeeGen::QueryInterface(REFIID riid, void** ppv) |
68 | { |
69 | if (!ppv) |
70 | return E_POINTER; |
71 | |
72 | *ppv = NULL; |
73 | |
74 | if (riid == IID_IUnknown) |
75 | *ppv = (IUnknown*)(ICeeGen*)this; |
76 | else if (riid == IID_ICeeGen) |
77 | *ppv = (ICeeGen*)this; |
78 | else if (riid == IID_ICeeGenInternal) |
79 | *ppv = (ICeeGenInternal*)this; |
80 | if (*ppv == NULL) |
81 | return E_NOINTERFACE; |
82 | AddRef(); |
83 | return S_OK; |
84 | } |
85 | |
86 | STDMETHODIMP_(ULONG) CCeeGen::AddRef(void) |
87 | { |
88 | return InterlockedIncrement(&m_cRefs); |
89 | } |
90 | |
91 | STDMETHODIMP_(ULONG) CCeeGen::Release(void) |
92 | { |
93 | if (InterlockedDecrement(&m_cRefs) == 0) { |
94 | Cleanup(); |
95 | delete this; |
96 | return 0; |
97 | } |
98 | return 1; |
99 | } |
100 | |
101 | STDMETHODIMP CCeeGen::SetInitialGrowth(DWORD growth) |
102 | { |
103 | getIlSection().SetInitialGrowth(growth); |
104 | |
105 | return S_OK; |
106 | } |
107 | |
108 | STDMETHODIMP CCeeGen::EmitString (__in LPWSTR lpString, ULONG *RVA) |
109 | { |
110 | HRESULT hr = S_OK; |
111 | BEGIN_ENTRYPOINT_NOTHROW; |
112 | |
113 | if (! RVA) |
114 | IfFailGo(E_POINTER); |
115 | hr = getStringSection().getEmittedStringRef(lpString, RVA); |
116 | ErrExit: |
117 | |
118 | END_ENTRYPOINT_NOTHROW; |
119 | return hr; |
120 | } |
121 | |
122 | STDMETHODIMP CCeeGen::GetString(ULONG RVA, __inout LPWSTR *lpString) |
123 | { |
124 | HRESULT hr = E_FAIL; |
125 | BEGIN_ENTRYPOINT_NOTHROW; |
126 | |
127 | if (! lpString) |
128 | IfFailGo(E_POINTER); |
129 | *lpString = (LPWSTR)getStringSection().computePointer(RVA); |
130 | |
131 | |
132 | ErrExit: |
133 | |
134 | END_ENTRYPOINT_NOTHROW; |
135 | if (*lpString) |
136 | return S_OK; |
137 | return hr; |
138 | } |
139 | |
140 | STDMETHODIMP CCeeGen::AllocateMethodBuffer(ULONG cchBuffer, UCHAR **lpBuffer, ULONG *RVA) |
141 | { |
142 | HRESULT hr = S_OK; |
143 | BEGIN_ENTRYPOINT_NOTHROW; |
144 | |
145 | ULONG methodOffset = 0; |
146 | |
147 | if (! cchBuffer) |
148 | IfFailGo(E_INVALIDARG); |
149 | if (! lpBuffer || ! RVA) |
150 | IfFailGo(E_POINTER); |
151 | *lpBuffer = (UCHAR*) getIlSection().getBlock(cchBuffer, 4); // Dword align |
152 | IfNullGo(*lpBuffer); |
153 | |
154 | // have to compute the method offset after getting the block, not |
155 | // before (since alignment might shift it up |
156 | // for in-memory, just return address and will calc later |
157 | methodOffset = getIlSection().dataLen() - cchBuffer; |
158 | |
159 | *RVA = methodOffset; |
160 | |
161 | ErrExit: |
162 | END_ENTRYPOINT_NOTHROW; |
163 | |
164 | return hr; |
165 | } |
166 | |
167 | STDMETHODIMP CCeeGen::GetMethodBuffer(ULONG RVA, UCHAR **lpBuffer) |
168 | { |
169 | HRESULT hr = E_FAIL; |
170 | BEGIN_ENTRYPOINT_NOTHROW; |
171 | |
172 | if (! lpBuffer) |
173 | IfFailGo(E_POINTER); |
174 | *lpBuffer = (UCHAR*)getIlSection().computePointer(RVA); |
175 | |
176 | |
177 | ErrExit: |
178 | END_ENTRYPOINT_NOTHROW; |
179 | |
180 | if (lpBuffer != NULL && *lpBuffer != 0) |
181 | return S_OK; |
182 | |
183 | return hr; |
184 | } |
185 | |
186 | STDMETHODIMP CCeeGen::ComputePointer(HCEESECTION section, ULONG RVA, UCHAR **lpBuffer) |
187 | { |
188 | HRESULT hr = E_FAIL; |
189 | BEGIN_ENTRYPOINT_NOTHROW; |
190 | |
191 | if (! lpBuffer) |
192 | IfFailGo(E_POINTER); |
193 | *lpBuffer = (UCHAR*) ((CeeSection *)section)->computePointer(RVA); |
194 | |
195 | ErrExit: |
196 | END_ENTRYPOINT_NOTHROW; |
197 | |
198 | if (lpBuffer != NULL && *lpBuffer != 0) |
199 | return S_OK; |
200 | return hr; |
201 | } |
202 | |
203 | STDMETHODIMP CCeeGen::GetIMapTokenIface ( |
204 | IUnknown **pIMapToken) |
205 | { |
206 | BEGIN_ENTRYPOINT_NOTHROW; |
207 | |
208 | _ASSERTE(!"E_NOTIMPL" ); |
209 | END_ENTRYPOINT_NOTHROW; |
210 | |
211 | return E_NOTIMPL; |
212 | } |
213 | |
214 | STDMETHODIMP CCeeGen::AddNotificationHandler ( |
215 | IUnknown *pHandler) |
216 | { |
217 | BEGIN_ENTRYPOINT_NOTHROW; |
218 | _ASSERTE(!"E_NOTIMPL" ); |
219 | END_ENTRYPOINT_NOTHROW; |
220 | |
221 | return E_NOTIMPL; |
222 | } |
223 | |
224 | STDMETHODIMP CCeeGen::GenerateCeeFile () |
225 | { |
226 | BEGIN_ENTRYPOINT_NOTHROW; |
227 | |
228 | _ASSERTE(!"E_NOTIMPL" ); |
229 | END_ENTRYPOINT_NOTHROW; |
230 | |
231 | return E_NOTIMPL; |
232 | } |
233 | |
234 | STDMETHODIMP CCeeGen::GenerateCeeMemoryImage (void **) |
235 | { |
236 | BEGIN_ENTRYPOINT_NOTHROW; |
237 | |
238 | _ASSERTE(!"E_NOTIMPL" ); |
239 | END_ENTRYPOINT_NOTHROW; |
240 | |
241 | return E_NOTIMPL; |
242 | } |
243 | |
244 | STDMETHODIMP CCeeGen::GetIlSection ( |
245 | HCEESECTION *section) |
246 | { |
247 | BEGIN_ENTRYPOINT_NOTHROW; |
248 | |
249 | *section = (HCEESECTION)(m_sections[m_ilIdx]); |
250 | END_ENTRYPOINT_NOTHROW; |
251 | |
252 | return S_OK; |
253 | } |
254 | |
255 | STDMETHODIMP CCeeGen::GetStringSection(HCEESECTION *section) |
256 | { |
257 | BEGIN_ENTRYPOINT_NOTHROW; |
258 | |
259 | _ASSERTE(!"E_NOTIMPL" ); |
260 | END_ENTRYPOINT_NOTHROW; |
261 | |
262 | return E_NOTIMPL; |
263 | } |
264 | |
265 | STDMETHODIMP CCeeGen::AddSectionReloc ( |
266 | HCEESECTION section, |
267 | ULONG offset, |
268 | HCEESECTION relativeTo, |
269 | CeeSectionRelocType relocType) |
270 | { |
271 | HRESULT hr = S_OK; |
272 | BEGIN_ENTRYPOINT_NOTHROW; |
273 | |
274 | hr = m_sections[m_ilIdx]->addSectReloc(offset, *(m_sections[m_ilIdx]), relocType); |
275 | END_ENTRYPOINT_NOTHROW; |
276 | return hr; |
277 | } |
278 | |
279 | STDMETHODIMP CCeeGen::GetSectionCreate ( |
280 | const char *name, |
281 | DWORD flags, |
282 | HCEESECTION *section) |
283 | { |
284 | HRESULT hr = S_OK; |
285 | BEGIN_ENTRYPOINT_NOTHROW; |
286 | |
287 | short sectionIdx; |
288 | hr = getSectionCreate (name, flags, (CeeSection **)section, §ionIdx); |
289 | END_ENTRYPOINT_NOTHROW; |
290 | return hr; |
291 | } |
292 | |
293 | STDMETHODIMP CCeeGen::GetSectionDataLen ( |
294 | HCEESECTION section, |
295 | ULONG *dataLen) |
296 | { |
297 | BEGIN_ENTRYPOINT_NOTHROW; |
298 | |
299 | CeeSection *pSection = (CeeSection*) section; |
300 | *dataLen = pSection->dataLen(); |
301 | END_ENTRYPOINT_NOTHROW; |
302 | |
303 | return NOERROR; |
304 | } |
305 | |
306 | STDMETHODIMP CCeeGen::GetSectionBlock ( |
307 | HCEESECTION section, |
308 | ULONG len, |
309 | ULONG align, |
310 | void **ppBytes) |
311 | { |
312 | BEGIN_ENTRYPOINT_NOTHROW; |
313 | |
314 | CeeSection *pSection = (CeeSection*) section; |
315 | *ppBytes = (BYTE *)pSection->getBlock(len, align); |
316 | END_ENTRYPOINT_NOTHROW; |
317 | |
318 | if (*ppBytes == 0) |
319 | return E_OUTOFMEMORY; |
320 | return NOERROR; |
321 | } |
322 | |
323 | STDMETHODIMP CCeeGen::TruncateSection ( |
324 | HCEESECTION section, |
325 | ULONG len) |
326 | { |
327 | BEGIN_ENTRYPOINT_NOTHROW; |
328 | |
329 | _ASSERTE(!"E_NOTIMPL" ); |
330 | END_ENTRYPOINT_NOTHROW; |
331 | return E_NOTIMPL; |
332 | } |
333 | |
334 | |
335 | |
336 | CCeeGen::CCeeGen() // protected ctor |
337 | { |
338 | // All other init done in InitCommon() |
339 | m_cRefs = 0; |
340 | m_peSectionMan = NULL; |
341 | m_pTokenMap = NULL; |
342 | m_pRemapHandler = NULL; |
343 | |
344 | } |
345 | |
346 | // Shared init code between derived classes, called by virtual Init() |
347 | HRESULT CCeeGen::Init() // not-virtual, protected |
348 | { |
349 | // Public, Virtual init must create our SectionManager, and |
350 | // Common init does the rest |
351 | _ASSERTE(m_peSectionMan != NULL); |
352 | |
353 | HRESULT hr = S_OK; |
354 | |
355 | PESection *section = NULL; |
356 | CeeSection *ceeSection = NULL; |
357 | |
358 | m_corHeader = NULL; |
359 | |
360 | m_numSections = 0; |
361 | m_allocSections = 10; |
362 | m_sections = new CeeSection * [ m_allocSections ]; |
363 | if (m_sections == NULL) { |
364 | hr = E_OUTOFMEMORY; |
365 | goto LExit; |
366 | } |
367 | |
368 | m_pTokenMap = NULL; |
369 | m_fTokenMapSupported = FALSE; |
370 | m_pRemapHandler = NULL; |
371 | |
372 | // These text section needs special support for handling string management now that we have |
373 | // merged the sections together, so create it with an underlying CeeSectionString rather than the |
374 | // more generic CeeSection |
375 | |
376 | hr = m_peSectionMan->getSectionCreate(".text" , sdExecute, §ion); |
377 | if (FAILED(hr)) { |
378 | goto LExit; |
379 | } |
380 | |
381 | ceeSection = new CeeSectionString(*this, *section); |
382 | if (ceeSection == NULL) { |
383 | hr = E_OUTOFMEMORY; |
384 | goto LExit; |
385 | } |
386 | |
387 | hr = addSection(ceeSection, &m_stringIdx); |
388 | |
389 | m_textIdx = m_stringIdx; |
390 | |
391 | m_metaIdx = m_textIdx; // meta section is actually in .text |
392 | m_ilIdx = m_textIdx; // il section is actually in .text |
393 | m_corHdrIdx = -1; |
394 | m_encMode = FALSE; |
395 | |
396 | LExit: |
397 | if (FAILED(hr)) { |
398 | Cleanup(); |
399 | } |
400 | |
401 | return hr; |
402 | } |
403 | |
404 | // For EnC mode, generate strings into .rdata section rather than .text section |
405 | HRESULT CCeeGen::setEnCMode() |
406 | { |
407 | PESection *section = NULL; |
408 | HRESULT hr = m_peSectionMan->getSectionCreate(".rdata" , sdExecute, §ion); |
409 | TESTANDRETURNHR(hr); |
410 | CeeSection *ceeSection = new CeeSectionString(*this, *section); |
411 | if (ceeSection == NULL) |
412 | { |
413 | return E_OUTOFMEMORY; |
414 | } |
415 | hr = addSection(ceeSection, &m_stringIdx); |
416 | if (SUCCEEDED(hr)) |
417 | m_encMode = TRUE; |
418 | return hr; |
419 | } |
420 | |
421 | |
422 | HRESULT CCeeGen::cloneInstance(CCeeGen *destination) { //public, virtual |
423 | _ASSERTE(destination); |
424 | |
425 | destination->m_pTokenMap = m_pTokenMap; |
426 | destination->m_fTokenMapSupported = m_fTokenMapSupported; |
427 | destination->m_pRemapHandler = m_pRemapHandler; |
428 | |
429 | //Create a deep copy of the section manager (and each of it's sections); |
430 | return m_peSectionMan->cloneInstance(destination->m_peSectionMan); |
431 | } |
432 | |
433 | HRESULT CCeeGen::Cleanup() // virtual |
434 | { |
435 | HRESULT hr; |
436 | for (int i = 0; i < m_numSections; i++) { |
437 | delete m_sections[i]; |
438 | } |
439 | |
440 | delete [] m_sections; |
441 | |
442 | CeeGenTokenMapper *pMapper = m_pTokenMap; |
443 | if (pMapper) { |
444 | if (pMapper->m_pIImport) { |
445 | IMetaDataEmit *pIIEmit; |
446 | if (SUCCEEDED( hr = pMapper->m_pIImport->QueryInterface(IID_IMetaDataEmit, (void **) &pIIEmit))) |
447 | { |
448 | pIIEmit->SetHandler(NULL); |
449 | pIIEmit->Release(); |
450 | } |
451 | _ASSERTE(SUCCEEDED(hr)); |
452 | pMapper->m_pIImport->Release(); |
453 | } |
454 | pMapper->Release(); |
455 | m_pTokenMap = NULL; |
456 | } |
457 | |
458 | if (m_pRemapHandler) |
459 | { |
460 | m_pRemapHandler->Release(); |
461 | m_pRemapHandler = NULL; |
462 | } |
463 | |
464 | if (m_peSectionMan) { |
465 | m_peSectionMan->Cleanup(); |
466 | delete m_peSectionMan; |
467 | } |
468 | |
469 | return S_OK; |
470 | } |
471 | |
472 | HRESULT CCeeGen::addSection(CeeSection *section, short *sectionIdx) |
473 | { |
474 | if (m_numSections >= m_allocSections) |
475 | { |
476 | _ASSERTE(m_allocSections > 0); |
477 | while (m_numSections >= m_allocSections) |
478 | m_allocSections <<= 1; |
479 | CeeSection **newSections = new CeeSection * [m_allocSections]; |
480 | if (newSections == NULL) |
481 | return E_OUTOFMEMORY; |
482 | CopyMemory(newSections, m_sections, m_numSections * sizeof(*m_sections)); |
483 | if (m_sections != NULL) |
484 | delete [] m_sections; |
485 | m_sections = newSections; |
486 | } |
487 | |
488 | if (sectionIdx) |
489 | *sectionIdx = m_numSections; |
490 | |
491 | m_sections[m_numSections++] = section; |
492 | return S_OK; |
493 | } |
494 | |
495 | HRESULT CCeeGen::getSectionCreate (const char *name, DWORD flags, CeeSection **section, short *sectionIdx) |
496 | { |
497 | if (strcmp(name, ".il" ) == 0) |
498 | name = ".text" ; |
499 | else if (strcmp(name, ".meta" ) == 0) |
500 | name = ".text" ; |
501 | else if (strcmp(name, ".rdata" ) == 0 && !m_encMode) |
502 | name = ".text" ; |
503 | for (int i=0; i<m_numSections; i++) { |
504 | if (strcmp((const char *)m_sections[i]->name(), name) == 0) { |
505 | if (section) |
506 | *section = m_sections[i]; |
507 | if (sectionIdx) |
508 | *sectionIdx = i; |
509 | return S_OK; |
510 | } |
511 | } |
512 | PESection *pewSect = NULL; |
513 | HRESULT hr = m_peSectionMan->getSectionCreate(name, flags, &pewSect); |
514 | TESTANDRETURNHR(hr); |
515 | CeeSection *newSect = new CeeSection(*this, *pewSect); |
516 | // if this fails, the PESection will get nuked in the destructor for CCeeGen |
517 | if (newSect == NULL) |
518 | { |
519 | return E_OUTOFMEMORY; |
520 | } |
521 | |
522 | hr = addSection(newSect, sectionIdx); |
523 | TESTANDRETURNHR(hr); |
524 | if (section) |
525 | *section = newSect; |
526 | return S_OK; |
527 | } |
528 | |
529 | |
530 | HRESULT CCeeGen::emitMetaData(IMetaDataEmit *emitter, CeeSection* section, DWORD offset, BYTE* buffer, unsigned buffLen) |
531 | { |
532 | HRESULT hr = S_OK; |
533 | |
534 | ReleaseHolder<IStream> metaStream(NULL); |
535 | |
536 | IfFailRet((HRESULT)CreateStreamOnHGlobal(NULL, TRUE, &metaStream)); |
537 | |
538 | if (! m_fTokenMapSupported) { |
539 | IUnknown *pMapTokenIface; |
540 | IfFailGoto(getMapTokenIface(&pMapTokenIface, emitter), Exit); |
541 | |
542 | // Set a callback for token remap and save the tokens which change. |
543 | IfFailGoto(emitter->SetHandler(pMapTokenIface), Exit); |
544 | } |
545 | |
546 | // generate the metadata |
547 | IfFailGoto(emitter->SaveToStream(metaStream, 0), Exit); |
548 | |
549 | // get size of stream and get sufficient storage for it |
550 | |
551 | if (section == 0) { |
552 | section = &getMetaSection(); |
553 | STATSTG statStg; |
554 | IfFailGoto((HRESULT)(metaStream->Stat(&statStg, STATFLAG_NONAME)), Exit); |
555 | |
556 | buffLen = statStg.cbSize.u.LowPart; |
557 | if(m_objSwitch) |
558 | { |
559 | CeeSection* pSect; |
560 | DWORD flags = IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_ALIGN_1BYTES; // 0x00100A00 |
561 | IfFailGoto(getSectionCreate(".cormeta" ,flags,&pSect,&m_metaIdx), Exit); |
562 | } |
563 | buffer = (BYTE *)section->getBlock(buffLen, sizeof(DWORD)); |
564 | IfNullGoto(buffer, Exit); |
565 | offset = getMetaSection().dataLen() - buffLen; |
566 | } |
567 | else { |
568 | _ASSERTE(buffer[buffLen-1] || true); // Dereference 'buffer' |
569 | _ASSERTE(section->computeOffset(PCHAR(buffer)) == offset); |
570 | } |
571 | |
572 | // reset seek pointer and read from stream |
573 | { |
574 | LARGE_INTEGER disp = { {0, 0} }; |
575 | IfFailGoto((HRESULT)metaStream->Seek(disp, STREAM_SEEK_SET, NULL), Exit); |
576 | } |
577 | ULONG metaDataLen; |
578 | IfFailGoto((HRESULT)metaStream->Read(buffer, buffLen+1, &metaDataLen), Exit); |
579 | |
580 | _ASSERTE(metaDataLen <= buffLen); |
581 | |
582 | #ifdef ENC_DELTA_HACK |
583 | { |
584 | extern int __cdecl fclose(FILE *); |
585 | WCHAR szFileName[256]; |
586 | DWORD len = GetEnvironmentVariable(W("COMP_ENC_EMIT" ), szFileName, ARRAYSIZE(szFileName)); |
587 | _ASSERTE(len < (ARRAYSIZE(szFileName) + 6)); // +6 for the .dmeta |
588 | if (len > 0 && len < (ARRAYSIZE(szFileName) + 6)) |
589 | { |
590 | wcscat_s(szFileName, ARRAYSIZE(szFileName), W(".dmeta" )); |
591 | FILE *pDelta; |
592 | int ec = _wfopen_s(&pDelta, szFileName, W("wb" )); |
593 | if (FAILED(ec)) { return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED); } |
594 | fwrite(buffer, 1, metaDataLen, pDelta); |
595 | fclose(pDelta); |
596 | } |
597 | } |
598 | #endif |
599 | |
600 | |
601 | // Set meta virtual address to offset of metadata within .meta, and |
602 | // and add a reloc for this offset, which will get turned |
603 | // into an rva when the pewriter writes out the file. |
604 | |
605 | m_corHeader->MetaData.VirtualAddress = VAL32(offset); |
606 | getCorHeaderSection().addSectReloc(m_corHeaderOffset + offsetof(IMAGE_COR20_HEADER, MetaData), *section, srRelocAbsolute); |
607 | m_corHeader->MetaData.Size = VAL32(metaDataLen); |
608 | |
609 | Exit: |
610 | |
611 | if (! m_fTokenMapSupported) { |
612 | // Remove the handler that we set |
613 | hr = emitter->SetHandler(NULL); |
614 | } |
615 | |
616 | #ifdef _DEBUG |
617 | if (FAILED(hr) && hr != E_OUTOFMEMORY) |
618 | _ASSERTE(!"Unexpected Failure" ); |
619 | #endif |
620 | |
621 | return hr; |
622 | } |
623 | |
624 | // Create the COM header - it goes at front of .meta section |
625 | // Need to do this before the meta data is copied in, but don't do at |
626 | // the same time because may not have metadata |
627 | HRESULT CCeeGen::() |
628 | { |
629 | HRESULT hr = S_OK; |
630 | CeeSection * = NULL; |
631 | if (m_corHdrIdx < 0) { |
632 | hr = getSectionCreate(".text0" , sdExecute, &corHeaderSection, &m_corHdrIdx); |
633 | TESTANDRETURNHR(hr); |
634 | |
635 | m_corHeaderOffset = corHeaderSection->dataLen(); |
636 | m_corHeader = (IMAGE_COR20_HEADER*)corHeaderSection->getBlock(sizeof(IMAGE_COR20_HEADER)); |
637 | if (! m_corHeader) |
638 | return E_OUTOFMEMORY; |
639 | memset(m_corHeader, 0, sizeof(IMAGE_COR20_HEADER)); |
640 | } |
641 | return S_OK; |
642 | } |
643 | |
644 | HRESULT CCeeGen::getMethodRVA(ULONG codeOffset, ULONG *codeRVA) |
645 | { |
646 | _ASSERTE(codeRVA); |
647 | // for runtime conversion, just return the offset and will calculate real address when need the code |
648 | *codeRVA = codeOffset; |
649 | return S_OK; |
650 | } |
651 | |
652 | HRESULT CCeeGen::getMapTokenIface(IUnknown **pIMapToken, IMetaDataEmit *emitter) |
653 | { |
654 | if (! pIMapToken) |
655 | return E_POINTER; |
656 | if (! m_pTokenMap) { |
657 | // Allocate the token mapper. As code is generated, each moved token will be added to |
658 | // the mapper and the client will also add a TokenMap reloc for it so we can update later |
659 | CeeGenTokenMapper *pMapper = new CeeGenTokenMapper; |
660 | if (pMapper == NULL) |
661 | { |
662 | return E_OUTOFMEMORY; |
663 | } |
664 | |
665 | if (emitter) { |
666 | HRESULT hr; |
667 | hr = emitter->QueryInterface(IID_IMetaDataImport, (PVOID *) &pMapper->m_pIImport); |
668 | _ASSERTE(SUCCEEDED(hr)); |
669 | } |
670 | m_pTokenMap = pMapper; |
671 | m_fTokenMapSupported = (emitter == 0); |
672 | |
673 | // If we've been holding onto a token remap handler waiting |
674 | // for the token mapper to get created, add it to the token |
675 | // mapper now and release our hold on it. |
676 | if (m_pRemapHandler && m_pTokenMap) |
677 | { |
678 | m_pTokenMap->AddTokenMapper(m_pRemapHandler); |
679 | m_pRemapHandler->Release(); |
680 | m_pRemapHandler = NULL; |
681 | } |
682 | } |
683 | *pIMapToken = getTokenMapper()->GetMapTokenIface(); |
684 | return S_OK; |
685 | } |
686 | |
687 | HRESULT CCeeGen::addNotificationHandler(IUnknown *pHandler) |
688 | { |
689 | // Null is no good... |
690 | if (!pHandler) |
691 | return E_POINTER; |
692 | |
693 | HRESULT hr = S_OK; |
694 | IMapToken *pIMapToken = NULL; |
695 | |
696 | // Is this an IMapToken? If so, we can put it to good use... |
697 | if (SUCCEEDED(pHandler->QueryInterface(IID_IMapToken, |
698 | (void**)&pIMapToken))) |
699 | { |
700 | // You gotta have a token mapper to use an IMapToken, though. |
701 | if (m_pTokenMap) |
702 | { |
703 | hr = m_pTokenMap->AddTokenMapper(pIMapToken); |
704 | pIMapToken->Release(); |
705 | } |
706 | else |
707 | { |
708 | // Hold onto it for later, just in case a token mapper |
709 | // gets created. We're holding a reference to it here, |
710 | // too. |
711 | m_pRemapHandler = pIMapToken; |
712 | } |
713 | } |
714 | |
715 | return hr; |
716 | } |
717 | |