//===- IRBuilder.h --------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // IRBuilder is a class used as a convenient way to create MCLinker sections // with a consistent and simplified interface. // //===----------------------------------------------------------------------===// #ifndef MCLD_IRBUILDER_H #define MCLD_IRBUILDER_H #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mcld { class Module; class LinkerConfig; class InputTree; /** \class IRBuilder * \brief IRBuilder provides an uniform API for creating sections and * inserting them into a input file. * * Ahead-of-time virtual machines (VM) usually compiles an intermediate * language into a system-dependent binary. IRBuilder helps such kind of VMs * to emit binaries in native object format, such as ELF or MachO. */ class IRBuilder { public: enum ObjectFormat { ELF, MachO, COFF }; enum SymbolDefinePolicy { Force, AsReferred }; enum SymbolResolvePolicy { Unresolve, Resolve }; public: IRBuilder(Module& pModule, const LinkerConfig& pConfig); ~IRBuilder(); const InputBuilder& getInputBuilder() const { return m_InputBuilder; } InputBuilder& getInputBuilder() { return m_InputBuilder; } const Module& getModule() const { return m_Module; } Module& getModule() { return m_Module; } /// @} /// @name Input Files On The Command Line /// @{ /// CreateInput - To create an input file and append it to the input tree. /// This function is like to add an input file in the command line. /// /// There are four types of the input files: /// - relocatable objects, /// - shared objects, /// - archives, /// - and user-defined objects. /// /// If Input::Unknown type is given, MCLinker will automatically /// open and read the input file, and create sections of the input. Otherwise, /// users need to manually create sections by IRBuilder. /// /// @see mcld::Input /// /// @param pName [in] The name of the input file. /// @param pPath [in] The path of the input file. /// @param pType [in] The type of the input file. MCLinker will parse the /// input file to create sections only if pType is /// Input::Unknown. /// @return the created mcld::Input. Input* CreateInput(const std::string& pName, const sys::fs::Path& pPath, Input::Type pType); /// ReadInput - To read an input file and append it to the input tree. /// This function is like to add an input file in the command line. /// /// This funciton is equal to call /// @ref IRBuilder::CreateInput(pName, pPath, Input::Unknown); /// /// MCLinker will automatically open and read the input file, and create /// sections of the input. /// /// @see mcld::Input /// /// @param pName [in] The name of the input file. /// @param pPath [in] The path of the input file. /// @return the created mcld::Input. Input* ReadInput(const std::string& pName, const sys::fs::Path& pPath); /// ReadInput - To read an input file and append it to the input tree. /// /// This function is equal to -l option. This function tells MCLinker to /// search for lib[pNameSpec].so or lib[pNameSpec].a in the search path. /// /// @param pNameSpec [in] The namespec of the input file. /// @return the created mcld::Input. Input* ReadInput(const std::string& pNameSpec); /// ReadInput - To read an input file and append it to the input tree. /// /// This function is like to add an input in the command line. /// /// LLVM compiler usually emits outputs by llvm::raw_ostream. /// mcld::raw_mem_ostream inherits llvm::raw_ostream and is suitable to be /// the output of LLVM compier. Users can connect LLVM compiler and MCLinker /// by passing mcld::raw_mem_ostream from LLVM compiler to MCLinker. /// /// @param pMemOStream [in] The input raw_mem_stream /// @param the create mcld::Input. Input* ReadInput(raw_mem_ostream& pMemOStream); /// ReadInput - To read an input file and append it to the input tree. /// Another way to open file manually. Use MCLinker's mcld::FileHandle. Input* ReadInput(FileHandle& pFileHandle); /// ReadInput - To read an input file and append it to the input tree. /// /// This function is like to add an input in the command line. /// /// This function tells MCLinker to read pRawMemory as an image of an object /// file. So far, MCLinekr only supports ELF object format, but it will /// support various object formats in the future. MCLinker relies triple to /// know the object format of pRawMemory. /// @param [in] pName The name of the input file /// @param [in] pRawMemory An image of object file /// @param [in] pSize The size of the memory /// @return The created mcld::Input Input* ReadInput(const std::string& pName, void* pRawMemory, size_t pSize); /// StartGroup - Add an opening tag of group. /// /// This function is equal to --start-group option. This function tells /// MCLinker to create a new archive group and to add the following archives /// in the created group. The archives in a group are searched repeatedly /// until no new undefined references are created. bool StartGroup(); /// EndGroup - Add a closing tag of group. /// /// This function is equal to --end-group option. This function tells /// MCLinker to stop adding following archives in the created group. bool EndGroup(); /// @} /// @name Positional Options On The Command Line /// @{ /// WholeArchive - Append a --whole-archive option on the command line /// /// This function is equal to --whole-archive option. This function tells /// MCLinker to include every object files in the following archives. void WholeArchive(); /// NoWholeArchive - Append a --no-whole-archive option on the command line. /// /// This function is equal to --no-whole-archive option. This function tells /// MCLinker to stop including every object files in the following archives. /// Only used object files in the following archives are included. void NoWholeArchive(); /// AsNeeded - Append a --as-needed option on the command line. /// /// This function is equal to --as-needed option. This function tells /// MCLinker to not add a DT_NEEDED tag in .dynamic sections for the /// following shared objects that are not really used. MCLinker will add tags // only for the following shared objects which is really used. void AsNeeded(); /// NoAsNeeded - Append a --no-as-needed option on the command line. /// /// This function is equal to --no-as-needed option. This function tells /// MCLinker to add a DT_NEEDED tag in .dynamic section for every shared /// objects that is created after this option. void NoAsNeeded(); /// CopyDTNeeded - Append a --add-needed option on the command line. /// /// This function is equal to --add-needed option. This function tells /// NCLinker to copy all DT_NEEDED tags of every following shared objects /// to the output file. void CopyDTNeeded(); /// NoCopyDTNeeded - Append a --no-add-needed option on the command line. /// /// This function is equal to --no-add-needed option. This function tells /// MCLinker to stop copying all DT_NEEDS tags in the following shared /// objects to the output file. void NoCopyDTNeeded(); /// AgainstShared - Append a -Bdynamic option on the command line. /// /// This function is equal to -Bdynamic option. This function tells MCLinker /// to search shared objects before archives for the following namespec. void AgainstShared(); /// AgainstStatic - Append a -static option on the command line. /// /// This function is equal to -static option. This function tells MCLinker to /// search archives before shared objects for the following namespec. void AgainstStatic(); /// @} /// @name Input Methods /// @{ /// CreateELFHeader - To create and append a section header in the input file /// /// @param OF [in] The file format. @see ObjectFormat /// @param pInput [in, out] The input file. /// @param pName [in] The name of the section. /// @param pType [in] The meaning of the content in the section. The /// value is format-dependent. In ELF, the value is /// SHT_* in normal. /// @param pFlag [in] The format-dependent flag. In ELF, the value is /// SHF_* in normal. /// @param pAlign [in] The alignment constraint of the section /// @return The created section header. static LDSection* CreateELFHeader(Input& pInput, const std::string& pName, uint32_t pType, uint32_t pFlag, uint32_t pAlign); /// CreateSectionData - To create a section data for given pSection. /// @param [in, out] pSection The given LDSection. It can be in either an /// input or the output. /// pSection.getSectionData() is set to a valid section data. /// @return The created section data. If the pSection already has section /// data, or if the pSection's type should not have a section data /// (.eh_frame or relocation data), then an assertion occurs. static SectionData* CreateSectionData(LDSection& pSection); /// CreateRelocData - To create a relocation data for given pSection. /// @param [in, out] pSection The given LDSection. It can be in either an /// input or the output. /// pSection.getRelocData() is set to a valid relocation data. /// @return The created relocation data. If the pSection already has /// relocation data, or if the pSection's type is not /// LDFileFormat::Relocation, then an assertion occurs. static RelocData* CreateRelocData(LDSection &pSection); /// CreateEhFrame - To create a eh_frame for given pSection /// @param [in, out] pSection The given LDSection. It can be in either an /// input or the output. /// pSection.getEhFrame() is set to a valid eh_frame. /// @return The created eh_frame. If the pSection already has eh_frame data, /// or if the pSection's type is not LDFileFormat::EhFrame, then an /// assertion occurs. static EhFrame* CreateEhFrame(LDSection& pSection); /// CreateBSS - To create a bss section for given pSection /// @param [in, out] pSection The given LDSection. It can be in either an /// input or the output. /// pSection.getSectionData() is set to a valid section data and /// contains a fillment fragment whose size is pSection.size(). /// @return The create section data. It the pSection already has a section /// data, or if the pSection's type is not LDFileFormat::BSS, then /// an assertion occurs. static SectionData* CreateBSS(LDSection& pSection); /// CreateRegion - To create a region fragment in the input file. /// This function tells MCLinker to read a piece of data from the input /// file, and to create a region fragment that carries the data. The data /// will be deallocated automatically when pInput is destroyed. /// /// @param pInput [in, out] The input file. /// @param pOffset [in] The starting file offset of the data /// @param pLength [in] The number of bytes of the data /// @return If pLength is zero or failing to request a region, return a /// FillFragment. static Fragment* CreateRegion(Input& pInput, size_t pOffset, size_t pLength); /// CreateRegion - To create a region fragment wrapping the given memory. /// This function tells MCLinker to create a region fragment by the data /// directly. Since the data is given from outside, not read from the input /// file, users should deallocated the data manually. /// /// @param pMemory [in] The start address of the given data /// @param pLength [in] The number of bytes of the data /// @return If pLength is zero or failing to request a region, return a /// FillFragment. static Fragment* CreateRegion(void* pMemory, size_t pLength); /// AppendFragment - To append pFrag to the given SectionData pSD. /// This function tells MCLinker to append a fragment to section data, and /// update size of the section header. /// /// @note In order to keep the alignment of pFrag, This function inserts an /// AlignFragment before pFrag if the section header's alignment is larger /// than 1. /// @note This function does not update offset of section headers. /// /// @param pFrag [in, out] The appended fragment. Its offset is set as the /// section offset in pSD. /// @param pSD [in, out] The section data. Size of the header is also /// updated. /// @return Total size of the inserted fragments. static uint64_t AppendFragment(Fragment& pFrag, SectionData& pSD); /// AppendRelocation - To append a relocation to a relocation data. /// This function tells MCLinker to add a general relocation to the /// relocation data. This function does not update offset and size of section /// headers. /// /// @param pReloc [in] The appended relocation. /// @param pRD [in, out] The relocation data being appended. static void AppendRelocation(Relocation& pRelocation, RelocData& pRD); /// AppendEhFrame - To append a fragment to a EhFrame. /// @note In order to keep the alignment of pFrag, This function inserts an /// AlignFragment before pFrag if the section header's alignment is larger /// than 1. /// @note This function also update size of the section header, but does not /// update header's offset. /// /// @param pFrag [in, out] The appended fragment. /// @param pEhFrame [in, out] The EhFrame. /// @return Total size of the inserted fragments. static uint64_t AppendEhFrame(Fragment& pFrag, EhFrame& pEhFrame); /// AppendEhFrame - To append a FDE to the given EhFrame pEhFram. /// @note In order to keep the alignment of pFrag, This function inserts an /// AlignFragment before pFrag if the section header's alignment is larger /// than 1. /// @note This function also update size of the section header, but does not /// update header's offset. /// /// @param [in, out] pFDE The appended FDE entry. /// @param [in, out] pEhFrame The eh_frame being appended. /// @return Total size of the inserted fragments. static uint64_t AppendEhFrame(EhFrame::FDE& pFDE, EhFrame& pEhFrame); /// AppendEhFrame - To append a CIE to the given EhFrame pEhFram. /// @note In order to keep the alignment of pFrag, This function inserts an /// AlignFragment before pFrag if the section header's alignment is larger /// than 1. /// @note This function also update size of the section header, but does not /// update header's offset. /// /// @param [in, out] pCIE The appended CIE entry. /// @param [in, out] pEhFrame The eh_frame being appended. /// @return Total size of the inserted fragments. static uint64_t AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame); /// AddSymbol - To add a symbol to the input file. /// This function create a new symbol and insert it into the input file. If /// mcld::Module has another symbol with the same name, then this function /// resolves these two symbols and keeps one in mcld::Module by their /// attributes. /// /// This is a general method for all kinds of symbol. /// /// @param [in, out] pInput The input file. Either a relocatable or dynamic /// object /// @param [in] pName The name of the symbol /// @param [in] pType What the symbol refers to. May be a object, /// function, no-type and so on. @see ResolveInfo /// @param [in] pDesc { Undefined, Define, Common, Indirect } /// @param [in] pBind { Global, Weak, Local, Absolute } /// @param [in] pSize The size of the symbol. Bigger common symbols /// overrides the smaller common symbols. /// @param [in] pValue Common symbols' value are alignment constraints /// Undefined symbols don't have value. /// The rest symbols' value are relative section /// offset. /// @param [in] pSection Absolute, undefined, common symbols do not have /// pSection. Keep their pSection be NULL. /// @oaram [in] pVis The visibility of the symbol /// /// @return The added symbol. If the insertion fails due to the resoluction, /// return NULL. LDSymbol* AddSymbol(Input& pInput, const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBind, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue = 0x0, LDSection* pSection = NULL, ResolveInfo::Visibility pVis = ResolveInfo::Default); /// AddSymbol - To add a symbol in mcld::Module /// This function create a new symbol and insert it into mcld::Module. /// /// @tparam POLICY idicate the condition to define or not to define the /// symbol. /// - AsRefered /// - Define a symbol only if mcld::Module contains a symbol with /// identical name. If mcld::Module does not have any symbol with /// the same name, this function returns NULL. /// /// - Force /// - Define a symbol no matter mcld::Module has a symbol with identical /// name or not. /// /// @tparam RESOLVE indicate the method to define a symbol. If we must define /// a symbol in mcld::Module, then how to define it. /// /// - Resolve /// - Follow the symbol resolution rule to bind the symbol references. /// Resolution of the symbols with idential name depends on their /// attributes. /// /// - Unresolve /// - Forcefully override the symbol in mcld::Module. With this /// argument, AddSymbol function turns a blind eye to symbol /// resolution rules. /// /// @param [in] pName The name of the symbol /// @param [in] pType The type of the symbol /// @param [in] pDesc The description of the symbol, Could be one of /// { Undefined, Define, Common, Indirect } /// @param [in] pBinding The binding of the symbol. Could be one of /// { Global, Weak, Local, Absolute } /// /// @return The symbol kept in mcld::Module. template LDSymbol* AddSymbol(const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize = 0, LDSymbol::ValueType pValue = 0x0, FragmentRef* pFragmentRef = FragmentRef::Null(), ResolveInfo::Visibility pVisibility = ResolveInfo::Default); /// AddRelocation - To add a relocation entry /// /// @param [in] pSection The relocation section. pSection's link should point to /// the target section. /// @param [in] pType The type of the relocation (target dependent) /// @param [in] pSym The symbol should be the symbol in the input file. /// @param [in] pOffset The offset of target section. /// @param [in] pAddend Tthe addend value for applying relocation static Relocation* AddRelocation(LDSection& pSection, Relocation::Type pType, LDSymbol& pSym, uint32_t pOffset, Relocation::Address pAddend = 0); private: LDSymbol* addSymbolFromObject(const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); LDSymbol* addSymbolFromDynObj(Input& pInput, const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, ResolveInfo::Visibility pVisibility); private: Module& m_Module; const LinkerConfig& m_Config; InputBuilder m_InputBuilder; }; template<> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); template<> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); template<> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); template<> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); } // end of namespace mcld #endif