HRESULT CCeeGen::getMapTokenIface(IUnknown **pIMapToken, IMetaDataEmit *emitter) { if (! pIMapToken) return E_POINTER; if (! m_pTokenMap) { // Allocate the token mapper. As code is generated, each moved token will be added to // the mapper and the client will also add a TokenMap reloc for it so we can update later CeeGenTokenMapper *pMapper = new CeeGenTokenMapper; TESTANDRETURN(pMapper != NULL, E_OUTOFMEMORY); if (emitter) { #ifdef _DEBUG HRESULT hr = #endif emitter->QueryInterface(IID_IMetaDataImport, (PVOID *) &pMapper->m_pIImport); _ASSERTE(SUCCEEDED(hr)); } m_pTokenMap = pMapper; m_fTokenMapSupported = (emitter == 0); // If we've been holding onto a token remap handler waiting // for the token mapper to get created, add it to the token // mapper now and release our hold on it. if (m_pRemapHandler && m_pTokenMap) { m_pTokenMap->AddTokenMapper(m_pRemapHandler); m_pRemapHandler->Release(); m_pRemapHandler = NULL; } } *pIMapToken = getTokenMapper()->GetMapTokenIface(); return S_OK; }
HRESULT CCeeGen::getSectionCreate (const char *name, DWORD flags, CeeSection **section, short *sectionIdx) { if (strcmp(name, ".il") == 0) name = ".text"; else if (strcmp(name, ".meta") == 0) name = ".text"; else if (strcmp(name, ".rdata") == 0 && !m_encMode) name = ".text"; for (int i=0; i<m_numSections; i++) { if (strcmp((const char *)m_sections[i]->name(), name) == 0) { if (section) *section = m_sections[i]; if (sectionIdx) *sectionIdx = i; return S_OK; } } PESection *pewSect = NULL; HRESULT hr = m_peSectionMan->getSectionCreate(name, flags, &pewSect); TESTANDRETURNHR(hr); CeeSection *newSect = new CeeSection(*this, *pewSect); // if this fails, the PESection will get nuked in the destructor for CCeeGen TESTANDRETURN(newSect != NULL, E_OUTOFMEMORY); hr = addSection(newSect, sectionIdx); TESTANDRETURNHR(hr); if (section) *section = newSect; return S_OK; }
HRESULT CeeFileGenWriter::setLibraryName(LPWSTR libraryName) { if (m_libraryName) delete[] m_libraryName; m_libraryName = (LPWSTR)new WCHAR[(lstrlenW(libraryName) + 1)]; TESTANDRETURN(m_libraryName != NULL, E_OUTOFMEMORY); wcscpy(m_libraryName, libraryName); return S_OK; } // HRESULT CeeFileGenWriter::setLibraryName()
HRESULT CeeFileGenWriter::setResourceFileName(LPWSTR fileName) { if (m_resourceFileName) delete[] m_resourceFileName; m_resourceFileName = (LPWSTR)new WCHAR[(lstrlenW(fileName) + 1)]; TESTANDRETURN(m_resourceFileName!=NULL, E_OUTOFMEMORY); wcscpy(m_resourceFileName, fileName); return S_OK; } // HRESULT CeeFileGenWriter::setResourceFileName()
// For EnC mode, generate strings into .rdata section rather than .text section HRESULT CCeeGen::setEnCMode() { PESection *section = NULL; HRESULT hr = m_peSectionMan->getSectionCreate(".rdata", sdExecute, §ion); TESTANDRETURNHR(hr); CeeSection *ceeSection = new CeeSectionString(*this, *section); TESTANDRETURN(ceeSection != NULL, E_OUTOFMEMORY); hr = addSection(ceeSection, &m_stringIdx); if (SUCCEEDED(hr)) m_encMode = TRUE; return hr; }
HRESULT CeeSectionString::getEmittedStringRef(__in_z LPWSTR target, StringRef *ref) { TESTANDRETURN(ref!=NULL, E_POINTER); ULONG hashId = HashString(target) % MaxVirtualEntries; ULONG bucketIndex = hashId / MaxRealEntries; StringTableEntry *entry; entry = findStringInsert(stringTable[bucketIndex], target, hashId); if (! entry) return E_OUTOFMEMORY; *ref = entry->m_offset; return S_OK; }
HRESULT CeeFileGenWriter::CreateNewInstance(CCeeGen *pCeeFileGenFrom, CeeFileGenWriter* & pGenWriter) { pGenWriter = new CeeFileGenWriter; TESTANDRETURN(pGenWriter, E_OUTOFMEMORY); PEWriter *pPEWriter = new PEWriter; TESTANDRETURN(pPEWriter, E_OUTOFMEMORY); //HACK HACK HACK. //What's really the correct thing to be doing here? //HRESULT hr = pPEWriter->Init(pCeeFileGenFrom ? pCeeFileGenFrom->getPESectionMan() : NULL); HRESULT hr = pPEWriter->Init(NULL); TESTANDRETURNHR(hr); //Create the general PEWriter. pGenWriter->m_peSectionMan = pPEWriter; hr = pGenWriter->Init(); // base class member to finish init TESTANDRETURNHR(hr); pGenWriter->setImageBase(CEE_IMAGE_BASE); // use same default as linker pGenWriter->setSubsystem(IMAGE_SUBSYSTEM_WINDOWS_CUI, CEE_IMAGE_SUBSYSTEM_MAJOR_VERSION, CEE_IMAGE_SUBSYSTEM_MINOR_VERSION); hr = pGenWriter->allocateIAT(); // so iat goes out first TESTANDRETURNHR(hr); hr = pGenWriter->allocateCorHeader(); // so cor header near front TESTANDRETURNHR(hr); //If we were passed a CCeeGen at the beginning, copy it's data now. if (pCeeFileGenFrom) { pCeeFileGenFrom->cloneInstance((CCeeGen*)pGenWriter); } // set il RVA to be after the preallocated sections pPEWriter->setIlRva(pGenWriter->m_iDataSectionIAT->dataLen()); return hr; } // HRESULT CeeFileGenWriter::CreateNewInstance()
HRESULT CCeeGen::emitMetaData(IMetaDataEmit *emitter, CeeSection* section, DWORD offset, BYTE* buffer, unsigned buffLen) { HRESULT hr; if (! m_fTokenMapSupported) { IUnknown *pMapTokenIface; hr = getMapTokenIface(&pMapTokenIface, emitter); _ASSERTE(SUCCEEDED(hr)); // Set a callback for token remap and save the tokens which change. hr = emitter->SetHandler(pMapTokenIface); _ASSERTE(SUCCEEDED(hr)); } // generate the metadata IStream *metaStream; int rc = CreateStreamOnHGlobal(NULL, TRUE, &metaStream); _ASSERTE(rc == S_OK); hr = emitter->SaveToStream(metaStream, 0); _ASSERTE(SUCCEEDED(hr)); // get size of stream and get sufficient storage for it if (section == 0) { section = &getMetaSection(); STATSTG statStg; rc = metaStream->Stat(&statStg, STATFLAG_NONAME); _ASSERTE(rc == S_OK); buffLen = statStg.cbSize.u.LowPart; if(m_objSwitch) { CeeSection* pSect; DWORD flags = IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_ALIGN_1BYTES; // 0x00100A00 hr = getSectionCreate(".cormeta",flags,&pSect,&m_metaIdx); } buffer = (BYTE *)section->getBlock(buffLen, sizeof(DWORD)); TESTANDRETURN(buffer, E_OUTOFMEMORY); offset = getMetaSection().dataLen() - buffLen; } // reset seek pointer and read from stream LARGE_INTEGER disp = { {0, 0} }; rc = metaStream->Seek(disp, STREAM_SEEK_SET, NULL); _ASSERTE(rc == S_OK); ULONG metaDataLen; rc = metaStream->Read(buffer, buffLen+1, &metaDataLen); // +1 so assert below will fire. _ASSERTE(metaDataLen <= buffLen); metaStream->Release(); if (! m_fTokenMapSupported) { // Remove the handler that we set hr = emitter->SetHandler(NULL); TESTANDRETURNHR(hr); } // Set meta virtual address to offset of metadata within .meta, and // and add a reloc for this offset, which will get turned // into an rva when the pewriter writes out the file. m_corHeader->MetaData.VirtualAddress = VAL32(offset); getCorHeaderSection().addSectReloc(m_corHeaderOffset + offsetof(IMAGE_COR20_HEADER, MetaData), *section, srRelocAbsolute); m_corHeader->MetaData.Size = VAL32(metaDataLen); return S_OK; }