// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // =========================================================================== // File: CEEGEN.H // // =========================================================================== #ifndef _CEEGEN_H_ #define _CEEGEN_H_ #include "cor.h" #include "iceefilegen.h" #include "ceegentokenmapper.h" class CeeSection; class CeeSectionString; class CCeeGen; class PESectionMan; class PESection; typedef DWORD StringRef; #if 0 This is a description of the current implementation of these types for generating CLR modules. ICeeGen - interface to generate in-memory CLR module. CCeeGen - implementation of ICeeGen. Currently it uses both CeeSections as well as PESections (inside PESectionMan), and maintains a 1:1 relation between them. This is ugly. CeeFileGenWriter - Provides functionality to write in-memory module to PE format file. Uses PEWriter (m_pSectionMan) for file-writing functionality PEWriter - It can generate a PE format file. It also knows to apply pointer relocs when it lays out the PESections. ICeeFileGen - Interface used by compilers, ngen, etc, to generate a CLR file. Has a bunch of methods to emit signatures, tokens, methods, etc which are not implemented. These are left over from before CeeFileGenWriter, PEWriter and ICeeFileGen are implemented in mscorpe.dll. The other types live in mscorwks.dll (src\md\CeeFileGen) +----------------------------+ | ICeeGen | | | | COM-style version of | | ICeeFileGen. HCEEFILE is | | replaced with "this" | +-------------------------+ | | | CeeSectionImpl | +----------------------------+ +-------------------------+ | | | | | | v | v +---------------------------+ | +------------+ | CCeeGen | | | | +---------------------------+ | | CeeSection | contains | | | | |<-------------| CeeSection* m_sections | | +------------+ | | | /| PESectionMan m_pSectionMan| | / | | | +-----------------+ / +---------------------------+ v | PESectionMan |<----+ | +-----------+ | | contains | | PESection | +-----------------+ | | | contains | PESection * | v | |<----------| sectStart, | +------------------------------+ +-----------+ | sectCur, | | CeeFileGenWriter | | sectEnd | +------------------------------+ +-----------------+ | Does meta-data specific | | | stuff and then dispatches to | | | m_pSectionMan.PEWriter::***()| | | | v +------------------------------+ +------------------------+ ^ | PEWriter | |wraps +------------------------+ | | Low -level file writer | +----------------------------+ | Knows how to do | | ICeeFileGen | | pointer relocs | | | | | | C-style inteface. Deals | +------------------------+ | with HCEEFILE, HCEESECTION | | etc. It is mostly just a | | thin wrapper for a | | CeeFileGenWriter | +----------------------------+ #endif // 0 // ***** CeeSection classes class CeeSectionImpl { public: virtual unsigned dataLen() = 0; virtual char * getBlock( unsigned len, unsigned align = 1) = 0; virtual HRESULT addSectReloc( unsigned offset, CeeSection & relativeTo, CeeSectionRelocType reloc = srRelocAbsolute, CeeSectionRelocExtra * extra = NULL) = 0; virtual HRESULT addBaseReloc( unsigned offset, CeeSectionRelocType reloc = srRelocHighLow, CeeSectionRelocExtra * extra = NULL) = 0; virtual HRESULT directoryEntry(unsigned num) = 0; virtual unsigned char * name() = 0; virtual char * computePointer(unsigned offset) const = 0; virtual BOOL containsPointer(__in char * ptr) const = 0; virtual unsigned computeOffset(__in char * ptr) const = 0; virtual unsigned getBaseRVA() = 0; virtual void SetInitialGrowth(unsigned growth) = 0; }; class CeeSection { // m_ceeFile allows inter-section communication CCeeGen &m_ceeFile; // abstract away implementation to allow inheritance from CeeSection CeeSectionImpl &m_impl; public: enum RelocFlags { RELOC_NONE = 0, // address should be fixed up to be a RVA not a normal address RELOC_RVA = 1 }; CeeSection(CCeeGen &ceeFile, CeeSectionImpl &impl) : m_ceeFile(ceeFile), m_impl(impl) { LIMITED_METHOD_CONTRACT; } virtual ~CeeSection() {LIMITED_METHOD_CONTRACT; } // bytes in this section at present unsigned dataLen(); // section base, after linking unsigned getBaseRVA(); // get a block to write on (use instead of write to avoid copy) char* getBlock(unsigned len, unsigned align=1); // Indicates that the DWORD at 'offset' in the current section should // have the base of section 'relativeTo added to it HRESULT addSectReloc(unsigned offset, CeeSection& relativeTo, CeeSectionRelocType = srRelocAbsolute, CeeSectionRelocExtra *extra = 0); // Add a base reloc for the given offset in the current section virtual HRESULT addBaseReloc(unsigned offset, CeeSectionRelocType reloc = srRelocHighLow, CeeSectionRelocExtra *extra = 0); // this section will be directory entry 'num' HRESULT directoryEntry(unsigned num); // return section name unsigned char *name(); // simulate the base + offset with a more complex data storage char * computePointer(unsigned offset) const; BOOL containsPointer(__in char *ptr) const; unsigned computeOffset(__in char *ptr) const; CeeSectionImpl &getImpl(); CCeeGen &ceeFile(); void SetInitialGrowth(unsigned growth); }; // ***** CCeeGen class // Only handles in memory stuff // Base class for CeeFileGenWriter (which actually generates PEFiles) class CCeeGen : public ICeeGen, ICeeGenInternal { LONG m_cRefs; BOOL m_encMode; protected: short m_textIdx; // m_sections[] index for the .text section short m_metaIdx; // m_sections[] index for metadata (.text, or .cormeta for obj files) short m_corHdrIdx; // m_sections[] index for the COM+ header (.text0) short m_stringIdx; // m_sections[] index for strings (.text, or .rdata for EnC) short m_ilIdx; // m_sections[] index for IL (.text) bool m_objSwitch; CeeGenTokenMapper *m_pTokenMap; BOOLEAN m_fTokenMapSupported; // temporary to support both models IMapToken *m_pRemapHandler; CeeSection **m_sections; short m_numSections; short m_allocSections; PESectionMan * m_peSectionMan; IMAGE_COR20_HEADER *m_corHeader; DWORD m_corHeaderOffset; HRESULT allocateCorHeader(); HRESULT addSection(CeeSection *section, short *sectionIdx); HRESULT setEnCMode(); // Init process: Call static CreateNewInstance() , not operator new protected: HRESULT Init(); CCeeGen(); public: virtual ~CCeeGen() {} static HRESULT CreateNewInstance(CCeeGen* & pCeeFileGen); // call this to instantiate virtual HRESULT Cleanup(); // ICeeGen interfaces ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); STDMETHODIMP QueryInterface( REFIID riid, void **ppInterface); STDMETHODIMP EmitString ( __in LPWSTR lpString, // [IN] String to emit ULONG *RVA); STDMETHODIMP GetString ( ULONG RVA, __inout LPWSTR *lpString); STDMETHODIMP AllocateMethodBuffer ( ULONG cchBuffer, // [IN] Length of string to emit UCHAR **lpBuffer, // [OUT] Returned buffer ULONG *RVA); STDMETHODIMP GetMethodBuffer ( ULONG RVA, UCHAR **lpBuffer); STDMETHODIMP GetIMapTokenIface ( IUnknown **pIMapToken); STDMETHODIMP GenerateCeeFile (); STDMETHODIMP GetIlSection ( HCEESECTION *section); STDMETHODIMP GetStringSection ( HCEESECTION *section); STDMETHODIMP AddSectionReloc ( HCEESECTION section, ULONG offset, HCEESECTION relativeTo, CeeSectionRelocType relocType); STDMETHODIMP GetSectionCreate ( const char *name, DWORD flags, HCEESECTION *section); STDMETHODIMP GetSectionDataLen ( HCEESECTION section, ULONG *dataLen); STDMETHODIMP GetSectionBlock ( HCEESECTION section, ULONG len, ULONG align=1, void **ppBytes=0); STDMETHODIMP TruncateSection ( HCEESECTION section, ULONG len); STDMETHODIMP GenerateCeeMemoryImage (void **ppImage); STDMETHODIMP ComputePointer ( HCEESECTION section, ULONG RVA, // [IN] RVA for method to return UCHAR **lpBuffer); // [OUT] Returned buffer STDMETHODIMP AddNotificationHandler(IUnknown *pHandler); // Write the metadata in "emitter" to the default metadata section is "section" is 0 // If 'section != 0, it will put the data in 'buffer'. This // buffer is assumed to be in 'section' at 'offset' and of size 'buffLen' // (should use GetSaveSize to insure that buffer is big enough virtual HRESULT emitMetaData(IMetaDataEmit *emitter, CeeSection* section=0, DWORD offset=0, BYTE* buffer=0, unsigned buffLen=0); virtual HRESULT getMethodRVA(ULONG codeOffset, ULONG *codeRVA); STDMETHODIMP SetInitialGrowth(DWORD growth); CeeSection &getTextSection(); CeeSection &getMetaSection(); CeeSection &getCorHeaderSection(); CeeSectionString &getStringSection(); CeeSection &getIlSection(); virtual HRESULT getSectionCreate (const char *name, DWORD flags, CeeSection **section=NULL, short *sectionIdx = NULL); PESectionMan* getPESectionMan() { LIMITED_METHOD_CONTRACT; return m_peSectionMan; } virtual HRESULT getMapTokenIface(IUnknown **pIMapToken, IMetaDataEmit *emitter=0); CeeGenTokenMapper *getTokenMapper() { LIMITED_METHOD_CONTRACT; return m_pTokenMap; } virtual HRESULT addNotificationHandler(IUnknown *pHandler); //Clone is actually a misnomer here. This method will copy all of the //instance variables and then do a deep copy (as necessary) of the sections. //Section data will be appended onto any information already in the section. //This is done to support the DynamicIL -> PersistedIL transform. virtual HRESULT cloneInstance(CCeeGen *destination); #ifdef EMIT_FIXUPS public: virtual HRESULT addFixup(CeeSection& sectionSource, unsigned offset, CeeSectionRelocType reloc, CeeSection * sectionTarget = NULL, CeeSectionRelocExtra *extra = 0) { LIMITED_METHOD_CONTRACT; return(E_NOTIMPL); } #endif }; // ***** CeeSection inline methods inline unsigned CeeSection::dataLen() { WRAPPER_NO_CONTRACT; return m_impl.dataLen(); } inline unsigned CeeSection::getBaseRVA() { WRAPPER_NO_CONTRACT; return m_impl.getBaseRVA(); } inline char *CeeSection::getBlock(unsigned len, unsigned align) { WRAPPER_NO_CONTRACT; return m_impl.getBlock(len, align); } inline HRESULT CeeSection::addSectReloc( unsigned offset, CeeSection& relativeTo, CeeSectionRelocType reloc, CeeSectionRelocExtra *extra) { WRAPPER_NO_CONTRACT; return(m_impl.addSectReloc(offset, relativeTo, reloc, extra)); } inline HRESULT CeeSection::addBaseReloc(unsigned offset, CeeSectionRelocType reloc, CeeSectionRelocExtra *extra) { WRAPPER_NO_CONTRACT; return(m_impl.addBaseReloc(offset, reloc, extra)); } inline HRESULT CeeSection::directoryEntry(unsigned num) { WRAPPER_NO_CONTRACT; TESTANDRETURN(num < IMAGE_NUMBEROF_DIRECTORY_ENTRIES, E_INVALIDARG); m_impl.directoryEntry(num); return S_OK; } inline CCeeGen &CeeSection::ceeFile() { LIMITED_METHOD_CONTRACT; return m_ceeFile; } inline CeeSectionImpl &CeeSection::getImpl() { LIMITED_METHOD_CONTRACT; return m_impl; } inline unsigned char *CeeSection::name() { WRAPPER_NO_CONTRACT; return m_impl.name(); } inline char * CeeSection::computePointer(unsigned offset) const { WRAPPER_NO_CONTRACT; return m_impl.computePointer(offset); } inline BOOL CeeSection::containsPointer(__in char *ptr) const { WRAPPER_NO_CONTRACT; return m_impl.containsPointer(ptr); } inline unsigned CeeSection::computeOffset(__in char *ptr) const { WRAPPER_NO_CONTRACT; return m_impl.computeOffset(ptr); } inline void CeeSection::SetInitialGrowth(unsigned growth) { WRAPPER_NO_CONTRACT; m_impl.SetInitialGrowth(growth); } // ***** CCeeGen inline methods inline CeeSection &CCeeGen::getTextSection() { LIMITED_METHOD_CONTRACT; return *m_sections[m_textIdx]; } inline CeeSection &CCeeGen::getMetaSection() { LIMITED_METHOD_CONTRACT; return *m_sections[m_metaIdx]; } inline CeeSection &CCeeGen::getCorHeaderSection() { LIMITED_METHOD_CONTRACT; _ASSERTE(m_corHdrIdx >= 0); return *m_sections[m_corHdrIdx]; } inline CeeSectionString &CCeeGen::getStringSection() { LIMITED_METHOD_CONTRACT; return *(CeeSectionString*)m_sections[m_stringIdx]; } inline CeeSection &CCeeGen::getIlSection() { LIMITED_METHOD_CONTRACT; return *m_sections[m_ilIdx]; } #endif