diff options
author | Pirama Arumuga Nainar <pirama@google.com> | 2016-03-18 21:54:50 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-03-18 21:54:52 +0000 |
commit | e1ebaae92243025b384676c97f8c012a850e337a (patch) | |
tree | a7befed71dbf26f45a068ee673db6d79e8b3e404 | |
parent | a4e968f7c0528fb5bc8d80d83ae0b061f965f2b1 (diff) | |
parent | 07177ff8032d136567f3e99d372cb67713f1bba8 (diff) | |
download | mclinker-n-iot-preview-2.tar.gz |
Merge changes from topic 'rebase_r256229'android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-iot-preview-2nougat-mr1-wear-releasen-iot-preview-2
* changes:
Fix up mclinker so that it builds/runs for LLVM rebase to r256229.
Rebase mclinker for LLVM update to r256229.
78 files changed, 3673 insertions, 913 deletions
diff --git a/include/mcld/Fragment/Fragment.h b/include/mcld/Fragment/Fragment.h index 76a5028..3e84811 100644 --- a/include/mcld/Fragment/Fragment.h +++ b/include/mcld/Fragment/Fragment.h @@ -24,7 +24,7 @@ class SectionData; /** \class Fragment * \brief Fragment is the minimun linking unit of MCLinker. */ -class Fragment : public llvm::ilist_node<Fragment> { +class Fragment : public llvm::ilist_node_with_parent<Fragment, SectionData> { public: enum Type { Alignment, Fillment, Region, Target, Stub, Null }; diff --git a/include/mcld/Fragment/Stub.h b/include/mcld/Fragment/Stub.h index 94f58e9..3ef72ec 100644 --- a/include/mcld/Fragment/Stub.h +++ b/include/mcld/Fragment/Stub.h @@ -20,6 +20,8 @@ namespace mcld { +class BranchIsland; +class IRBuilder; class Relocation; class ResolveInfo; @@ -63,9 +65,15 @@ class Stub : public Fragment { /// isMyDuty - return true when the pReloc is problematic and the stub is able /// to fix it! - virtual bool isMyDuty(const class Relocation& pReloc, + virtual bool isMyDuty(const Relocation& pReloc, uint64_t pSource, - uint64_t pTargetSymValue) const = 0; + uint64_t pTargetSymValue) const { + return false; + } + + virtual bool isMyDuty(const FragmentRef& pFragRef) const { + return false; + } /// name - name of this stub virtual const std::string& name() const = 0; @@ -96,6 +104,16 @@ class Stub : public Fragment { const_fixup_iterator fixup_end() const { return m_FixupList.end(); } + size_t fixup_size() const { return m_FixupList.size(); } + + virtual void applyFixup(Relocation& pSrcReloc, + IRBuilder& pBuilder, + BranchIsland& pIsland); + + virtual void applyFixup(FragmentRef& pSrcFragRef, + IRBuilder& pBuilder, + BranchIsland& pIsland); + /// ----- modifiers ----- /// void setSymInfo(ResolveInfo* pSymInfo); @@ -113,6 +131,9 @@ class Stub : public Fragment { /// addFixup - add a fixup from a existing fixup of the prototype void addFixup(const Fixup& pFixup); + const FixupListType& getFixupList() const { return m_FixupList; } + FixupListType& getFixupList() { return m_FixupList; } + private: /// doClone - when adding a backend stub, we should implement this function virtual Stub* doClone() = 0; diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h index 787c5eb..5b9c92b 100644 --- a/include/mcld/GeneralOptions.h +++ b/include/mcld/GeneralOptions.h @@ -251,11 +251,6 @@ class GeneralOptions { bool genUnwindInfo() const { return m_bGenUnwindInfo; } - // -G, max GP size option - void setGPSize(int gpsize) { m_GPSize = gpsize; } - - int getGPSize() const { return m_GPSize; } - HashStyle getHashStyle() const { return m_HashStyle; } bool hasGNUHash() const { @@ -388,7 +383,6 @@ class GeneralOptions { bool m_bPrintICFSections : 1; // --print-icf-sections ICF m_ICF; size_t m_ICFIterations; - uint32_t m_GPSize; // -G, --gpsize StripSymbolMode m_StripSymbols; RpathList m_RpathList; ScriptList m_ScriptList; diff --git a/include/mcld/IRBuilder.h b/include/mcld/IRBuilder.h index b68b8fa..e613dac 100644 --- a/include/mcld/IRBuilder.h +++ b/include/mcld/IRBuilder.h @@ -353,6 +353,9 @@ class IRBuilder { /// @return Total size of the inserted fragments. static uint64_t AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame); + /// CreateLocalSymbol - Create a local symbol at the given FragmentRef. + ResolveInfo* CreateLocalSymbol(FragmentRef& pFragRef); + /// 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 diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h index c57e5fb..1e7ccda 100644 --- a/include/mcld/LD/BranchIsland.h +++ b/include/mcld/LD/BranchIsland.h @@ -74,6 +74,8 @@ class BranchIsland { const_reloc_iterator reloc_end() const { return m_Relocations.end(); } /// observers + SectionData* getParent() const { return m_Entry.getParent(); } + uint64_t offset() const; size_t size() const; @@ -91,6 +93,8 @@ class BranchIsland { /// addStub - add a stub into the island bool addStub(const Stub* pPrototype, const Relocation& pReloc, Stub& pStub); + void addStub(Stub& pStub); + /// addRelocation - add a relocation into island bool addRelocation(Relocation& pReloc); @@ -159,7 +163,7 @@ class BranchIsland { Fragment& m_Entry; // entry fragment of the island Fragment* m_pExit; // exit fragment of the island Fragment* m_pRear; // rear fragment of the island - size_t m_MaxSize; + const size_t m_MaxSize; std::string m_Name; StubMapType m_StubMap; /// m_Relocations - list of relocations created for stubs in this island diff --git a/include/mcld/LD/BranchIslandFactory.h b/include/mcld/LD/BranchIslandFactory.h index 575d40f..545173d 100644 --- a/include/mcld/LD/BranchIslandFactory.h +++ b/include/mcld/LD/BranchIslandFactory.h @@ -28,11 +28,10 @@ class BranchIslandFactory : public GCFactory<BranchIsland, 0> { /// ctor /// @param pMaxFwdBranchRange - the max forward branch range of the target /// @param pMaxBwdBranchRange - the max backward branch range of the target - /// @param pMaxIslandSize - a predifned value (64KB here) to decide the max - /// size of the island + /// @param pMaxIslandSize - the group size to place stubs between sections BranchIslandFactory(int64_t pMaxFwdBranchRange, int64_t pMaxBwdBranchRange, - size_t pMaxIslandSize = 65536U); + size_t pMaxIslandSize); ~BranchIslandFactory(); diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc index 8340cd8..ac44022 100644 --- a/include/mcld/LD/DiagCommonKinds.inc +++ b/include/mcld/LD/DiagCommonKinds.inc @@ -181,8 +181,8 @@ DIAG(fatal_unwritable_output, "unable to write output file %0") DIAG(warn_unsupported_option, DiagnosticEngine::Warning, - "Option `%0' is not implemented yet!", - "Option `%0' is not implemented yet!") + "%0: unsupported option", + "%0: unsupported option") DIAG(warn_shared_textrel, DiagnosticEngine::Warning, "Add DT_TEXTREL in a shared object!", @@ -223,7 +223,3 @@ DIAG(eh_missing_text_section, DiagnosticEngine::Fatal, "missing text section for '%0' in file '%1'", "missing text section for '%0' in file '%1'") -DIAG(eh_missing_exidx_section, - DiagnosticEngine::Fatal, - "missing .ARM.exidx section for '%0' in file '%1'", - "missing .ARM.exidx section for '%0' in file '%1'") diff --git a/include/mcld/LD/DiagLayouts.inc b/include/mcld/LD/DiagLayouts.inc index c41b775..e0e6d09 100644 --- a/include/mcld/LD/DiagLayouts.inc +++ b/include/mcld/LD/DiagLayouts.inc @@ -32,3 +32,9 @@ DIAG(debug_icf_folded_section, DiagnosticEngine::Debug, "ICF folding section `%0' of `%1' into `%2' of `%3'", "ICF folding section `%0' of `%1' into `%2' of `%3'") +DIAG(err_no_space_to_place_stubs, + DiagnosticEngine::Error, + "There is no space left to place stubs. Current stub group size: %0\n" + "Use --stub-group-size option to increase the group size.", + "There is no space left to place stubs. Current stub group size: %0\n" + "Use --stub-group-size option to increase the group size.") diff --git a/include/mcld/LD/DiagMips.inc b/include/mcld/LD/DiagMips.inc new file mode 100644 index 0000000..48c0169 --- /dev/null +++ b/include/mcld/LD/DiagMips.inc @@ -0,0 +1,53 @@ +// Mips specific errors and warnings on object file incompatibilities +DIAG(error_Mips_incompatible_class, + DiagnosticEngine::Fatal, + "target '%0' is incompatible with '%1' in %2", + "target '%0' is incompatible with '%1' in %2") +DIAG(error_Mips_inconsistent_arch, + DiagnosticEngine::Error, + "target arch '%0' is inconsist with the '%1' in %2", + "target arch '%0' is inconsist with the '%1' in %2") +DIAG(error_Mips_abiflags_invalid_size, + DiagnosticEngine::Error, + "invalid size of .MIPS.abiflags section in %0", + "invalid size of .MIPS.abiflags section in %0") +DIAG(error_Mips_abiflags_invalid_version, + DiagnosticEngine::Error, + "unexpected .MIPS.abiflags section version number '%0' in %1", + "unexpected .MIPS.abiflags section version number '%0' in %1") +DIAG(error_Mips_inconsistent_abi, + DiagnosticEngine::Error, + "target ABI is incompatible with ABI in %0", + "target ABI is incompatible with ABI in %0") +DIAG(error_Mips_inconsistent_mnan, + DiagnosticEngine::Error, + "target -mnan=%0 flag is incompatible with -mnan=%1 in %2", + "target -mnan=%0 flag is incompatible with -mnan=%1 in %2") +DIAG(error_Mips_inconsistent_fp64, + DiagnosticEngine::Error, + "target -mfp flag is incompatible with -mfp in %0", + "target -mfp flag is incompatible with -mfp in %0") +DIAG(error_Mips_m16_unsupported, + DiagnosticEngine::Error, + "MIPS16 extension is unsupported: %0", + "MIPS16 extension is unsupported: %0") +DIAG(warn_Mips_abicalls_linking, + DiagnosticEngine::Warning, + "conflicting linking abicalls and non-abicalls files on %0.", + "conflicting linking abicalls and non-abicalls files on %0.") +DIAG(warn_Mips_fp_abi_incompatible, + DiagnosticEngine::Warning, + "FP ABI %0 is incompatible with %1 used by %2", + "FP ABI %0 is incompatible with %1 used by %2") +DIAG(warn_Mips_isa_incompatible, + DiagnosticEngine::Warning, + "inconsistent ISA between .MIPS.abiflags and ELF header e_flags field: %0", + "inconsistent ISA between .MIPS.abiflags and ELF header e_flags field: %0") +DIAG(warn_Mips_isa_ext_incompatible, + DiagnosticEngine::Warning, + "inconsistent ISA extensions between .MIPS.abiflags and ELF header e_flags field: %0", + "inconsistent ISA extensions between .MIPS.abiflags and ELF header e_flags field: %0") +DIAG(warn_Mips_ases_incompatible, + DiagnosticEngine::Warning, + "inconsistent ASEs between .MIPS.abiflags and ELF header e_flags field: %0", + "inconsistent ASEs between .MIPS.abiflags and ELF header e_flags field: %0") diff --git a/include/mcld/LD/DiagnosticInfos.h b/include/mcld/LD/DiagnosticInfos.h index 804394e..a82fda9 100644 --- a/include/mcld/LD/DiagnosticInfos.h +++ b/include/mcld/LD/DiagnosticInfos.h @@ -24,6 +24,7 @@ enum ID { #include "mcld/LD/DiagLayouts.inc" #include "mcld/LD/DiagGOTPLT.inc" #include "mcld/LD/DiagLDScript.inc" +#include "mcld/LD/DiagMips.inc" #undef DIAG NUM_OF_BUILDIN_DIAGNOSTIC_INFO }; diff --git a/include/mcld/LD/ELFSegmentFactory.h b/include/mcld/LD/ELFSegmentFactory.h index 12a5831..05c6747 100644 --- a/include/mcld/LD/ELFSegmentFactory.h +++ b/include/mcld/LD/ELFSegmentFactory.h @@ -57,6 +57,10 @@ class ELFSegmentFactory { /// @param pType - p_type in ELF program header ELFSegment* produce(uint32_t pType, uint32_t pFlag = llvm::ELF::PF_R); + ELFSegment* insert(iterator pPosition, + uint32_t pType, + uint32_t pFlag = llvm::ELF::PF_R); + void erase(iterator pSegment); private: diff --git a/include/mcld/LD/SectionData.h b/include/mcld/LD/SectionData.h index 22cda34..82027c2 100644 --- a/include/mcld/LD/SectionData.h +++ b/include/mcld/LD/SectionData.h @@ -61,6 +61,10 @@ class SectionData { bool empty() const { return m_Fragments.empty(); } + static FragmentListType SectionData::*getSublistAccess(Fragment *) { + return &SectionData::m_Fragments; + } + reference front() { return m_Fragments.front(); } const_reference front() const { return m_Fragments.front(); } reference back() { return m_Fragments.back(); } diff --git a/include/mcld/LD/StubFactory.h b/include/mcld/LD/StubFactory.h index 2a093d0..b3adf98 100644 --- a/include/mcld/LD/StubFactory.h +++ b/include/mcld/LD/StubFactory.h @@ -17,6 +17,7 @@ namespace mcld { class BranchIslandFactory; class IRBuilder; +class FragmentRef; class Relocation; class Stub; @@ -37,12 +38,18 @@ class StubFactory { IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory); + Stub* create(FragmentRef& pFragRef, + IRBuilder& pBuilder, + BranchIslandFactory& pBRIslandFactory); + private: /// findPrototype - find if there is a registered stub prototype for the given /// relocation Stub* findPrototype(const Relocation& pReloc, const uint64_t pSource, - uint64_t pTargetSymValue); + uint64_t pTargetSymValue) const; + + Stub* findPrototype(const FragmentRef& pFragRef) const; private: typedef std::vector<Stub*> StubPoolType; diff --git a/include/mcld/Script/ScriptScanner.h b/include/mcld/Script/ScriptScanner.h index 4a572a1..da54750 100644 --- a/include/mcld/Script/ScriptScanner.h +++ b/include/mcld/Script/ScriptScanner.h @@ -10,7 +10,11 @@ #define MCLD_SCRIPT_SCRIPTSCANNER_H_ #ifndef __FLEX_LEXER_H -#include "FlexLexer.h" +#ifdef ANDROID +#include "mcld/Script/FlexLexer.h" +#else +#include <FlexLexer.h> +#endif #endif #ifndef YY_DECL diff --git a/include/mcld/Target/GNUInfo.h b/include/mcld/Target/GNUInfo.h index 2a55688..d09e5d9 100644 --- a/include/mcld/Target/GNUInfo.h +++ b/include/mcld/Target/GNUInfo.h @@ -35,8 +35,7 @@ class GNUInfo { virtual uint8_t ABIVersion() const { return 0x0; } /// defaultTextSegmentAddr - target should specify its own default start - /// address - /// of the text segment. esp. for exec. + /// address of the text segment. esp. for exec. virtual uint64_t defaultTextSegmentAddr() const { return 0x0; } /// flags - the value of ElfXX_Ehdr::e_flags @@ -47,7 +46,6 @@ class GNUInfo { /// dyld - the name of the default dynamic linker /// target may override this function if needed. - /// @ref gnu ld, bfd/elf32-i386.c:521 virtual const char* dyld() const { return "/usr/lib/libc.so.1"; } /// isDefaultExecStack - target should specify whether the stack is default @@ -62,6 +60,9 @@ class GNUInfo { /// here. If target favors the different size, please override this function virtual uint64_t abiPageSize() const { return 0x1000; } + /// stubGroupSize - the default group size to place stubs between sections. + virtual unsigned stubGroupSize() const { return 0x10000; } + protected: const llvm::Triple& m_Triple; }; diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h index 212d081..a396084 100644 --- a/include/mcld/Target/GNULDBackend.h +++ b/include/mcld/Target/GNULDBackend.h @@ -189,6 +189,9 @@ class GNULDBackend : public TargetLDBackend { /// Different concrete target backend may overlap this function. virtual bool allocateCommonSymbols(Module& pModule); + /// mergeFlags - update set of ELF header flags + virtual void mergeFlags(Input& pInput, const char* ELF_hdr) {} + /// updateSectionFlags - update pTo's flags when merging pFrom /// update the output section flags based on input section flags. virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom); @@ -307,11 +310,14 @@ class GNULDBackend : public TargetLDBackend { /// maxFwdBranchOffset - return the max forward branch offset of the backend. /// Target can override this function if needed. - virtual int64_t maxFwdBranchOffset() { return INT64_MAX; } + virtual int64_t maxFwdBranchOffset() const { return INT64_MAX; } /// maxBwdBranchOffset - return the max backward branch offset of the backend. /// Target can override this function if needed. - virtual int64_t maxBwdBranchOffset() { return 0; } + virtual int64_t maxBwdBranchOffset() const { return 0; } + + /// stubGroupSize - return the group size to place stubs between sections. + virtual unsigned stubGroupSize() const; /// checkAndSetHasTextRel - check pSection flag to set HasTextRel void checkAndSetHasTextRel(const LDSection& pSection); diff --git a/include/mcld/TargetOptions.h b/include/mcld/TargetOptions.h index 23a376b..2c7d973 100644 --- a/include/mcld/TargetOptions.h +++ b/include/mcld/TargetOptions.h @@ -58,12 +58,37 @@ class TargetOptions { bool is32Bits() const { return (32 == m_BitClass); } bool is64Bits() const { return (64 == m_BitClass); } + // -G, max GP size option + void setGPSize(unsigned pGPSize) { m_GPSize = pGPSize; } + + unsigned getGPSize() const { return m_GPSize; } + + void setStubGroupSize(unsigned pSize) { m_StubGroupSize = pSize; } + + unsigned getStubGroupSize() const { return m_StubGroupSize; } + + void setFixCA53Erratum835769(bool pEnable = true) { + m_FixCA53Erratum835769 = pEnable; + } + + bool fixCA53Erratum835769() const { return m_FixCA53Erratum835769; } + + void setFixCA53Erratum843419(bool pEnable = true) { + m_FixCA53Erratum843419 = pEnable; + } + + bool fixCA53Erratum843419() const { return m_FixCA53Erratum843419; } + private: llvm::Triple m_Triple; std::string m_ArchName; std::string m_TargetCPU; Endian m_Endian; unsigned int m_BitClass; + unsigned m_GPSize; // -G, --gpsize + unsigned m_StubGroupSize; + bool m_FixCA53Erratum835769 : 1; + bool m_FixCA53Erratum843419 : 1; }; } // namespace mcld diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp index 1996acf..c7d0dde 100644 --- a/lib/Core/GeneralOptions.cpp +++ b/lib/Core/GeneralOptions.cpp @@ -61,7 +61,6 @@ GeneralOptions::GeneralOptions() m_bPrintICFSections(false), m_ICF(ICF::None), m_ICFIterations(2), - m_GPSize(8), m_StripSymbols(StripSymbolMode::KeepAllSymbols), m_HashStyle(HashStyle::SystemV) { } diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp index 252fc43..4c6eab8 100644 --- a/lib/Core/IRBuilder.cpp +++ b/lib/Core/IRBuilder.cpp @@ -601,6 +601,36 @@ Relocation* IRBuilder::AddRelocation(LDSection& pSection, return relocation; } +ResolveInfo* IRBuilder::CreateLocalSymbol(FragmentRef& pFragRef) { + // Create and add symbol to the name pool. + ResolveInfo* resolveInfo = + m_Module.getNamePool().createSymbol(/* pName */"", + /* pIsDyn */false, + ResolveInfo::Section, + ResolveInfo::Define, + ResolveInfo::Local, + /* pSize */0, + ResolveInfo::Hidden); + if (resolveInfo == nullptr) { + return nullptr; + } + + // Create input symbol. + LDSymbol* inputSym = LDSymbol::Create(*resolveInfo); + if (inputSym == nullptr) { + return nullptr; + } + + inputSym->setFragmentRef(FragmentRef::Create(*pFragRef.frag(), + pFragRef.offset())); + inputSym->setValue(/* pValue */0); + + // The output symbol is simply an alias to the input symbol. + resolveInfo->setSymPtr(inputSym); + + return resolveInfo; +} + /// AddSymbol - define an output symbol and override it immediately template <> LDSymbol* IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( diff --git a/lib/Core/TargetOptions.cpp b/lib/Core/TargetOptions.cpp index c7678ba..e830710 100644 --- a/lib/Core/TargetOptions.cpp +++ b/lib/Core/TargetOptions.cpp @@ -13,11 +13,21 @@ namespace mcld { //===----------------------------------------------------------------------===// // TargetOptions //===----------------------------------------------------------------------===// -TargetOptions::TargetOptions() : m_Endian(Unknown), m_BitClass(0) { +TargetOptions::TargetOptions() + : m_Endian(Unknown), + m_BitClass(0), + m_GPSize(8), + m_StubGroupSize(0), + m_FixCA53Erratum835769(false) { } TargetOptions::TargetOptions(const std::string& pTriple) - : m_Triple(pTriple), m_Endian(Unknown), m_BitClass(0) { + : m_Triple(pTriple), + m_Endian(Unknown), + m_BitClass(0), + m_GPSize(8), + m_StubGroupSize(0), + m_FixCA53Erratum835769(false) { } TargetOptions::~TargetOptions() { diff --git a/lib/Fragment/Stub.cpp b/lib/Fragment/Stub.cpp index b658ece..53fe776 100644 --- a/lib/Fragment/Stub.cpp +++ b/lib/Fragment/Stub.cpp @@ -8,6 +8,13 @@ //===----------------------------------------------------------------------===// #include "mcld/Fragment/Stub.h" +#include "mcld/IRBuilder.h" +#include "mcld/Fragment/Relocation.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/ResolveInfo.h" + +#include <cassert> + namespace mcld { Stub::Stub() : Fragment(Fragment::Stub), m_pSymInfo(NULL) { @@ -22,6 +29,49 @@ void Stub::setSymInfo(ResolveInfo* pSymInfo) { m_pSymInfo = pSymInfo; } +void Stub::applyFixup(Relocation& pSrcReloc, + IRBuilder& pBuilder, + BranchIsland& pIsland) { + // build a name for stub symbol + std::string sym_name("__"); + sym_name.append(pSrcReloc.symInfo()->name()) + .append("_") + .append(name()) + .append("@") + .append(pIsland.name()); + + // create LDSymbol for the stub + LDSymbol* symbol = + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( + sym_name, + ResolveInfo::Function, + ResolveInfo::Define, + ResolveInfo::Local, + size(), + initSymValue(), + FragmentRef::Create(*this, initSymValue()), + ResolveInfo::Default); + setSymInfo(symbol->resolveInfo()); + + // add relocations of this stub (i.e., set the branch target of the stub) + for (fixup_iterator it = fixup_begin(), ie = fixup_end(); it != ie; ++it) { + Relocation* reloc = + Relocation::Create((*it)->type(), + *(FragmentRef::Create(*this, (*it)->offset())), + (*it)->addend()); + reloc->setSymInfo(pSrcReloc.symInfo()); + pIsland.addRelocation(*reloc); + } +} + +void Stub::applyFixup(FragmentRef& pSrcFragRef, + IRBuilder& pBuilder, + BranchIsland& pIsland) { + // If applying fixups is based on the source FragmentRef, each target stub + // probably should override this function. + assert(0 && "target stub should override this function"); +} + void Stub::addFixup(DWord pOffset, SWord pAddend, Type pType) { assert(pOffset < size()); m_FixupList.push_back(new Fixup(pOffset, pAddend, pType)); diff --git a/lib/LD/BranchIsland.cpp b/lib/LD/BranchIsland.cpp index 0405263..e3237df 100644 --- a/lib/LD/BranchIsland.cpp +++ b/lib/LD/BranchIsland.cpp @@ -17,9 +17,9 @@ namespace mcld { -//========================== +//============================================================================// // BranchIsland - +//============================================================================// BranchIsland::BranchIsland(Fragment& pEntryFrag, size_t pMaxSize, size_t pIndex) : m_Entry(pEntryFrag), m_pExit(pEntryFrag.getNextNode()), @@ -123,6 +123,30 @@ bool BranchIsland::addStub(const Stub* pPrototype, return !exist; } +void BranchIsland::addStub(Stub& pStub) { + bool exist = false; + Key key(&pStub, pStub.symInfo()->outSymbol(), 0); + m_StubMap.insert(key, exist); + + m_pRear = &pStub; + SectionData* sd = m_Entry.getParent(); + + // insert alignment fragment + // TODO: check if we can reduce this alignment fragment for some cases + AlignFragment* align_frag = + new AlignFragment(pStub.alignment(), 0x0, 1u, pStub.alignment() - 1); + align_frag->setParent(sd); + sd->getFragmentList().insert(end(), align_frag); + align_frag->setOffset(align_frag->getPrevNode()->getOffset() + + align_frag->getPrevNode()->size()); + + // insert stub fragment + pStub.setParent(sd); + sd->getFragmentList().insert(end(), &pStub); + pStub.setOffset(pStub.getPrevNode()->getOffset() + + pStub.getPrevNode()->size()); +} + /// addRelocation - add a relocation into island bool BranchIsland::addRelocation(Relocation& pReloc) { m_Relocations.push_back(&pReloc); diff --git a/lib/LD/BranchIslandFactory.cpp b/lib/LD/BranchIslandFactory.cpp index cace800..bc9f603 100644 --- a/lib/LD/BranchIslandFactory.cpp +++ b/lib/LD/BranchIslandFactory.cpp @@ -38,25 +38,27 @@ BranchIslandFactory::~BranchIslandFactory() { /// group - group fragments and create islands when needed /// @param pSectionData - the SectionData holds fragments need to be grouped void BranchIslandFactory::group(Module& pModule) { - /* FIXME: Currently only support relaxing .text section! */ - LDSection* text = pModule.getSection(".text"); - if (text != NULL && text->hasSectionData()) { - SectionData& sd = *text->getSectionData(); - uint64_t group_end = m_MaxFwdBranchRange; - for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; ++it) { - if ((*it).getOffset() + (*it).size() > group_end) { - Fragment* frag = (*it).getPrevNode(); - while (frag != NULL && frag->getKind() == Fragment::Alignment) { - frag = frag->getPrevNode(); - } - if (frag != NULL) { - produce(*frag); - group_end = (*it).getOffset() + m_MaxFwdBranchRange; + for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end(); + sect != sectEnd; ++sect) { + if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) { + SectionData& sd = *((*sect)->getSectionData()); + uint64_t group_end = m_MaxFwdBranchRange; + for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; + ++it) { + if ((*it).getOffset() + (*it).size() > group_end) { + Fragment* frag = (*it).getPrevNode(); + while (frag != NULL && frag->getKind() == Fragment::Alignment) { + frag = frag->getPrevNode(); + } + if (frag != NULL) { + produce(*frag); + group_end = (*it).getOffset() + m_MaxFwdBranchRange; + } } } + if (getIslands(sd.back()).first == NULL) + produce(sd.back()); } - if (getIslands(sd.back()).first == NULL) - produce(sd.back()); } } @@ -78,11 +80,15 @@ std::pair<BranchIsland*, BranchIsland*> BranchIslandFactory::getIslands( BranchIsland* bwd = NULL; for (iterator it = begin(), ie = end(), prev = ie; it != ie; prev = it, ++it) { + if (pFragment.getParent() != (*it).getParent()) { + continue; + } + if ((pFragment.getOffset() < (*it).offset()) && ((pFragment.getOffset() + m_MaxFwdBranchRange) >= (*it).offset())) { fwd = &*it; - if (prev != ie) { + if ((prev != ie) && (pFragment.getParent() == (*prev).getParent())) { int64_t bwd_off = (int64_t)pFragment.getOffset() + m_MaxBwdBranchRange; if ((pFragment.getOffset() > (*prev).offset()) && (bwd_off <= (int64_t)(*prev).offset())) { diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp index 080c318..0ba2e9c 100644 --- a/lib/LD/DiagnosticInfos.cpp +++ b/lib/LD/DiagnosticInfos.cpp @@ -51,6 +51,7 @@ static const DiagStaticInfo DiagCommonInfo[] = { #include "mcld/LD/DiagLayouts.inc" // NOLINT [build/include] [4] #include "mcld/LD/DiagGOTPLT.inc" // NOLINT [build/include] [4] #include "mcld/LD/DiagLDScript.inc" // NOLINT [build/include] [4] +#include "mcld/LD/DiagMips.inc" // NOLINT [build/include] [4] #undef DIAG {0, DiagnosticEngine::None, 0, 0}}; @@ -69,6 +70,7 @@ static const DiagStaticInfo DiagLoCInfo[] = { #include "mcld/LD/DiagLayouts.inc" // NOLINT [build/include] [4] #include "mcld/LD/DiagGOTPLT.inc" // NOLINT [build/include] [4] #include "mcld/LD/DiagLDScript.inc" // NOLINT [build/include] [4] +#include "mcld/LD/DiagMips.inc" // NOLINT [build/include] [4] #undef DIAG {0, DiagnosticEngine::None, 0, 0}}; diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp index aeefd37..bcd031c 100644 --- a/lib/LD/ELFObjectReader.cpp +++ b/lib/LD/ELFObjectReader.cpp @@ -100,6 +100,7 @@ bool ELFObjectReader::readHeader(Input& pInput) { llvm::StringRef region = pInput.memArea()->request(pInput.fileOffset(), hdr_size); const char* ELF_hdr = region.begin(); + m_Backend.mergeFlags(pInput, ELF_hdr); bool result = m_pELFReader->readSectionHeaders(pInput, ELF_hdr); return result; } diff --git a/lib/LD/ELFSegmentFactory.cpp b/lib/LD/ELFSegmentFactory.cpp index de2d175..678bbfc 100644 --- a/lib/LD/ELFSegmentFactory.cpp +++ b/lib/LD/ELFSegmentFactory.cpp @@ -80,6 +80,12 @@ ELFSegment* ELFSegmentFactory::produce(uint32_t pType, uint32_t pFlag) { return back(); } +ELFSegment* ELFSegmentFactory::insert(iterator pPosition, + uint32_t pType, + uint32_t pFlag) { + return *(m_Segments.insert(pPosition, ELFSegment::Create(pType, pFlag))); +} + void ELFSegmentFactory::erase(iterator pSegment) { m_Segments.erase(pSegment); } diff --git a/lib/LD/EhFrameReader.cpp b/lib/LD/EhFrameReader.cpp index 383c1ee..f26a5cd 100644 --- a/lib/LD/EhFrameReader.cpp +++ b/lib/LD/EhFrameReader.cpp @@ -197,10 +197,14 @@ bool EhFrameReader::addCIE(EhFrame& pEhFrame, return false; } // skip the Return Address Register - if (cie_end - handler < 1) { - return false; + if (version == 1) { + if (cie_end - handler < 1) + return false; + ++handler; + } else { + if (!skip_LEB128(&handler, cie_end)) + return false; } - ++handler; llvm::StringRef augment((const char*)aug_str_front); diff --git a/lib/LD/IdenticalCodeFolding.cpp b/lib/LD/IdenticalCodeFolding.cpp index 527dccb..5ba0fc1 100644 --- a/lib/LD/IdenticalCodeFolding.cpp +++ b/lib/LD/IdenticalCodeFolding.cpp @@ -232,22 +232,21 @@ void IdenticalCodeFolding::FoldingCandidate::initConstantContent( // Get the static content from relocs. if (reloc_sect != NULL && reloc_sect->hasRelocData()) { - RelocData::iterator rel, relEnd = reloc_sect->getRelocData()->end(); - for (rel = reloc_sect->getRelocData()->begin(); rel != relEnd; ++rel) { + for (Relocation& rel : *reloc_sect->getRelocData()) { llvm::format_object<Relocation::Type, Relocation::Address, Relocation::Address, Relocation::Address> rel_info("%x%llx%llx%llx", - rel->type(), - rel->symValue(), - rel->addend(), - rel->place()); + rel.type(), + rel.symValue(), + rel.addend(), + rel.place()); char rel_str[48]; rel_info.print(rel_str, sizeof(rel_str)); content.append(rel_str); // Handle the recursive call. - LDSymbol* sym = rel->symInfo()->outSymbol(); + LDSymbol* sym = rel.symInfo()->outSymbol(); if ((sym->type() == ResolveInfo::Function) && sym->hasFragRef()) { LDSection* def = &sym->fragRef()->frag()->getParent()->getSection(); if (def == sect) { @@ -255,12 +254,12 @@ void IdenticalCodeFolding::FoldingCandidate::initConstantContent( } } - if (!pBackend.isSymbolPreemptible(*rel->symInfo()) && sym->hasFragRef() && + if (!pBackend.isSymbolPreemptible(*rel.symInfo()) && sym->hasFragRef() && (pKeptSections.find( &sym->fragRef()->frag()->getParent()->getSection()) != pKeptSections.end())) { // Mark this reloc as a variable. - variable_relocs.push_back(rel); + variable_relocs.push_back(&rel); } else { // TODO: Support inlining merge sections if possible (target-dependent). if ((sym->binding() == ResolveInfo::Local) || diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp index 75de0cf..6b8c81c 100644 --- a/lib/LD/StubFactory.cpp +++ b/lib/LD/StubFactory.cpp @@ -9,6 +9,7 @@ #include "mcld/LD/StubFactory.h" #include "mcld/IRBuilder.h" +#include "mcld/Fragment/FragmentRef.h" #include "mcld/Fragment/Relocation.h" #include "mcld/Fragment/Stub.h" #include "mcld/LD/BranchIsland.h" @@ -58,77 +59,71 @@ Stub* StubFactory::create(Relocation& pReloc, stub = islands.second->findStub(prototype, pReloc); } - if (stub != NULL) { - // reset the branch target to the stub instead! - pReloc.setSymInfo(stub->symInfo()); - } else { + if (stub == NULL) { // find if there is such a stub in the forward island. stub = islands.first->findStub(prototype, pReloc); - if (stub != NULL) { - // reset the branch target to the stub instead! - pReloc.setSymInfo(stub->symInfo()); - } else { + if (stub == NULL) { // create a stub from the prototype stub = prototype->clone(); - // build a name for stub symbol - std::string name("__"); - name.append(pReloc.symInfo()->name()) - .append("_") - .append(stub->name()) - .append("@") - .append(islands.first->name()); - - // create LDSymbol for the stub - LDSymbol* symbol = - pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( - name, - ResolveInfo::Function, - ResolveInfo::Define, - ResolveInfo::Local, - stub->size(), // size - stub->initSymValue(), // value - FragmentRef::Create(*stub, stub->initSymValue()), - ResolveInfo::Default); - stub->setSymInfo(symbol->resolveInfo()); - - // add relocations of this stub (i.e., set the branch target of the - // stub) - for (Stub::fixup_iterator it = stub->fixup_begin(), - ie = stub->fixup_end(); - it != ie; - ++it) { - Relocation* reloc = - Relocation::Create((*it)->type(), - *(FragmentRef::Create(*stub, (*it)->offset())), - (*it)->addend()); - reloc->setSymInfo(pReloc.symInfo()); - islands.first->addRelocation(*reloc); - } + // apply fixups in this new stub + stub->applyFixup(pReloc, pBuilder, *islands.first); // add stub to the forward branch island islands.first->addStub(prototype, pReloc, *stub); - - // reset the branch target of the input reloc to this stub instead! - pReloc.setSymInfo(stub->symInfo()); } } } return stub; } +Stub* StubFactory::create(FragmentRef& pFragRef, + IRBuilder& pBuilder, + BranchIslandFactory& pBRIslandFactory) { + Stub* prototype = findPrototype(pFragRef); + if (prototype == NULL) { + return NULL; + } else { + std::pair<BranchIsland*, BranchIsland*> islands = + pBRIslandFactory.getIslands(*(pFragRef.frag())); + // early exit if we can not find the forward island. + if (islands.first == NULL) { + return NULL; + } else { + // create a stub from the prototype + Stub* stub = prototype->clone(); + + // apply fixups in this new stub + stub->applyFixup(pFragRef, pBuilder, *islands.first); + + // add stub to the forward branch island + islands.first->addStub(*stub); + + return stub; + } // (islands.first == NULL) + } // if (prototype == NULL) +} + /// findPrototype - find if there is a registered stub prototype for the given /// relocation Stub* StubFactory::findPrototype(const Relocation& pReloc, uint64_t pSource, - uint64_t pTargetSymValue) { - for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end(); - it != ie; - ++it) { + uint64_t pTargetSymValue) const { + for (StubPoolType::const_iterator it = m_StubPool.begin(), + ie = m_StubPool.end(); it != ie; ++it) { if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue)) return (*it); } return NULL; } +Stub* StubFactory::findPrototype(const FragmentRef& pFragRef) const { + for (StubPoolType::const_iterator it = m_StubPool.begin(), + ie = m_StubPool.end(); it != ie; ++it) { + if ((*it)->isMyDuty(pFragRef)) + return (*it); + } + return NULL; +} + } // namespace mcld diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index 4d8ffeb..a9813d9 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -986,9 +986,8 @@ void ObjectLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput) { break; } } else { - std::memcpy(target_addr, - &pReloc.target(), - pReloc.size(*m_LDBackend.getRelocator()) / 8); + std::memcpy(target_addr, &pReloc.target(), + (pReloc.size(*m_LDBackend.getRelocator()) + 7) / 8); } } diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc index 67fdd73..a429838 100644 --- a/lib/Support/Unix/FileSystem.inc +++ b/lib/Support/Unix/FileSystem.inc @@ -15,6 +15,7 @@ #include <dirent.h> #include <fcntl.h> +#include <limits.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> diff --git a/lib/Target/AArch64/AArch64CA53Erratum835769Stub.cpp b/lib/Target/AArch64/AArch64CA53Erratum835769Stub.cpp new file mode 100644 index 0000000..7d10a1e --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum835769Stub.cpp @@ -0,0 +1,93 @@ +//===- AArch64CA53Erratum835769Stub.cpp -----------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64CA53Erratum835769Stub.h" +#include "AArch64InsnHelpers.h" + +#include "mcld/Fragment/FragmentRef.h" +#include "mcld/Fragment/Relocation.h" +#include "mcld/IRBuilder.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/LDSymbol.h" +#include "mcld/LD/ResolveInfo.h" + +#include <llvm/ADT/StringExtras.h> +#include <llvm/Support/ELF.h> + +#include <cassert> + +namespace mcld { + +//===----------------------------------------------------------------------===// +// AArch64CA53Erratum835769Stub +//===----------------------------------------------------------------------===// +AArch64CA53Erratum835769Stub::AArch64CA53Erratum835769Stub() { +} + +/// for doClone +AArch64CA53Erratum835769Stub::AArch64CA53Erratum835769Stub( + const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd) + : AArch64CA53ErratumStub(pData, pSize, pName, pBegin, pEnd) { +} + +AArch64CA53Erratum835769Stub::~AArch64CA53Erratum835769Stub() { +} + +bool AArch64CA53Erratum835769Stub::isMyDuty(const FragmentRef& pFragRef) const { + unsigned rt; + unsigned rt2; + bool is_pair; + bool is_load; + ErratumSequence code; + pFragRef.memcpy(&code, sizeof(ErratumSequence), 0); + + if (AArch64InsnHelpers::isMLXL(code.insns[1]) && + AArch64InsnHelpers::isMemOp(code.insns[0], rt, rt2, is_pair, is_load)) { + // Any SIMD memory op is independent of the subsequent MLA by definition of + // the erratum. + if (AArch64InsnHelpers::getBit(code.insns[0], 26) != 0) { + return true; + } + + // If not SIMD, check for integer memory ops and MLA relationship. + unsigned ra = AArch64InsnHelpers::getRa(code.insns[1]); + unsigned rm = AArch64InsnHelpers::getRm(code.insns[1]); + unsigned rn = AArch64InsnHelpers::getRn(code.insns[1]); + + // If this is a load and there's a true(RAW) dependency, we are safe and + // this is not an erratum sequence. + if (is_load && + ((rt == ra) || + (rt == rm) || + (rt == rn) || + (is_pair && ((rt2 == ra) || (rt2 == rm) || (rt2 == rn))))) { + return false; + } + + // We conservatively put out stubs for all other cases (including + // writebacks). + return true; + } + + return false; +} + +Stub* AArch64CA53Erratum835769Stub::doClone() { + return new AArch64CA53Erratum835769Stub(getData(), + size(), + "erratum_835769_veneer", + fixup_begin(), + fixup_end()); +} + +} // namespace mcld diff --git a/lib/Target/AArch64/AArch64CA53Erratum835769Stub.h b/lib/Target/AArch64/AArch64CA53Erratum835769Stub.h new file mode 100644 index 0000000..2adadb4 --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum835769Stub.h @@ -0,0 +1,63 @@ +//===- AArch64CA53Erratum835769Stub.h -------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64CA53ERRATUM835769STUB_H_ +#define TARGET_AARCH64_AARCH64CA53ERRATUM835769STUB_H_ + +#include "AArch64CA53ErratumStub.h" + +#include "mcld/Support/Compiler.h" +#include <llvm/Support/DataTypes.h> +#include <string> +#include <vector> + +namespace mcld { + +class FragmentRef; + +class AArch64CA53Erratum835769Stub : public AArch64CA53ErratumStub { + public: + static constexpr unsigned ErratumInsnOffset = 4; + + struct ErratumSequence { + unsigned insns[2]; + }; + + public: + AArch64CA53Erratum835769Stub(); + + ~AArch64CA53Erratum835769Stub(); + + bool isMyDuty(const FragmentRef& pFragRef) const; + + unsigned getErratumInsnOffset() const { + return ErratumInsnOffset; + } + + unsigned getErratumSequenceSize() const { + return sizeof(ErratumSequence); + } + + private: + /// for doClone + AArch64CA53Erratum835769Stub(const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd); + + /// doClone + Stub* doClone(); + + private: + DISALLOW_COPY_AND_ASSIGN(AArch64CA53Erratum835769Stub); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64CA53ERRATUM835769STUB_H_ diff --git a/lib/Target/AArch64/AArch64CA53Erratum843419Stub.cpp b/lib/Target/AArch64/AArch64CA53Erratum843419Stub.cpp new file mode 100644 index 0000000..978c533 --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum843419Stub.cpp @@ -0,0 +1,93 @@ +//===- AArch64CA53Erratum843419Stub.cpp -----------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64CA53Erratum843419Stub.h" +#include "AArch64InsnHelpers.h" + +#include "mcld/Fragment/FragmentRef.h" +#include "mcld/Fragment/Relocation.h" +#include "mcld/IRBuilder.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/LDSection.h" +#include "mcld/LD/LDSymbol.h" +#include "mcld/LD/ResolveInfo.h" +#include "mcld/LD/SectionData.h" + +#include <llvm/ADT/StringExtras.h> +#include <llvm/Support/ELF.h> + +#include <cassert> + +namespace mcld { + +//===----------------------------------------------------------------------===// +// AArch64CA53Erratum843419Stub +//===----------------------------------------------------------------------===// +AArch64CA53Erratum843419Stub::AArch64CA53Erratum843419Stub() { +} + +/// for doClone +AArch64CA53Erratum843419Stub::AArch64CA53Erratum843419Stub( + const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd) + : AArch64CA53ErratumStub(pData, pSize, pName, pBegin, pEnd) { +} + +AArch64CA53Erratum843419Stub::~AArch64CA53Erratum843419Stub() { +} + +bool AArch64CA53Erratum843419Stub::isErratum843419Sequence(unsigned insn1, + unsigned insn2, + unsigned insn3) { + unsigned rt; + unsigned rt2; + bool is_pair; + bool is_load; + return AArch64InsnHelpers::isMemOp(insn2, rt, rt2, is_pair, is_load) && + (!is_pair || (is_pair && !is_load)) && + AArch64InsnHelpers::isLDSTUIMM(insn3) && + (AArch64InsnHelpers::getRn(insn3) == AArch64InsnHelpers::getRd(insn1)); +} + +bool AArch64CA53Erratum843419Stub::isMyDuty(const FragmentRef& pFragRef) const { + if ((pFragRef.offset() + AArch64InsnHelpers::InsnSize * 3) > + pFragRef.frag()->size()) { + return false; + } + + // The first instruction must be ending at 0xFF8 or 0xFFC. + const uint64_t vma = pFragRef.frag()->getParent()->getSection().addr() + + pFragRef.getOutputOffset(); + const unsigned page_offset = (vma & 0xFFF); + if ((page_offset != 0xFF8) && (page_offset != 0xFFC)) { + return false; + } + + ErratumSequence code; + pFragRef.memcpy(&code, AArch64InsnHelpers::InsnSize * 3, 0); + + if (isErratum843419Sequence(code.insns[0], code.insns[1], code.insns[2])) { + return true; + } + + return false; +} + +Stub* AArch64CA53Erratum843419Stub::doClone() { + return new AArch64CA53Erratum843419Stub(getData(), + size(), + "erratum_843419_veneer", + fixup_begin(), + fixup_end()); +} + +} // namespace mcld diff --git a/lib/Target/AArch64/AArch64CA53Erratum843419Stub.h b/lib/Target/AArch64/AArch64CA53Erratum843419Stub.h new file mode 100644 index 0000000..4c3b5b6 --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum843419Stub.h @@ -0,0 +1,68 @@ +//===- AArch64CA53Erratum843419Stub.h -------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB_H_ +#define TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB_H_ + +#include "AArch64CA53ErratumStub.h" + +#include "mcld/Support/Compiler.h" +#include <llvm/Support/DataTypes.h> +#include <string> +#include <vector> + +namespace mcld { + +class FragmentRef; + +class AArch64CA53Erratum843419Stub : public AArch64CA53ErratumStub { + public: + static constexpr unsigned ErratumInsnOffset = 8; + + struct ErratumSequence { + unsigned insns[3]; + }; + + public: + static bool isErratum843419Sequence(unsigned insn1, + unsigned insn2, + unsigned insn3); + + public: + AArch64CA53Erratum843419Stub(); + + ~AArch64CA53Erratum843419Stub(); + + bool isMyDuty(const FragmentRef& pFragRef) const; + + unsigned getErratumInsnOffset() const { + return ErratumInsnOffset; + } + + unsigned getErratumSequenceSize() const { + return sizeof(ErratumSequence); + } + + private: + /// for doClone + AArch64CA53Erratum843419Stub(const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd); + + /// doClone + Stub* doClone(); + + private: + DISALLOW_COPY_AND_ASSIGN(AArch64CA53Erratum843419Stub); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB_H_ diff --git a/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.cpp b/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.cpp new file mode 100644 index 0000000..f498d65 --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.cpp @@ -0,0 +1,84 @@ +//===- AArch64CA53Erratum843419Stub2.cpp ----------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64CA53Erratum843419Stub.h" +#include "AArch64CA53Erratum843419Stub2.h" +#include "AArch64InsnHelpers.h" + +#include "mcld/Fragment/FragmentRef.h" +#include "mcld/Fragment/Relocation.h" +#include "mcld/IRBuilder.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/LDSection.h" +#include "mcld/LD/LDSymbol.h" +#include "mcld/LD/ResolveInfo.h" +#include "mcld/LD/SectionData.h" + +#include <llvm/ADT/StringExtras.h> +#include <llvm/Support/ELF.h> + +#include <cassert> + +namespace mcld { + +//===----------------------------------------------------------------------===// +// AArch64CA53Erratum843419Stub2 +//===----------------------------------------------------------------------===// +AArch64CA53Erratum843419Stub2::AArch64CA53Erratum843419Stub2() { +} + +/// for doClone +AArch64CA53Erratum843419Stub2::AArch64CA53Erratum843419Stub2( + const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd) + : AArch64CA53ErratumStub(pData, pSize, pName, pBegin, pEnd) { +} + +AArch64CA53Erratum843419Stub2::~AArch64CA53Erratum843419Stub2() { +} + +bool AArch64CA53Erratum843419Stub2::isMyDuty( + const FragmentRef& pFragRef) const { + if ((pFragRef.offset() + AArch64InsnHelpers::InsnSize * 4) > + pFragRef.frag()->size()) { + return false; + } + + // The first instruction must be ending at 0xFF8 or 0xFFC. + const uint64_t vma = pFragRef.frag()->getParent()->getSection().addr() + + pFragRef.getOutputOffset(); + const unsigned page_offset = (vma & 0xFFF); + if ((page_offset != 0xFF8) && (page_offset != 0xFFC)) { + return false; + } + + ErratumSequence code; + pFragRef.memcpy(&code, AArch64InsnHelpers::InsnSize * 4, 0); + + if (AArch64CA53Erratum843419Stub::isErratum843419Sequence(code.insns[0], + code.insns[1], + code.insns[3])) { + return true; + } + + return false; +} + +Stub* AArch64CA53Erratum843419Stub2::doClone() { + return new AArch64CA53Erratum843419Stub2(getData(), + size(), + "erratum_843419_veneer", + fixup_begin(), + fixup_end()); +} + +} // namespace mcld diff --git a/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.h b/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.h new file mode 100644 index 0000000..53a282b --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53Erratum843419Stub2.h @@ -0,0 +1,63 @@ +//===- AArch64CA53Erratum843419Stub2.h ------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB2_H_ +#define TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB2_H_ + +#include "AArch64CA53ErratumStub.h" + +#include "mcld/Support/Compiler.h" +#include <llvm/Support/DataTypes.h> +#include <string> +#include <vector> + +namespace mcld { + +class FragmentRef; + +class AArch64CA53Erratum843419Stub2 : public AArch64CA53ErratumStub { + public: + static constexpr unsigned ErratumInsnOffset = 12; + + struct ErratumSequence { + unsigned insns[4]; + }; + + public: + AArch64CA53Erratum843419Stub2(); + + ~AArch64CA53Erratum843419Stub2(); + + bool isMyDuty(const FragmentRef& pFragRef) const; + + unsigned getErratumInsnOffset() const { + return ErratumInsnOffset; + } + + unsigned getErratumSequenceSize() const { + return sizeof(ErratumSequence); + } + + private: + /// for doClone + AArch64CA53Erratum843419Stub2(const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd); + + /// doClone + Stub* doClone(); + + private: + DISALLOW_COPY_AND_ASSIGN(AArch64CA53Erratum843419Stub2); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64CA53ERRATUM843419STUB2_H_ diff --git a/lib/Target/AArch64/AArch64CA53ErratumStub.cpp b/lib/Target/AArch64/AArch64CA53ErratumStub.cpp new file mode 100644 index 0000000..9fdc496 --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53ErratumStub.cpp @@ -0,0 +1,149 @@ +//===- AArch64CA53ErratumStub.cpp -----------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64CA53ErratumStub.h" +#include "AArch64InsnHelpers.h" +#include "AArch64LDBackend.h" +#include "AArch64RelocationHelpers.h" +#include "AArch64Relocator.h" + +#include "mcld/Fragment/FragmentRef.h" +#include "mcld/Fragment/Relocation.h" +#include "mcld/IRBuilder.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/LDSymbol.h" +#include "mcld/LD/ResolveInfo.h" + +#include <llvm/ADT/StringExtras.h> +#include <llvm/Support/ELF.h> + +#include <cassert> + +namespace mcld { + +//===----------------------------------------------------------------------===// +// AArch64CA53ErratumStub +//===----------------------------------------------------------------------===// +const uint32_t AArch64CA53ErratumStub::TEMPLATE[] = { + 0x00000000, // Placeholder for erratum insn + 0x00000000, // Palceholder for branch instruction +}; + +AArch64CA53ErratumStub::AArch64CA53ErratumStub() + : m_pData(NULL), + m_Name("erratum__prototype"), + m_Size(0x0) { + m_pData = TEMPLATE; + m_Size = sizeof(TEMPLATE); + addFixup(0x0, 0, AArch64Relocator::R_AARCH64_REWRITE_INSN); + addFixup(0x4, 0, llvm::ELF::R_AARCH64_JUMP26); +} + +/// for doClone +AArch64CA53ErratumStub::AArch64CA53ErratumStub(const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd) + : m_pData(pData), + m_Name(pName), + m_Size(pSize) { + for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it) { + addFixup(**it); + } +} + +AArch64CA53ErratumStub::~AArch64CA53ErratumStub() { +} + +bool AArch64CA53ErratumStub::isMyDuty(const FragmentRef& pFragRef) const { + return false; +} + +void AArch64CA53ErratumStub::applyFixup(FragmentRef& pSrcFragRef, + IRBuilder& pBuilder, + BranchIsland& pIsland) { + assert(isMyDuty(pSrcFragRef)); + + // Build stub symbol name. + std::string sym_name("__"); + sym_name.append(name()) + .append(llvm::utohexstr(pIsland.numOfStubs())) + .append("@") + .append(pIsland.name()); + + // Create LDSymbol for the stub. + LDSymbol* stub_sym = + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( + sym_name, + ResolveInfo::NoType, + ResolveInfo::Define, + ResolveInfo::Local, + size(), + initSymValue(), + FragmentRef::Create(*this, initSymValue()), + ResolveInfo::Default); + setSymInfo(stub_sym->resolveInfo()); + + // Create the target symbol of the stub to the next instruction of erratum + // pattarn. + FragmentRef* target = FragmentRef::Create(*pSrcFragRef.frag(), + pSrcFragRef.offset() + + getErratumInsnOffset() + + AArch64InsnHelpers::InsnSize); + ResolveInfo* target_info = pBuilder.CreateLocalSymbol(*target); + + // Apply the fixups. + fixup_iterator it = fixup_begin(); + // Rewrite the first instruction as the erratum instruction. + Relocation* reloc = + Relocation::Create((*it)->type(), + *(FragmentRef::Create(*this, (*it)->offset())), + (*it)->addend()); + reloc->setSymInfo(target_info); + + std::unique_ptr<unsigned[]> code(new unsigned[getErratumSequenceSize() / 4]); + pSrcFragRef.memcpy(code.get(), getErratumSequenceSize(), 0); + reloc->target() = + code[getErratumInsnOffset() / AArch64InsnHelpers::InsnSize]; + pIsland.addRelocation(*reloc); + + // Construct the second instruction as a branch to target. + ++it; + reloc = Relocation::Create((*it)->type(), + *(FragmentRef::Create(*this, (*it)->offset())), + (*it)->addend()); + reloc->setSymInfo(target_info); + reloc->target() = AArch64InsnHelpers::buildBranchInsn(); + pIsland.addRelocation(*reloc); + + assert((++it) == fixup_end()); +} + +const std::string& AArch64CA53ErratumStub::name() const { + return m_Name; +} + +const uint32_t* AArch64CA53ErratumStub::getData() const { + return m_pData; +} + +const uint8_t* AArch64CA53ErratumStub::getContent() const { + return reinterpret_cast<const uint8_t*>(m_pData); +} + +size_t AArch64CA53ErratumStub::size() const { + return m_Size; +} + +size_t AArch64CA53ErratumStub::alignment() const { + return 8; +} + +} // namespace mcld diff --git a/lib/Target/AArch64/AArch64CA53ErratumStub.h b/lib/Target/AArch64/AArch64CA53ErratumStub.h new file mode 100644 index 0000000..9c9998e --- /dev/null +++ b/lib/Target/AArch64/AArch64CA53ErratumStub.h @@ -0,0 +1,71 @@ +//===- AArch64CA53ErratumStub.h -------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64CA53ERRATUMSTUB_H_ +#define TARGET_AARCH64_AARCH64CA53ERRATUMSTUB_H_ + +#include "mcld/Fragment/Stub.h" +#include "mcld/Support/Compiler.h" +#include <llvm/Support/DataTypes.h> +#include <string> +#include <vector> + +namespace mcld { + +class BranchIsland; +class FragmentRef; +class IRBuilder; + +class AArch64CA53ErratumStub : public Stub { + public: + AArch64CA53ErratumStub(); + + AArch64CA53ErratumStub(const uint32_t* pData, + size_t pSize, + const char* pName, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd); + + ~AArch64CA53ErratumStub(); + + bool isMyDuty(const FragmentRef& pFragRef) const; + + void applyFixup(FragmentRef& pSrcFragRef, + IRBuilder& pBuilder, + BranchIsland& pIsland); + + const std::string& name() const; + + const uint32_t* getData() const; + + const uint8_t* getContent() const; + + size_t size() const; + + size_t alignment() const; + + public: + virtual unsigned getErratumSequenceSize() const = 0; + + virtual unsigned getErratumInsnOffset() const = 0; + + private: + static const uint32_t TEMPLATE[]; + + private: + const uint32_t* m_pData; + std::string m_Name; + size_t m_Size; + + private: + DISALLOW_COPY_AND_ASSIGN(AArch64CA53ErratumStub); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64CA53ERRATUMSTUB_H_ diff --git a/lib/Target/AArch64/AArch64GNUInfo.h b/lib/Target/AArch64/AArch64GNUInfo.h index 491d189..e2a2857 100644 --- a/lib/Target/AArch64/AArch64GNUInfo.h +++ b/lib/Target/AArch64/AArch64GNUInfo.h @@ -20,8 +20,6 @@ class AArch64GNUInfo : public GNUInfo { uint32_t machine() const { return llvm::ELF::EM_AARCH64; } - uint64_t abiPageSize() const { return 0x10000; } - uint64_t defaultTextSegmentAddr() const { return 0x400000; } // There are no processor-specific flags so this field shall contain zero. diff --git a/lib/Target/AArch64/AArch64InsnHelpers.h b/lib/Target/AArch64/AArch64InsnHelpers.h new file mode 100644 index 0000000..265464f --- /dev/null +++ b/lib/Target/AArch64/AArch64InsnHelpers.h @@ -0,0 +1,278 @@ +//===- AArch64InsnHelpers.h -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64INSNHELPERS_H_ +#define TARGET_AARCH64_AARCH64INSNHELPERS_H_ + +#include "mcld/Support/Compiler.h" + +namespace mcld { + +class AArch64InsnHelpers { + public: + typedef uint32_t InsnType; + + static constexpr unsigned InsnSize = 4; + + // Zero register encoding - 31. + static constexpr unsigned ZR = 31; + + static unsigned getBits(InsnType insn, int pos, int l) { + return (insn >> pos) & ((1 << l) - 1); + } + + static unsigned getRt(InsnType insn) { + return getBits(insn, 0, 5); + } + + static unsigned getRt2(InsnType insn) { + return getBits(insn, 10, 5); + } + + static unsigned getRa(InsnType insn) { + return getBits(insn, 10, 5); + } + + static unsigned getRd(InsnType insn) { + return getBits(insn, 0, 5); + } + + static unsigned getRn(InsnType insn) { + return getBits(insn, 5, 5); + } + + static unsigned getRm(InsnType insn) { + return getBits(insn, 16, 5); + } + + static unsigned getBit(InsnType insn, int pos) { + return getBits(insn, pos, 1); + } + + static unsigned getOp31(InsnType insn) { + return getBits(insn, 21, 3); + } + + // All ld/st ops. See C4-182 of the ARM ARM. The encoding space for LD_PCREL, + // LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops. + static bool isLD(InsnType insn) { + return (getBit(insn, 22) == 1); + } + + static bool isLDST(InsnType insn) { + return (((insn) & 0x0a000000) == 0x08000000); + } + + static bool isLDSTEX(InsnType insn) { + return (((insn) & 0x3f000000) == 0x08000000); + } + + static bool isLDSTPCREL(InsnType insn) { + return (((insn) & 0x3b000000) == 0x18000000); + } + + static bool isLDSTNAP(InsnType insn) { + return (((insn) & 0x3b800000) == 0x28000000); + } + + static bool isLDSTPPI(InsnType insn) { + return (((insn) & 0x3b800000) == 0x28800000); + } + + static bool isLDSTPO(InsnType insn) { + return (((insn) & 0x3b800000) == 0x29000000); + } + + static bool isLDSTPPRE(InsnType insn) { + return (((insn) & 0x3b800000) == 0x29800000); + } + + static bool isLDSTUI(InsnType insn) { + return (((insn) & 0x3b200c00) == 0x38000000); + } + + static bool isLDSTPIIMM(InsnType insn) { + return (((insn) & 0x3b200c00) == 0x38000400); + } + + static bool isLDSTU(InsnType insn) { + return (((insn) & 0x3b200c00) == 0x38000800); + } + + static bool isLDSTPREIMM(InsnType insn) { + return (((insn) & 0x3b200c00) == 0x38000c00); + } + + static bool isLDSTRO(InsnType insn) { + return (((insn) & 0x3b200c00) == 0x38200800); + } + + static bool isLDSTUIMM(InsnType insn) { + return (((insn) & 0x3b000000) == 0x39000000); + } + + static bool isLDSTSIMDM(InsnType insn) { + return (((insn) & 0xbfbf0000) == 0x0c000000); + } + + static bool isLDSTSIMDMPI(InsnType insn) { + return (((insn) & 0xbfa00000) == 0x0c800000); + } + + static bool isLDSTSIMDS(InsnType insn) { + return (((insn) & 0xbf9f0000) == 0x0d000000); + } + + static bool isLDSTSIMDSPI(InsnType insn) { + return (((insn) & 0xbf800000) == 0x0d800000); + } + + // Return true if INSN is a mac insn. + static bool isMAC(InsnType insn) { + return (insn & 0xff000000) == 0x9b000000; + } + + // Return true if INSN is multiply-accumulate + static bool isMLXL(InsnType insn) { + unsigned op31 = getOp31(insn); + // Exclude MUL instructions which are encoded as a multiple-accumulate with + // RA = XZR + if (isMAC(insn) && + ((op31 == 0) || (op31 == 1) || (op31 == 5)) && + getRa(insn) != ZR) { + return true; + } + return false; + } + + // Classify an INSN if it is indeed a load/store. + // + // Return true if INSN is a LD/ST instruction otherwise return false. For + // scalar LD/ST instructions is_pair is false, rt is returned and rt2 is set + // equal to rt. For LD/ST pair instructions is_pair is true, rt and rt2 are + // returned. + static bool isMemOp(InsnType insn, + unsigned& rt, + unsigned& rt2, + bool& is_pair, + bool& is_load) { + // Bail out quickly if INSN doesn't fall into the the load-store encoding + // space. + if (!isLDST(insn)) { + return false; + } + + is_pair = false; + is_load = false; + + if (isLDSTEX(insn)) { + rt = getRt(insn); + rt2 = rt; + if (getBit(insn, 21) == 1) { + is_pair = true; + rt2 = getRt2(insn); + } + is_load = isLD(insn); + return true; + } else if (isLDSTNAP(insn) || + isLDSTPPI(insn) || + isLDSTPO(insn) || + isLDSTPPRE(insn)) { + rt = getRt(insn); + rt2 = getRt2(insn); + is_pair = true; + is_load = isLD(insn); + } else if (isLDSTPCREL(insn) || + isLDSTUI(insn) || + isLDSTPIIMM(insn) || + isLDSTU(insn) || + isLDSTPREIMM(insn) || + isLDSTRO(insn) || + isLDSTUIMM(insn)) { + rt = getRt(insn); + rt2 = rt; + unsigned opc = getBits(insn, 22, 2); + unsigned v = getBit(insn, 26); + unsigned opc_v = opc | (v << 2); + if (isLDSTPCREL(insn) || + ((opc_v == 1) || + (opc_v == 2) || + (opc_v == 3) || + (opc_v == 5) || + (opc_v == 7))) { + is_load = true; + } + return true; + } else if (isLDSTSIMDM(insn) || isLDSTSIMDMPI(insn)) { + unsigned opcode = (insn >> 12) & 0xf; + rt = getRt(insn); + is_load = (getBit(insn, 22) != 0); + switch (opcode) { + case 0: + case 2: { + rt2 = rt + 3; + return true; + } + case 4: + case 6: { + rt2 = rt + 2; + return true; + } + case 7: { + rt2 = rt; + return true; + } + case 8: + case 10: { + rt2 = rt + 1; + return true; + } + default: { + return false; + } + } // switch (opcode) + } else if (isLDSTSIMDS(insn) || isLDSTSIMDSPI(insn)) { + unsigned r = (insn >> 21) & 1; + unsigned opcode = (insn >> 13) & 0x7; + rt = getRt(insn); + is_load = (getBit(insn, 22) != 0); + switch (opcode) { + case 0: + case 2: + case 4: + case 6: { + rt2 = rt + r; + return true; + } + case 1: + case 3: + case 5: + case 7: { + rt2 = rt + ((r == 0) ? 2 : 3); + return true; + } + default: { + return false; + } + } // switch (opcode) + } + + return false; + } + + static InsnType buildBranchInsn() { + return 0x14000000; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(AArch64InsnHelpers); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64INSNHELPERS_H_ diff --git a/lib/Target/AArch64/AArch64LDBackend.cpp b/lib/Target/AArch64/AArch64LDBackend.cpp index 9224275..b899a5c 100644 --- a/lib/Target/AArch64/AArch64LDBackend.cpp +++ b/lib/Target/AArch64/AArch64LDBackend.cpp @@ -7,9 +7,14 @@ // //===----------------------------------------------------------------------===// #include "AArch64.h" +#include "AArch64CA53Erratum835769Stub.h" +#include "AArch64CA53Erratum843419Stub.h" +#include "AArch64CA53Erratum843419Stub2.h" #include "AArch64ELFDynamic.h" #include "AArch64GNUInfo.h" +#include "AArch64InsnHelpers.h" #include "AArch64LDBackend.h" +#include "AArch64LongBranchStub.h" #include "AArch64Relocator.h" #include "mcld/IRBuilder.h" @@ -281,7 +286,6 @@ uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection, return result; } - // TODO return pRegion.size(); } @@ -304,36 +308,232 @@ unsigned int AArch64GNULDBackend::getTargetSectionOrder( return SHO_UNDEFINED; } +void AArch64GNULDBackend::scanErrata(Module& pModule, + IRBuilder& pBuilder, + size_t& num_new_stubs, + size_t& stubs_strlen) { + // TODO: Implement AArch64 ErrataStubFactory to create the specific erratum + // stub and simplify the logics. + for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end(); + sect != sectEnd; ++sect) { + if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) { + SectionData* sd = (*sect)->getSectionData(); + for (SectionData::iterator it = sd->begin(), ie = sd->end(); it != ie; + ++it) { + Fragment* frag = llvm::dyn_cast<RegionFragment>(it); + if (frag != NULL) { + FragmentRef* frag_ref = FragmentRef::Create(*frag, 0); + for (unsigned offset = 0; offset < frag->size(); + offset += AArch64InsnHelpers::InsnSize) { + Stub* stub = getStubFactory()->create(*frag_ref, + pBuilder, + *getBRIslandFactory()); + if (stub != NULL) { + // A stub symbol should be local + assert(stub->symInfo() != NULL && stub->symInfo()->isLocal()); + const AArch64CA53ErratumStub* erratum_stub = + reinterpret_cast<const AArch64CA53ErratumStub*>(stub); + assert(erratum_stub != NULL); + // Rewrite the erratum instruction as a branch to the stub. + uint64_t offset = frag_ref->offset() + + erratum_stub->getErratumInsnOffset(); + Relocation* reloc = + Relocation::Create(llvm::ELF::R_AARCH64_JUMP26, + *(FragmentRef::Create(*frag, offset)), + /* pAddend */0); + reloc->setSymInfo(stub->symInfo()); + reloc->target() = AArch64InsnHelpers::buildBranchInsn(); + addExtraRelocation(reloc); + + ++num_new_stubs; + stubs_strlen += stub->symInfo()->nameSize() + 1; + } + + frag_ref->assign(*frag, offset + AArch64InsnHelpers::InsnSize); + } // for each INSN + } + } // for each FRAGMENT + } + } // for each TEXT section +} + bool AArch64GNULDBackend::doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { - // TODO - return false; + assert(getStubFactory() != NULL && getBRIslandFactory() != NULL); + + // Number of new stubs added + size_t num_new_stubs = 0; + // String lengh to hold new stub symbols + size_t stubs_strlen = 0; + + if (config().targets().fixCA53Erratum835769() || + config().targets().fixCA53Erratum843419()) { + scanErrata(pModule, pBuilder, num_new_stubs, stubs_strlen); + } + + ELFFileFormat* file_format = getOutputFormat(); + // check branch relocs and create the related stubs if needed + Module::obj_iterator input, inEnd = pModule.obj_end(); + for (input = pModule.obj_begin(); input != inEnd; ++input) { + LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); + for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { + if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData()) + continue; + RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end(); + for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) { + Relocation* relocation = llvm::cast<Relocation>(reloc); + + switch (relocation->type()) { + case llvm::ELF::R_AARCH64_CALL26: + case llvm::ELF::R_AARCH64_JUMP26: { + // calculate the possible symbol value + uint64_t sym_value = 0x0; + LDSymbol* symbol = relocation->symInfo()->outSymbol(); + if (symbol->hasFragRef()) { + uint64_t value = symbol->fragRef()->getOutputOffset(); + uint64_t addr = + symbol->fragRef()->frag()->getParent()->getSection().addr(); + sym_value = addr + value; + } + if ((relocation->symInfo()->reserved() & + AArch64Relocator::ReservePLT) != 0x0) { + // FIXME: we need to find out the address of the specific plt + // entry + assert(file_format->hasPLT()); + sym_value = file_format->getPLT().addr(); + } + Stub* stub = getStubFactory()->create(*relocation, // relocation + sym_value, // symbol value + pBuilder, + *getBRIslandFactory()); + if (stub != NULL) { + // a stub symbol should be local + assert(stub->symInfo() != NULL && stub->symInfo()->isLocal()); + // reset the branch target of the reloc to this stub instead + relocation->setSymInfo(stub->symInfo()); + + ++num_new_stubs; + stubs_strlen += stub->symInfo()->nameSize() + 1; + } + break; + } + default: { + break; + } + } // end of switch + } // for all relocations + } // for all relocation section + } // for all inputs + + // Find the first fragment w/ invalid offset due to stub insertion. + std::vector<Fragment*> invalid_frags; + pFinished = true; + for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), + island_end = getBRIslandFactory()->end(); + island != island_end; + ++island) { + if ((*island).size() > stubGroupSize()) { + error(diag::err_no_space_to_place_stubs) << stubGroupSize(); + return false; + } + + if ((*island).numOfStubs() == 0) { + continue; + } + + Fragment* exit = &*(*island).end(); + if (exit == (*island).begin()->getParent()->end()) { + continue; + } + + if (((*island).offset() + (*island).size()) > exit->getOffset()) { + if (invalid_frags.empty() || + (invalid_frags.back()->getParent() != (*island).getParent())) { + invalid_frags.push_back(exit); + pFinished = false; + } + continue; + } + } + + // Reset the offset of invalid fragments. + for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie; + ++it) { + Fragment* invalid = *it; + while (invalid != NULL) { + invalid->setOffset(invalid->getPrevNode()->getOffset() + + invalid->getPrevNode()->size()); + invalid = invalid->getNextNode(); + } + } + + // Fix up the size of .symtab, .strtab, and TEXT sections + if (num_new_stubs == 0) { + return false; + } else { + switch (config().options().getStripSymbolMode()) { + case GeneralOptions::StripSymbolMode::StripAllSymbols: + case GeneralOptions::StripSymbolMode::StripLocals: + break; + default: { + LDSection& symtab = file_format->getSymTab(); + LDSection& strtab = file_format->getStrTab(); + + symtab.setSize(symtab.size() + + sizeof(llvm::ELF::Elf64_Sym) * num_new_stubs); + symtab.setInfo(symtab.getInfo() + num_new_stubs); + strtab.setSize(strtab.size() + stubs_strlen); + } + } // switch (config().options().getStripSymbolMode()) + + SectionData* prev = NULL; + for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), + island_end = getBRIslandFactory()->end(); + island != island_end; + ++island) { + SectionData* sd = (*island).begin()->getParent(); + if ((*island).numOfStubs() != 0) { + if (sd != prev) { + sd->getSection().setSize(sd->back().getOffset() + sd->back().size()); + } + } + prev = sd; + } + return true; + } // if (num_new_stubs == 0) } bool AArch64GNULDBackend::initTargetStubs() { - // TODO - return true; + StubFactory* factory = getStubFactory(); + if (factory != NULL) { + factory->addPrototype(new AArch64LongBranchStub(config().isCodeIndep())); + if (config().targets().fixCA53Erratum835769()) { + factory->addPrototype(new AArch64CA53Erratum835769Stub()); + } + if (config().targets().fixCA53Erratum843419()) { + factory->addPrototype(new AArch64CA53Erratum843419Stub()); + factory->addPrototype(new AArch64CA53Erratum843419Stub2()); + } + return true; + } + return false; } void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule) { - // TODO } bool AArch64GNULDBackend::finalizeTargetSymbols() { - // TODO return true; } bool AArch64GNULDBackend::mergeSection(Module& pModule, const Input& pInput, LDSection& pSection) { - // TODO return true; } bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD) { - // TODO return true; } diff --git a/lib/Target/AArch64/AArch64LDBackend.h b/lib/Target/AArch64/AArch64LDBackend.h index b94d535..a8cd52a 100644 --- a/lib/Target/AArch64/AArch64LDBackend.h +++ b/lib/Target/AArch64/AArch64LDBackend.h @@ -26,8 +26,11 @@ class GNUInfo; /// class AArch64GNULDBackend : public GNULDBackend { public: - static const int64_t AARCH64_MAX_FWD_BRANCH_OFFSET = (((1 << 25) - 1) << 2); - static const int64_t AARCH64_MAX_BWD_BRANCH_OFFSET = (-((1 << 25) << 2)); + static constexpr int64_t MAX_FWD_BRANCH_OFFSET = (((1 << 25) - 1) << 2); + static constexpr int64_t MAX_BWD_BRANCH_OFFSET = (-((1 << 25) << 2)); + + static constexpr int64_t MAX_ADRP_IMM = (1 << 20) - 1; + static constexpr int64_t MIN_ADRP_IMM = -(1 << 20); public: AArch64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo); @@ -113,8 +116,13 @@ class AArch64GNULDBackend : public GNULDBackend { private: void defineGOTSymbol(IRBuilder& pBuilder); - int64_t maxFwdBranchOffset() { return AARCH64_MAX_FWD_BRANCH_OFFSET; } - int64_t maxBwdBranchOffset() { return AARCH64_MAX_BWD_BRANCH_OFFSET; } + int64_t maxFwdBranchOffset() const { return MAX_FWD_BRANCH_OFFSET; } + int64_t maxBwdBranchOffset() const { return MAX_BWD_BRANCH_OFFSET; } + + void scanErrata(Module& pModule, + IRBuilder& pBuilder, + size_t& num_new_stubs, + size_t& stubs_strlen); /// mayRelax - Backends should override this function if they need relaxation bool mayRelax() { return true; } diff --git a/lib/Target/AArch64/AArch64LongBranchStub.cpp b/lib/Target/AArch64/AArch64LongBranchStub.cpp new file mode 100644 index 0000000..479abca --- /dev/null +++ b/lib/Target/AArch64/AArch64LongBranchStub.cpp @@ -0,0 +1,145 @@ +//===- AArch64LongBranchStub.cpp ------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64LongBranchStub.h" +#include "AArch64LDBackend.h" +#include "AArch64RelocationHelpers.h" + +#include "mcld/Fragment/Relocation.h" +#include "mcld/LD/BranchIsland.h" +#include "mcld/LD/LDSymbol.h" +#include "mcld/LD/ResolveInfo.h" + +#include <llvm/Support/ELF.h> + +#include <cassert> + +namespace mcld { + +//===----------------------------------------------------------------------===// +// AArch64LongBranchStub +//===----------------------------------------------------------------------===// +const uint32_t AArch64LongBranchStub::PIC_TEMPLATE[] = { + 0x58000090, // ldr ip0, 0x10 + 0x10000011, // adr ip1, #0 + 0x8b110210, // add ip0, ip0, ip1 + 0xd61f0200, // br ip0 + 0x00000000, // .xword <-- R_AARCH64_PREL64(X+12) + 0x00000000, +}; + +const uint32_t AArch64LongBranchStub::TEMPLATE[] = { + 0x58000050, // ldr ip0, 0x8 + 0xd61f0200, // br ip0 + 0x00000000, // .xword <-- R_AARCH64_PREL64(X) + 0x00000000, +}; + +const uint32_t AArch64LongBranchStub::ADRP_TEMPLATE[] = { + 0x90000010, // adrp ip0, X <-- R_AARCH64_ADR_PREL_PG_HI21(X) + 0x91000210, // add ip0, ip0, :lo12:X <-- R_AARCH64_ADD_ABS_LO12_NC(X) + 0xd61f0200, // br ip0 +}; + +AArch64LongBranchStub::AArch64LongBranchStub(bool pIsOutputPIC) + : m_pData(NULL), + m_Name("ljmp_prototype"), + m_Size(0x0) { + if (pIsOutputPIC) { + m_pData = PIC_TEMPLATE; + m_Size = sizeof(PIC_TEMPLATE); + addFixup(0x10, 12, llvm::ELF::R_AARCH64_PREL64); + } else { + m_pData = TEMPLATE; + m_Size = sizeof(TEMPLATE); + addFixup(0x8, 0, llvm::ELF::R_AARCH64_PREL64); + } +} + +/// for doClone +AArch64LongBranchStub::AArch64LongBranchStub(const uint32_t* pData, + size_t pSize, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd) + : m_pData(pData), + m_Name("ljmp_veneer"), + m_Size(pSize) { + for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it) { + addFixup(**it); + } +} + +AArch64LongBranchStub::~AArch64LongBranchStub() { +} + +bool AArch64LongBranchStub::isMyDuty(const Relocation& pReloc, + uint64_t pSource, + uint64_t pTargetSymValue) const { + assert((pReloc.type() == llvm::ELF::R_AARCH64_CALL26) || + (pReloc.type() == llvm::ELF::R_AARCH64_JUMP26)); + int64_t dest = pTargetSymValue + pReloc.addend(); + int64_t branch_offset = dest - pSource; + if ((branch_offset > AArch64GNULDBackend::MAX_FWD_BRANCH_OFFSET) || + (branch_offset < AArch64GNULDBackend::MAX_BWD_BRANCH_OFFSET)) { + return true; + } + return false; +} + +static bool isValidForADRP(uint64_t pSource, uint64_t pDest) { + int64_t imm = static_cast<int64_t>((helper_get_page_address(pDest) - + helper_get_page_address(pSource))) >> 12; + return ((imm <= AArch64GNULDBackend::MAX_ADRP_IMM) && + (imm >= AArch64GNULDBackend::MIN_ADRP_IMM)); +} + +void AArch64LongBranchStub::applyFixup(Relocation& pSrcReloc, + IRBuilder& pBuilder, + BranchIsland& pIsland) { + // Try to relax the stub itself. + LDSymbol* symbol = pSrcReloc.symInfo()->outSymbol(); + uint64_t dest = symbol->fragRef()->frag()->getParent()->getSection().addr() + + symbol->fragRef()->getOutputOffset(); + uint64_t src = pIsland.getParent()->getSection().addr() + + pIsland.offset() + + pIsland.size(); + if (isValidForADRP(src, dest)) { + m_pData = ADRP_TEMPLATE; + m_Name = "adrp_veneer"; + m_Size = sizeof(ADRP_TEMPLATE); + + getFixupList().clear(); + addFixup(0x0, 0, llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21); + addFixup(0x4, 0, llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC); + } + + Stub::applyFixup(pSrcReloc, pBuilder, pIsland); +} + +const std::string& AArch64LongBranchStub::name() const { + return m_Name; +} + +const uint8_t* AArch64LongBranchStub::getContent() const { + return reinterpret_cast<const uint8_t*>(m_pData); +} + +size_t AArch64LongBranchStub::size() const { + return m_Size; +} + +size_t AArch64LongBranchStub::alignment() const { + return 8; +} + +Stub* AArch64LongBranchStub::doClone() { + return new AArch64LongBranchStub(m_pData, m_Size, fixup_begin(), fixup_end()); +} + +} // namespace mcld diff --git a/lib/Target/AArch64/AArch64LongBranchStub.h b/lib/Target/AArch64/AArch64LongBranchStub.h new file mode 100644 index 0000000..d996040 --- /dev/null +++ b/lib/Target/AArch64/AArch64LongBranchStub.h @@ -0,0 +1,70 @@ +//===- AArch64LongBranchStub.h --------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_AARCH64_AARCH64LONGBRANCHSTUB_H_ +#define TARGET_AARCH64_AARCH64LONGBRANCHSTUB_H_ + +#include "mcld/Fragment/Stub.h" +#include "mcld/Support/Compiler.h" +#include <llvm/Support/DataTypes.h> +#include <string> +#include <vector> + +namespace mcld { + +class BranchIsland; +class IRBuilder; +class Relocation; + +class AArch64LongBranchStub : public Stub { + public: + explicit AArch64LongBranchStub(bool pIsOutputPIC); + + ~AArch64LongBranchStub(); + + bool isMyDuty(const Relocation& pReloc, + uint64_t pSource, + uint64_t pTargetSymValue) const; + + void applyFixup(Relocation& pSrcReloc, + IRBuilder& pBuilder, + BranchIsland& pIsland); + + const std::string& name() const; + + const uint8_t* getContent() const; + + size_t size() const; + + size_t alignment() const; + + private: + /// for doClone + AArch64LongBranchStub(const uint32_t* pData, + size_t pSize, + const_fixup_iterator pBegin, + const_fixup_iterator pEnd); + + /// doClone + Stub* doClone(); + + private: + static const uint32_t PIC_TEMPLATE[]; + static const uint32_t TEMPLATE[]; + static const uint32_t ADRP_TEMPLATE[]; + const uint32_t* m_pData; + std::string m_Name; + size_t m_Size; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(AArch64LongBranchStub); +}; + +} // namespace mcld + +#endif // TARGET_AARCH64_AARCH64LONGBRANCHSTUB_H_ diff --git a/lib/Target/AArch64/AArch64RelocationFunctions.h b/lib/Target/AArch64/AArch64RelocationFunctions.h index 2ed555d..668cc14 100644 --- a/lib/Target/AArch64/AArch64RelocationFunctions.h +++ b/lib/Target/AArch64/AArch64RelocationFunctions.h @@ -29,6 +29,7 @@ #define DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ValueType, MappedType) /* NOLINT */\ ValueType(0x0, MappedType(&none, "R_AARCH64_NULL", 0)), /* NOLINT */\ + ValueType(0x1, MappedType(&none, "R_AARCH64_REWRITE_INSN", 32)), /* NOLINT */\ ValueType(0x100, MappedType(&none, "R_AARCH64_NONE", 0)), /* NOLINT */\ ValueType(0x101, MappedType(&abs, "R_AARCH64_ABS64", 64)), /* NOLINT */\ ValueType(0x102, MappedType(&abs, "R_AARCH64_ABS32", 32)), /* NOLINT */\ diff --git a/lib/Target/AArch64/AArch64Relocator.cpp b/lib/Target/AArch64/AArch64Relocator.cpp index e59c112..9632f02 100644 --- a/lib/Target/AArch64/AArch64Relocator.cpp +++ b/lib/Target/AArch64/AArch64Relocator.cpp @@ -71,8 +71,10 @@ AArch64Relocator::~AArch64Relocator() { Relocator::Result AArch64Relocator::applyRelocation(Relocation& pRelocation) { Relocation::Type type = pRelocation.type(); - // valid types are 0x0, 0x100-0x239 - if ((type < 0x100 || type > 0x239) && (type != 0x0)) { + // valid types are 0x0, 0x100-1032, and R_AARCH64_REWRITE_INSN + if ((type < 0x100 || type > 1032) && + (type != 0x0) && + (type != R_AARCH64_REWRITE_INSN)) { return Relocator::Unknown; } assert(ApplyFunctions.find(type) != ApplyFunctions.end()); @@ -399,6 +401,31 @@ void AArch64Relocator::scanRelocation(Relocation& pReloc, issueUndefRef(pReloc, pSection, pInput); } +bool +AArch64Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const { + switch (pReloc.type()) { + case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21: + case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: + case llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC: + case llvm::ELF::R_AARCH64_ADR_GOT_PAGE: + case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: { + return true; + } + default: { + if (pReloc.symInfo()->isLocal()) { + // Do not fold any local symbols if building a shared object. + return (config().codeGenType() == LinkerConfig::DynObj); + } else { + // Do not fold any none global defualt symbols if building a shared + // object. + return ((config().codeGenType() == LinkerConfig::DynObj) && + (pReloc.symInfo()->visibility() != ResolveInfo::Default)); + } + } + } + return false; +} + uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const { if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32) error(diag::unsupport_reloc_for_debug_string) diff --git a/lib/Target/AArch64/AArch64Relocator.h b/lib/Target/AArch64/AArch64Relocator.h index 3de682c..f9641c0 100644 --- a/lib/Target/AArch64/AArch64Relocator.h +++ b/lib/Target/AArch64/AArch64Relocator.h @@ -58,6 +58,11 @@ class AArch64Relocator : public Relocator { */ enum EntryValue { Default = 0, SymVal = 1 }; + enum { + // mcld internal relocation to rewrite an instruction. + R_AARCH64_REWRITE_INSN = 1, + }; + public: AArch64Relocator(AArch64GNULDBackend& pParent, const LinkerConfig& pConfig); ~AArch64Relocator(); @@ -96,6 +101,10 @@ class AArch64Relocator : public Relocator { LDSection& pSection, Input& pInput); + /// mayHaveFunctionPointerAccess - check if the given reloc would possibly + /// access a function pointer. + virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const; + /// getDebugStringOffset - get the offset from the relocation target. This is /// used to get the debug string offset. uint32_t getDebugStringOffset(Relocation& pReloc) const; diff --git a/lib/Target/AArch64/Android.mk b/lib/Target/AArch64/Android.mk index a143c53..3abc1be 100644 --- a/lib/Target/AArch64/Android.mk +++ b/lib/Target/AArch64/Android.mk @@ -1,11 +1,16 @@ LOCAL_PATH:= $(call my-dir) mcld_aarch64_target_SRC_FILES := \ + AArch64CA53Erratum835769Stub.cpp \ + AArch64CA53Erratum843419Stub2.cpp \ + AArch64CA53Erratum843419Stub.cpp \ + AArch64CA53ErratumStub.cpp \ AArch64Diagnostic.cpp \ AArch64ELFDynamic.cpp \ AArch64Emulation.cpp \ AArch64GOT.cpp \ AArch64LDBackend.cpp \ + AArch64LongBranchStub.cpp \ AArch64PLT.cpp \ AArch64Relocator.cpp diff --git a/lib/Target/ARM/ARMException.cpp b/lib/Target/ARM/ARMException.cpp index 3893190..4e354ed 100644 --- a/lib/Target/ARM/ARMException.cpp +++ b/lib/Target/ARM/ARMException.cpp @@ -11,7 +11,6 @@ #include "ARMLDBackend.h" -#include "mcld/ADT/ilist_sort.h" #include "mcld/Fragment/RegionFragment.h" #include "mcld/LD/ELFFileFormat.h" #include "mcld/LD/LDContext.h" @@ -19,17 +18,21 @@ #include <memory> -static const char g_CantUnwindEntry[8] = { - // Relocation to text section. - 0, 0, 0, 0, - // EXIDX_CANTUNWIND (little endian.) - 1, 0, 0, 0, -}; - namespace mcld { +static RegionFragment* findRegionFragment(LDSection& pSection) { + SectionData* sectData = pSection.getSectionData(); + for (SectionData::iterator it = sectData->begin(), + end = sectData->end(); it != end; ++it) { + if (it->getKind() == Fragment::Region) { + return static_cast<RegionFragment*>(&*it); + } + } + return NULL; +} + void ARMExData::addInputMap(Input* pInput, - std::unique_ptr<ARMInputExMap>&& pExMap) { + std::unique_ptr<ARMInputExMap> pExMap) { assert(m_Inputs.find(pInput) == m_Inputs.end() && "multiple maps for an input"); @@ -46,27 +49,17 @@ void ARMExData::addInputMap(Input* pInput, } } -void ARMGNULDBackend::scanInputExceptionSections(Module& pModule) { +std::unique_ptr<ARMExData> ARMExData::create(Module& pModule) { + std::unique_ptr<ARMExData> exData(new ARMExData()); for (Module::obj_iterator it = pModule.obj_begin(), end = pModule.obj_end(); it != end; ++it) { Input* input = *it; - scanInputExceptionSections(pModule, *input); - } -} - -static RegionFragment* findRegionFragment(LDSection& pSection) { - SectionData* sectData = pSection.getSectionData(); - for (SectionData::iterator it = sectData->begin(), - end = sectData->end(); it != end; ++it) { - if (it->getKind() == Fragment::Region) { - return static_cast<RegionFragment*>(&*it); - } + exData->addInputMap(input, ARMInputExMap::create(*input)); } - return NULL; + return exData; } -void ARMGNULDBackend::scanInputExceptionSections(Module& pModule, - Input& pInput) { +std::unique_ptr<ARMInputExMap> ARMInputExMap::create(Input& pInput) { std::unique_ptr<ARMInputExMap> exMap(new ARMInputExMap()); // Scan the input and collect all related sections. @@ -74,21 +67,13 @@ void ARMGNULDBackend::scanInputExceptionSections(Module& pModule, for (LDContext::sect_iterator it = ctx->sectBegin(), end = ctx->sectEnd(); it != end; ++it) { LDSection* sect = *it; - llvm::StringRef name(sect->name()); - - if (name.startswith(".ARM.exidx")) { - ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name); + if (sect->type() == llvm::ELF::SHT_ARM_EXIDX) { + ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(*sect); exTuple->setExIdxSection(sect); exTuple->setTextSection(sect->getLink()); - } else if (name.startswith(".ARM.extab")) { - ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name); - exTuple->setExTabSection(sect); - } else if (name.startswith(".rel.ARM.exidx")) { - ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name); - exTuple->setRelExIdxSection(sect); - } else if (name.startswith(".rel.ARM.extab")) { - ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name); - exTuple->setRelExIdxSection(sect); + if (sect->getLink() == NULL) { + fatal(diag::eh_missing_text_section) << sect->name() << pInput.name(); + } } } @@ -100,225 +85,38 @@ void ARMGNULDBackend::scanInputExceptionSections(Module& pModule, ARMExSectionTuple* exTuple = it->second.get(); LDSection* const text = exTuple->getTextSection(); LDSection* const exIdx = exTuple->getExIdxSection(); - LDSection* const exTab = exTuple->getExTabSection(); - LDSection* const relExIdx = exTuple->getRelExIdxSection(); - LDSection* const relExTab = exTuple->getRelExTabSection(); - - // Check the .ARM.exidx section. - if (!exIdx) { - if (exTab) { - fatal(diag::eh_missing_exidx_section) << exTab->name() << pInput.name(); - } else if (relExIdx) { - fatal(diag::eh_missing_exidx_section) << relExIdx->name() - << pInput.name(); - } else if (relExTab) { - fatal(diag::eh_missing_exidx_section) << relExTab->name() - << pInput.name(); - } else { - llvm_unreachable("unexpected bad exception tuple"); - } - } - - // Check the text section. - if (!text) { - fatal(diag::eh_missing_text_section) << exIdx->name() << pInput.name(); - } // Ignore the exception section if the text section is ignored. if ((text->kind() == LDFileFormat::Ignore) || (text->kind() == LDFileFormat::Folded)) { // Set the related exception sections as LDFileFormat::Ignore. exIdx->setKind(LDFileFormat::Ignore); - if (exTab) { - exTab->setKind(LDFileFormat::Ignore); - } // Remove this tuple from the input exception map. - exMap->erase(it++); + ARMInputExMap::iterator deadIt = it++; + exMap->erase(deadIt); continue; } // Get RegionFragment from ".text", ".ARM.exidx", and ".ARM.extab" sections. RegionFragment* textFrag = findRegionFragment(*text); RegionFragment* exIdxFrag = findRegionFragment(*exIdx); - RegionFragment* exTabFrag = exTab ? findRegionFragment(*exTab) : NULL; exTuple->setTextFragment(textFrag); exTuple->setExIdxFragment(exIdxFrag); - exTuple->setExTabFragment(exTabFrag); - - // Get the RelocData from ".rel.ARM.exidx" and ".rel.ARM.extab" sections. - RelocData* exIdxRD = relExIdx ? relExIdx->getRelocData() : NULL; - RelocData* exTabRD = relExTab ? relExTab->getRelocData() : NULL; - - exTuple->setExIdxRelocData(exIdxRD); - exTuple->setExTabRelocData(exTabRD); // If there is no region fragment in the .ARM.extab section, then we can // skip this tuple. - if (!exIdxFrag) { - exMap->erase(it++); + if (exIdxFrag == NULL) { + ARMInputExMap::iterator deadIt = it++; + exMap->erase(deadIt); continue; } - // TODO: Sort the RelocData w.r.t. the fixup offset. - // Check next tuple ++it; } - // Add input map - m_ExData.addInputMap(&pInput, std::move(exMap)); -} - -class ExIdxFragmentComparator { - private: - const ARMExData& m_ExData; - - public: - explicit ExIdxFragmentComparator(const ARMExData& pExData) - : m_ExData(pExData) { - } - - bool operator()(const Fragment& a, const Fragment& b) { - ARMExSectionTuple* tupleA = m_ExData.getTupleByExIdx(&a); - ARMExSectionTuple* tupleB = m_ExData.getTupleByExIdx(&b); - - Fragment* textFragA = tupleA->getTextFragment(); - Fragment* textFragB = tupleB->getTextFragment(); - - uint64_t addrA = textFragA->getParent()->getSection().addr() + - textFragA->getOffset(); - uint64_t addrB = textFragB->getParent()->getSection().addr() + - textFragB->getOffset(); - return (addrA < addrB); - } -}; - -static mcld::ResolveInfo* -CreateLocalSymbolToFragmentEnd(mcld::Module& pModule, mcld::Fragment& pFrag) { - // Create and add symbol to the name pool. - mcld::ResolveInfo* resolveInfo = - pModule.getNamePool().createSymbol(/* pName */"", - /* pIsDyn */false, - mcld::ResolveInfo::Section, - mcld::ResolveInfo::Define, - mcld::ResolveInfo::Local, - /* pSize */0, - mcld::ResolveInfo::Hidden); - if (resolveInfo == nullptr) { - return nullptr; - } - - // Create input symbol. - mcld::LDSymbol* inputSym = mcld::LDSymbol::Create(*resolveInfo); - if (inputSym == nullptr) { - return nullptr; - } - - inputSym->setFragmentRef(mcld::FragmentRef::Create(pFrag, pFrag.size())); - inputSym->setValue(/* pValue */0); - - // The output symbol is simply an alias to the input symbol. - resolveInfo->setSymPtr(inputSym); - - return resolveInfo; -} - -void ARMGNULDBackend::rewriteARMExIdxSection(Module& pModule) { - if (!m_pEXIDX->hasSectionData()) { - // Return if this is empty section. - return; - } - - SectionData* sectData = m_pEXIDX->getSectionData(); - SectionData::FragmentListType& list = sectData->getFragmentList(); - - // Move the first fragment (align fragment) and last fragment (null fragment) - // to temporary list because we would only like to sort the region fragment. - SectionData::FragmentListType tmp; - { - SectionData::iterator first = sectData->begin(); - SectionData::iterator last = sectData->end(); - --last; - - assert(first->getKind() == Fragment::Alignment); - assert(last->getKind() == Fragment::Null); - - tmp.splice(tmp.end(), list, first); - tmp.splice(tmp.end(), list, last); - } - - // Sort the region fragments in the .ARM.exidx output section. - sort(list, ExIdxFragmentComparator(m_ExData)); - - // Fix the coverage of the .ARM.exidx table. - llvm::StringRef cantUnwindRegion(g_CantUnwindEntry, - sizeof(g_CantUnwindEntry)); - - SectionData::FragmentListType::iterator it = list.begin(); - if (it != list.end()) { - Fragment* prevTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment(); - uint64_t prevTextEnd = prevTextFrag->getParent()->getSection().addr() + - prevTextFrag->getOffset() + - prevTextFrag->size(); - ++it; - while (it != list.end()) { - Fragment* currTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment(); - uint64_t currTextBegin = currTextFrag->getParent()->getSection().addr() + - currTextFrag->getOffset(); - - if (currTextBegin > prevTextEnd) { - // Found a gap. Insert a can't unwind entry. - RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); - frag->setParent(sectData); - list.insert(it, frag); - - // Add PREL31 reference to the beginning of the uncovered region. - Relocation* reloc = - Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), - *FragmentRef::Create(*frag, /* pOffset */0), - /* pAddend */0); - reloc->setSymInfo( - CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); - addExtraRelocation(reloc); - } - - prevTextEnd = currTextBegin + currTextFrag->size(); - prevTextFrag = currTextFrag; - ++it; - } - - // Add a can't unwind entry to terminate .ARM.exidx section. - RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); - frag->setParent(sectData); - list.push_back(frag); - - // Add PREL31 reference to the end of the .text section. - Relocation* reloc = - Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), - *FragmentRef::Create(*frag, /* pOffset */0), - /* pAddend */0); - reloc->setSymInfo(CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); - addExtraRelocation(reloc); - } - - // Add the first and the last fragment back. - list.splice(list.begin(), tmp, tmp.begin()); - list.splice(list.end(), tmp, tmp.begin()); - - // Update the fragment offsets. - uint64_t offset = 0; - for (SectionData::iterator it = sectData->begin(), end = sectData->end(); - it != end; ++it) { - it->setOffset(offset); - offset += it->size(); - } - - // Update the section size. - m_pEXIDX->setSize(offset); - - // Rebuild the section header. - setOutputSectionAddress(pModule); + return exMap; } } // namespace mcld diff --git a/lib/Target/ARM/ARMException.h b/lib/Target/ARM/ARMException.h index 96afbde..157be2e 100644 --- a/lib/Target/ARM/ARMException.h +++ b/lib/Target/ARM/ARMException.h @@ -9,8 +9,11 @@ #ifndef TARGET_ARM_ARMEXCEPTION_H_ #define TARGET_ARM_ARMEXCEPTION_H_ +#include "mcld/LD/LDSection.h" + #include <llvm/ADT/PointerUnion.h> #include <llvm/ADT/StringRef.h> +#include <llvm/Support/ELF.h> #include <map> #include <memory> @@ -21,6 +24,7 @@ namespace mcld { class Fragment; class Input; class LDSection; +class Module; class RegionFragment; class RelocData; @@ -29,10 +33,7 @@ class ARMExSectionTuple { public: ARMExSectionTuple() : m_pTextSection(NULL), - m_pExIdxSection(NULL), - m_pExTabSection(NULL), - m_pRelExIdxSection(NULL), - m_pRelExTabSection(NULL) { + m_pExIdxSection(NULL) { } LDSection* getTextSection() const { @@ -43,18 +44,6 @@ class ARMExSectionTuple { return m_pExIdxSection; } - LDSection* getExTabSection() const { - return m_pExTabSection; - } - - LDSection* getRelExIdxSection() const { - return m_pRelExIdxSection; - } - - LDSection* getRelExTabSection() const { - return m_pRelExTabSection; - } - void setTextSection(LDSection* pSection) { m_pTextSection = pSection; } @@ -63,18 +52,6 @@ class ARMExSectionTuple { m_pExIdxSection = pSection; } - void setExTabSection(LDSection* pSection) { - m_pExTabSection = pSection; - } - - void setRelExIdxSection(LDSection* pSection) { - m_pRelExIdxSection = pSection; - } - - void setRelExTabSection(LDSection* pSection) { - m_pRelExTabSection = pSection; - } - RegionFragment* getTextFragment() const { return m_pTextFragment; } @@ -83,18 +60,6 @@ class ARMExSectionTuple { return m_pExIdxFragment; } - RegionFragment* getExTabFragment() const { - return m_pExTabFragment; - } - - RelocData* getExIdxRelocData() const { - return m_pExIdxRelocData; - } - - RelocData* getExTabRelocData() const { - return m_pExTabRelocData; - } - void setTextFragment(RegionFragment* pFragment) { m_pTextFragment = pFragment; } @@ -103,18 +68,6 @@ class ARMExSectionTuple { m_pExIdxFragment = pFragment; } - void setExTabFragment(RegionFragment* pFragment) { - m_pExTabFragment = pFragment; - } - - void setExIdxRelocData(RelocData* pRelocData) { - m_pExIdxRelocData = pRelocData; - } - - void setExTabRelocData(RelocData* pRelocData) { - m_pExTabRelocData = pRelocData; - } - private: // .text section union { @@ -127,102 +80,60 @@ class ARMExSectionTuple { LDSection* m_pExIdxSection; RegionFragment* m_pExIdxFragment; }; - - // .ARM.extab section - union { - LDSection* m_pExTabSection; - RegionFragment* m_pExTabFragment; - }; - - // .rel.ARM.exidx section - union { - LDSection* m_pRelExIdxSection; - RelocData* m_pExIdxRelocData; - }; - - // .rel.ARM.extab section - union { - LDSection* m_pRelExTabSection; - RelocData* m_pExTabRelocData; - }; }; -/// ARMInputExMap - ARM exception handling data of an Input +/// ARMInputExMap - ARM exception handling section mapping of a mcld::Input. class ARMInputExMap { public: - typedef std::map<std::string, std::unique_ptr<ARMExSectionTuple> > NameMap; - typedef NameMap::iterator iterator; - typedef NameMap::const_iterator const_iterator; + typedef std::map<LDSection*, std::unique_ptr<ARMExSectionTuple> > SectMap; + typedef SectMap::iterator iterator; + typedef SectMap::const_iterator const_iterator; public: - ARMInputExMap() { } - - /// get - Get the ARMExSectionTuple by the corresponding text section name. - /// As an exception, to get the ARMExSectionTuple for .text section, use "" - /// as the section name instead. - ARMExSectionTuple* get(const char* pName) const { - NameMap::const_iterator it = m_NameToExData.find(pName); - if (it == m_NameToExData.end()) { + // create - Build the exception handling section mapping of a mcld::Input. + static std::unique_ptr<ARMInputExMap> create(Input &input); + + /// getByExSection - Get the ARMExSectionTuple by the address of the + /// .ARM.exidx section. + ARMExSectionTuple* getByExSection(LDSection &pSect) const { + assert(pSect.type() == llvm::ELF::SHT_ARM_EXIDX); + SectMap::const_iterator it = m_SectToExData.find(&pSect); + if (it == m_SectToExData.end()) { return NULL; } return it->second.get(); } - ARMExSectionTuple* getByExSection(llvm::StringRef pName) const { - assert((pName.startswith(".ARM.exidx") || - pName.startswith(".ARM.extab")) && - "Not a .ARM.exidx section name"); - return get(pName.data() + sizeof(".ARM.ex***") - 1); - } - - ARMExSectionTuple* getByRelExSection(llvm::StringRef pName) const { - assert((pName.startswith(".rel.ARM.exidx") || - pName.startswith(".rel.ARM.extab")) && - "Not a .rel.ARM.exidx section name"); - return get(pName.data() + sizeof(".rel.ARM.ex***") - 1); - } - /// getOrCreate - Get an existing or create a new ARMExSectionTuple which is - /// associated with the text section name. As an exception, use "" as the - /// section name for .text section. - ARMExSectionTuple* getOrCreate(const char* pName) { - std::unique_ptr<ARMExSectionTuple>& result = m_NameToExData[pName]; + /// associated with the address of the .ARM.exidx section. + ARMExSectionTuple* getOrCreateByExSection(LDSection &pSect) { + assert(pSect.type() == llvm::ELF::SHT_ARM_EXIDX); + std::unique_ptr<ARMExSectionTuple>& result = m_SectToExData[&pSect]; if (!result) { result.reset(new ARMExSectionTuple()); } return result.get(); } - ARMExSectionTuple* getOrCreateByExSection(llvm::StringRef pName) { - assert((pName.startswith(".ARM.exidx") || - pName.startswith(".ARM.extab")) && - "Not a .ARM.exidx section name"); - return getOrCreate(pName.data() + sizeof(".ARM.ex***") - 1); - } - - ARMExSectionTuple* getOrCreateByRelExSection(llvm::StringRef pName) { - assert((pName.startswith(".rel.ARM.exidx") || - pName.startswith(".rel.ARM.extab")) && - "Not a .rel.ARM.exidx section name"); - return getOrCreate(pName.data() + sizeof(".rel.ARM.ex***") - 1); - } - /// begin - return the iterator to the begin of the map - iterator begin() { return m_NameToExData.begin(); } - const_iterator begin() const { return m_NameToExData.begin(); } + iterator begin() { return m_SectToExData.begin(); } + const_iterator begin() const { return m_SectToExData.begin(); } /// end - return the iterator to the end of the map - iterator end() { return m_NameToExData.end(); } - const_iterator end() const { return m_NameToExData.end(); } + iterator end() { return m_SectToExData.end(); } + const_iterator end() const { return m_SectToExData.end(); } /// erase - remove an entry from the map - void erase(iterator it) { m_NameToExData.erase(it); } + void erase(iterator it) { m_SectToExData.erase(it); } + + private: + ARMInputExMap() = default; private: - NameMap m_NameToExData; + SectMap m_SectToExData; }; -/// ARMExData - ARM exception handling data of a module +/// ARMExData - ARM exception handling data of a mcld::Module. class ARMExData { private: typedef std::map<Input*, std::unique_ptr<ARMInputExMap> > InputMap; @@ -230,11 +141,12 @@ class ARMExData { typedef std::map<const Fragment*, ARMExSectionTuple*> ExIdxMap; public: - ARMExData() { } + // create - Build the exception handling section mapping of a mcld::Module. + static std::unique_ptr<ARMExData> create(Module &module); // addInputMap - register the ARMInputExMap with associated pInput void addInputMap(Input* pInput, - std::unique_ptr<ARMInputExMap>&& pExMap); + std::unique_ptr<ARMInputExMap> pExMap); // getInputMap - get the ARMInputExMap corresponding to pInput ARMInputExMap* getInputMap(Input* pInput) const { @@ -255,6 +167,9 @@ class ARMExData { } private: + ARMExData() = default; + + private: // Map from Input to ARMInputExMap InputMap m_Inputs; diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp index 0907cac..b2fbfb2 100644 --- a/lib/Target/ARM/ARMLDBackend.cpp +++ b/lib/Target/ARM/ARMLDBackend.cpp @@ -10,6 +10,7 @@ #include "ARMGNUInfo.h" #include "ARMELFAttributeData.h" #include "ARMELFDynamic.h" +#include "ARMException.h" #include "ARMLDBackend.h" #include "ARMRelocator.h" #include "ARMToARMStub.h" @@ -19,16 +20,17 @@ #include "mcld/IRBuilder.h" #include "mcld/LinkerConfig.h" +#include "mcld/ADT/ilist_sort.h" #include "mcld/Fragment/AlignFragment.h" #include "mcld/Fragment/FillFragment.h" #include "mcld/Fragment/NullFragment.h" #include "mcld/Fragment/RegionFragment.h" #include "mcld/Fragment/Stub.h" #include "mcld/LD/BranchIslandFactory.h" -#include "mcld/LD/LDContext.h" #include "mcld/LD/ELFFileFormat.h" -#include "mcld/LD/ELFSegmentFactory.h" #include "mcld/LD/ELFSegment.h" +#include "mcld/LD/ELFSegmentFactory.h" +#include "mcld/LD/LDContext.h" #include "mcld/LD/StubFactory.h" #include "mcld/Object/ObjectBuilder.h" #include "mcld/Support/MemoryArea.h" @@ -45,9 +47,75 @@ #include <llvm/Support/ELF.h> #include <cstring> +#include <vector> namespace mcld { +/// Fragment data for EXIDX_CANTUNWIND. +static const char g_CantUnwindEntry[8] = { + // Relocation to text section. + 0, 0, 0, 0, + // EXIDX_CANTUNWIND (little endian.) + 1, 0, 0, 0, +}; + +/// Helper function to create a local symbol at the end of the fragment. +static mcld::ResolveInfo* +CreateLocalSymbolToFragmentEnd(mcld::Module& pModule, mcld::Fragment& pFrag) { + // Create and add symbol to the name pool. + mcld::ResolveInfo* resolveInfo = + pModule.getNamePool().createSymbol(/* pName */"", + /* pIsDyn */false, + mcld::ResolveInfo::Section, + mcld::ResolveInfo::Define, + mcld::ResolveInfo::Local, + /* pSize */0, + mcld::ResolveInfo::Hidden); + if (resolveInfo == nullptr) { + return nullptr; + } + + // Create input symbol. + mcld::LDSymbol* inputSym = mcld::LDSymbol::Create(*resolveInfo); + if (inputSym == nullptr) { + return nullptr; + } + + inputSym->setFragmentRef(mcld::FragmentRef::Create(pFrag, pFrag.size())); + inputSym->setValue(/* pValue */0); + + // The output symbol is simply an alias to the input symbol. + resolveInfo->setSymPtr(inputSym); + + return resolveInfo; +} + +/// Comparator to sort .ARM.exidx fragments according to the address of the +/// corresponding .text fragment. +class ExIdxFragmentComparator { + private: + const ARMExData& m_pExData; + + public: + explicit ExIdxFragmentComparator(const ARMExData& pExData) + : m_pExData(pExData) { + } + + bool operator()(const Fragment& a, const Fragment& b) { + ARMExSectionTuple* tupleA = m_pExData.getTupleByExIdx(&a); + ARMExSectionTuple* tupleB = m_pExData.getTupleByExIdx(&b); + + Fragment* textFragA = tupleA->getTextFragment(); + Fragment* textFragB = tupleB->getTextFragment(); + + uint64_t addrA = textFragA->getParent()->getSection().addr() + + textFragA->getOffset(); + uint64_t addrB = textFragB->getParent()->getSection().addr() + + textFragB->getOffset(); + return (addrA < addrB); + } +}; + //===----------------------------------------------------------------------===// // ARMGNULDBackend //===----------------------------------------------------------------------===// @@ -398,7 +466,10 @@ bool ARMGNULDBackend::finalizeTargetSymbols() { /// preMergeSections - hooks to be executed before merging sections void ARMGNULDBackend::preMergeSections(Module& pModule) { - scanInputExceptionSections(pModule); + // Since the link relationship between .text and .ARM.exidx will be discarded + // after merging sections, we have to build the exception handling section + // mapping before section merge. + m_pExData = ARMExData::create(pModule); } /// postMergeSections - hooks to be executed after merging sections @@ -634,6 +705,104 @@ unsigned int ARMGNULDBackend::getTargetSectionOrder( return SHO_UNDEFINED; } +void ARMGNULDBackend::rewriteARMExIdxSection(Module& pModule) { + if (!m_pEXIDX->hasSectionData()) { + // Return if this is empty section. + return; + } + + SectionData* sectData = m_pEXIDX->getSectionData(); + SectionData::FragmentListType& list = sectData->getFragmentList(); + + // Move the first fragment (align fragment) and last fragment (null fragment) + // to temporary list because we would only like to sort the region fragment. + SectionData::FragmentListType tmp; + { + SectionData::iterator first = sectData->begin(); + SectionData::iterator last = sectData->end(); + --last; + + assert(first->getKind() == Fragment::Alignment); + assert(last->getKind() == Fragment::Null); + + tmp.splice(tmp.end(), list, first); + tmp.splice(tmp.end(), list, last); + } + + // Sort the region fragments in the .ARM.exidx output section. + sort(list, ExIdxFragmentComparator(*m_pExData)); + + // Fix the coverage of the .ARM.exidx table. + llvm::StringRef cantUnwindRegion(g_CantUnwindEntry, + sizeof(g_CantUnwindEntry)); + + SectionData::FragmentListType::iterator it = list.begin(); + if (it != list.end()) { + Fragment* prevTextFrag = m_pExData->getTupleByExIdx(&*it)->getTextFragment(); + uint64_t prevTextEnd = prevTextFrag->getParent()->getSection().addr() + + prevTextFrag->getOffset() + + prevTextFrag->size(); + ++it; + while (it != list.end()) { + Fragment* currTextFrag = + m_pExData->getTupleByExIdx(&*it)->getTextFragment(); + uint64_t currTextBegin = currTextFrag->getParent()->getSection().addr() + + currTextFrag->getOffset(); + + if (currTextBegin > prevTextEnd) { + // Found a gap. Insert a can't unwind entry. + RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); + frag->setParent(sectData); + list.insert(it, frag); + + // Add PREL31 reference to the beginning of the uncovered region. + Relocation* reloc = + Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), + *FragmentRef::Create(*frag, /* pOffset */0), + /* pAddend */0); + reloc->setSymInfo( + CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); + addExtraRelocation(reloc); + } + + prevTextEnd = currTextBegin + currTextFrag->size(); + prevTextFrag = currTextFrag; + ++it; + } + + // Add a can't unwind entry to terminate .ARM.exidx section. + RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); + frag->setParent(sectData); + list.push_back(frag); + + // Add PREL31 reference to the end of the .text section. + Relocation* reloc = + Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), + *FragmentRef::Create(*frag, /* pOffset */0), + /* pAddend */0); + reloc->setSymInfo(CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); + addExtraRelocation(reloc); + } + + // Add the first and the last fragment back. + list.splice(list.begin(), tmp, tmp.begin()); + list.splice(list.end(), tmp, tmp.begin()); + + // Update the fragment offsets. + uint64_t offset = 0; + for (SectionData::iterator it = sectData->begin(), end = sectData->end(); + it != end; ++it) { + it->setOffset(offset); + offset += it->size(); + } + + // Update the section size. + m_pEXIDX->setSize(offset); + + // Rebuild the section header. + setOutputSectionAddress(pModule); +} + /// relax - the relaxation pass bool ARMGNULDBackend::relax(Module& pModule, IRBuilder& pBuilder) { if (!GNULDBackend::relax(pModule, pBuilder)) { @@ -692,6 +861,10 @@ bool ARMGNULDBackend::doRelax(Module& pModule, pBuilder, *getBRIslandFactory()); if (stub != NULL) { + assert(stub->symInfo() != NULL); + // reset the branch target of the reloc to this stub instead + relocation->setSymInfo(stub->symInfo()); + switch (config().options().getStripSymbolMode()) { case GeneralOptions::StripSymbolMode::StripAllSymbols: case GeneralOptions::StripSymbolMode::StripLocals: @@ -703,12 +876,7 @@ bool ARMGNULDBackend::doRelax(Module& pModule, LDSection& strtab = file_format->getStrTab(); // increase the size of .symtab and .strtab if needed - if (config().targets().is32Bits()) - symtab.setSize(symtab.size() + - sizeof(llvm::ELF::Elf32_Sym)); - else - symtab.setSize(symtab.size() + - sizeof(llvm::ELF::Elf64_Sym)); + symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym)); symtab.setInfo(symtab.getInfo() + 1); strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1); @@ -729,35 +897,62 @@ bool ARMGNULDBackend::doRelax(Module& pModule, } // for all inputs // find the first fragment w/ invalid offset due to stub insertion - Fragment* invalid = NULL; + std::vector<Fragment*> invalid_frags; pFinished = true; for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), island_end = getBRIslandFactory()->end(); island != island_end; ++island) { - if ((*island).end() == file_format->getText().getSectionData()->end()) - break; + if ((*island).size() > stubGroupSize()) { + error(diag::err_no_space_to_place_stubs) << stubGroupSize(); + return false; + } + + if ((*island).numOfStubs() == 0) { + continue; + } + + Fragment* exit = &*(*island).end(); + if (exit == (*island).begin()->getParent()->end()) { + continue; + } - Fragment* exit = (*island).end(); if (((*island).offset() + (*island).size()) > exit->getOffset()) { - invalid = exit; - pFinished = false; - break; + if (invalid_frags.empty() || + (invalid_frags.back()->getParent() != (*island).getParent())) { + invalid_frags.push_back(exit); + pFinished = false; + } + continue; } } // reset the offset of invalid fragments - while (invalid != NULL) { - invalid->setOffset(invalid->getPrevNode()->getOffset() + - invalid->getPrevNode()->size()); - invalid = invalid->getNextNode(); + for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie; + ++it) { + Fragment* invalid = *it; + while (invalid != NULL) { + invalid->setOffset(invalid->getPrevNode()->getOffset() + + invalid->getPrevNode()->size()); + invalid = invalid->getNextNode(); + } } - // reset the size of .text + // reset the size of section that has stubs inserted. if (isRelaxed) { - file_format->getText().setSize( - file_format->getText().getSectionData()->back().getOffset() + - file_format->getText().getSectionData()->back().size()); + SectionData* prev = NULL; + for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), + island_end = getBRIslandFactory()->end(); + island != island_end; + ++island) { + SectionData* sd = (*island).begin()->getParent(); + if ((*island).numOfStubs() != 0) { + if (sd != prev) { + sd->getSection().setSize(sd->back().getOffset() + sd->back().size()); + } + } + prev = sd; + } } return isRelaxed; } @@ -777,7 +972,7 @@ bool ARMGNULDBackend::initTargetStubs() { } /// maxFwdBranchOffset -int64_t ARMGNULDBackend::maxFwdBranchOffset() { +int64_t ARMGNULDBackend::maxFwdBranchOffset() const { if (m_pAttrData->usingThumb2()) { return THM2_MAX_FWD_BRANCH_OFFSET; } else { @@ -786,7 +981,7 @@ int64_t ARMGNULDBackend::maxFwdBranchOffset() { } /// maxBwdBranchOffset -int64_t ARMGNULDBackend::maxBwdBranchOffset() { +int64_t ARMGNULDBackend::maxBwdBranchOffset() const { if (m_pAttrData->usingThumb2()) { return THM2_MAX_BWD_BRANCH_OFFSET; } else { diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h index d2eae7c..53f4e9f 100644 --- a/lib/Target/ARM/ARMLDBackend.h +++ b/lib/Target/ARM/ARMLDBackend.h @@ -17,6 +17,8 @@ #include "mcld/Target/GNULDBackend.h" #include "mcld/Target/OutputRelocSection.h" +#include <memory> + namespace mcld { class ARMELFAttributeData; @@ -139,9 +141,9 @@ class ARMGNULDBackend : public GNULDBackend { void defineGOTSymbol(IRBuilder& pBuilder); /// maxFwdBranchOffset - int64_t maxFwdBranchOffset(); + int64_t maxFwdBranchOffset() const; /// maxBwdBranchOffset - int64_t maxBwdBranchOffset(); + int64_t maxBwdBranchOffset() const; /// mayRelax - Backends should override this function if they need relaxation bool mayRelax() { return true; } @@ -171,14 +173,6 @@ class ARMGNULDBackend : public GNULDBackend { /// target-dependent segments virtual void doCreateProgramHdrs(Module& pModule); - /// scanInputExceptionSections - scan exception-related input sections in - /// the Module, build the ARMExData, and reclaim GC'ed sections - void scanInputExceptionSections(Module& pModule); - - /// scanInputExceptionSections - scan exception-related input sections in - /// the Input, build the ARMInputExMap, and reclaim GC'ed sections - void scanInputExceptionSections(Module& pModule, Input& pInput); - /// rewriteExceptionSection - rewrite the output .ARM.exidx section. void rewriteARMExIdxSection(Module& pModule); @@ -208,9 +202,10 @@ class ARMGNULDBackend : public GNULDBackend { // LDSection* m_pDebugOverlay; // .ARM.debug_overlay // LDSection* m_pOverlayTable; // .ARM.overlay_table - // m_ExData - exception handling section data structures - ARMExData m_ExData; + // m_pExData - exception handling section data structures + std::unique_ptr<ARMExData> m_pExData; }; + } // namespace mcld #endif // TARGET_ARM_ARMLDBACKEND_H_ diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp index fd845cf..0e0a5ce 100644 --- a/lib/Target/ARM/ARMRelocator.cpp +++ b/lib/Target/ARM/ARMRelocator.cpp @@ -946,7 +946,8 @@ ARMRelocator::Result thm_jump19(Relocation& pReloc, ARMRelocator& pParent) { Relocator::DWord T = getThumbBit(pReloc); Relocator::DWord A = - helper_thumb32_cond_branch_offset(upper_inst, lower_inst); + helper_thumb32_cond_branch_offset(upper_inst, lower_inst) + + pReloc.addend(); Relocator::Address P = pReloc.place(); Relocator::Address S; // if symbol has plt @@ -1052,7 +1053,8 @@ ARMRelocator::Result thm_call(Relocation& pReloc, ARMRelocator& pParent) { uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1); Relocator::DWord T = getThumbBit(pReloc); - Relocator::DWord A = helper_thumb32_branch_offset(upper_inst, lower_inst); + Relocator::DWord A = + helper_thumb32_branch_offset(upper_inst, lower_inst) + pReloc.addend(); Relocator::Address P = pReloc.place(); Relocator::Address S; diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index 79fa25f..ac2cc2b 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -59,7 +59,7 @@ namespace { //===----------------------------------------------------------------------===// static const std::string simple_c_identifier_allowed_chars = "0123456789" - "ABCDEFGHIJKLMNOPWRSTUVWXYZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "_"; @@ -2175,7 +2175,13 @@ void GNULDBackend::setOutputSectionAddress(Module& pModule) { // Try to align p_vaddr at page boundary if not in script options. // To do so will add more padding in file, but can save one page // at runtime. - alignAddress(vma, (*seg)->align()); + // Avoid doing this optimization if -z relro is given, because there + // seems to be too many padding. + if (!config().options().hasRelro()) { + alignAddress(vma, (*seg)->align()); + } else { + vma += abiPageSize(); + } } } } else { @@ -2876,11 +2882,21 @@ void GNULDBackend::sortRelocation(LDSection& pSection) { } } +unsigned GNULDBackend::stubGroupSize() const { + const unsigned group_size = config().targets().getStubGroupSize(); + if (group_size == 0) { + return m_pInfo->stubGroupSize(); + } else { + return group_size; + } +} + /// initBRIslandFactory - initialize the branch island factory for relaxation bool GNULDBackend::initBRIslandFactory() { if (m_pBRIslandFactory == NULL) { - m_pBRIslandFactory = - new BranchIslandFactory(maxFwdBranchOffset(), maxBwdBranchOffset()); + m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(), + maxBwdBranchOffset(), + stubGroupSize()); } return true; } diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp index 5d4d4dc..b46de99 100644 --- a/lib/Target/Hexagon/HexagonLDBackend.cpp +++ b/lib/Target/Hexagon/HexagonLDBackend.cpp @@ -34,6 +34,7 @@ #include <llvm/Support/Casting.h> #include <cstring> +#include <vector> namespace mcld { @@ -577,6 +578,9 @@ bool HexagonLDBackend::doRelax(Module& pModule, *getBRIslandFactory()); if (stub != NULL) { assert(stub->symInfo() != NULL); + // reset the branch target of the reloc to this stub instead + relocation->setSymInfo(stub->symInfo()); + // increase the size of .symtab and .strtab LDSection& symtab = file_format->getSymTab(); LDSection& strtab = file_format->getStrTab(); @@ -594,35 +598,62 @@ bool HexagonLDBackend::doRelax(Module& pModule, } // find the first fragment w/ invalid offset due to stub insertion - Fragment* invalid = NULL; + std::vector<Fragment*> invalid_frags; pFinished = true; for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), island_end = getBRIslandFactory()->end(); island != island_end; ++island) { - if ((*island).end() == file_format->getText().getSectionData()->end()) - break; + if ((*island).size() > stubGroupSize()) { + error(diag::err_no_space_to_place_stubs) << stubGroupSize(); + return false; + } + + if ((*island).numOfStubs() == 0) { + continue; + } + + Fragment* exit = &*(*island).end(); + if (exit == (*island).begin()->getParent()->end()) { + continue; + } - Fragment* exit = (*island).end(); if (((*island).offset() + (*island).size()) > exit->getOffset()) { - invalid = exit; - pFinished = false; - break; + if (invalid_frags.empty() || + (invalid_frags.back()->getParent() != (*island).getParent())) { + invalid_frags.push_back(exit); + pFinished = false; + } + continue; } } // reset the offset of invalid fragments - while (invalid != NULL) { - invalid->setOffset(invalid->getPrevNode()->getOffset() + - invalid->getPrevNode()->size()); - invalid = invalid->getNextNode(); + for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie; + ++it) { + Fragment* invalid = *it; + while (invalid != NULL) { + invalid->setOffset(invalid->getPrevNode()->getOffset() + + invalid->getPrevNode()->size()); + invalid = invalid->getNextNode(); + } } - // reset the size of .text + // reset the size of section that has stubs inserted. if (isRelaxed) { - file_format->getText().setSize( - file_format->getText().getSectionData()->back().getOffset() + - file_format->getText().getSectionData()->back().size()); + SectionData* prev = NULL; + for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), + island_end = getBRIslandFactory()->end(); + island != island_end; + ++island) { + SectionData* sd = (*island).begin()->getParent(); + if ((*island).numOfStubs() != 0) { + if (sd != prev) { + sd->getSection().setSize(sd->back().getOffset() + sd->back().size()); + } + } + prev = sd; + } } return isRelaxed; } @@ -720,7 +751,7 @@ bool HexagonLDBackend::allocateCommonSymbols(Module& pModule) { return true; } - int8_t maxGPSize = config().options().getGPSize(); + int8_t maxGPSize = config().targets().getGPSize(); SymbolCategory::iterator com_sym, com_end; diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h index 89aea83..8e32062 100644 --- a/lib/Target/Hexagon/HexagonLDBackend.h +++ b/lib/Target/Hexagon/HexagonLDBackend.h @@ -157,7 +157,7 @@ class HexagonLDBackend : public GNULDBackend { void doCreateProgramHdrs(Module& pModule); /// maxFwdBranchOffset - int64_t maxFwdBranchOffset() { return ~(~0 << 6); } + int64_t maxFwdBranchOffset() const { return ~(~0U << 6); } virtual void setGOTSectionSize(IRBuilder& pBuilder); diff --git a/lib/Target/Hexagon/HexagonPLT.cpp b/lib/Target/Hexagon/HexagonPLT.cpp index ca9352a..dcd5c94 100644 --- a/lib/Target/Hexagon/HexagonPLT.cpp +++ b/lib/Target/Hexagon/HexagonPLT.cpp @@ -35,10 +35,10 @@ HexagonPLT1::HexagonPLT1(SectionData& pParent) HexagonPLT::HexagonPLT(LDSection& pSection, HexagonGOTPLT& pGOTPLT, const LinkerConfig& pConfig) - : PLT(pSection), m_GOTPLT(pGOTPLT), m_Config(pConfig) { - assert(LinkerConfig::DynObj == m_Config.codeGenType() || - LinkerConfig::Exec == m_Config.codeGenType() || - LinkerConfig::Binary == m_Config.codeGenType()); + : PLT(pSection), m_GOTPLT(pGOTPLT) { + assert(LinkerConfig::DynObj == pConfig.codeGenType() || + LinkerConfig::Exec == pConfig.codeGenType() || + LinkerConfig::Binary == pConfig.codeGenType()); m_PLT0 = hexagon_plt0; m_PLT0Size = sizeof(hexagon_plt0); diff --git a/lib/Target/Hexagon/HexagonPLT.h b/lib/Target/Hexagon/HexagonPLT.h index 22f580e..01f16b1 100644 --- a/lib/Target/Hexagon/HexagonPLT.h +++ b/lib/Target/Hexagon/HexagonPLT.h @@ -85,8 +85,6 @@ class HexagonPLT : public PLT { const uint8_t* m_PLT0; unsigned int m_PLT0Size; - - const LinkerConfig& m_Config; }; class HexagonPLT1 : public PLT::Entry<sizeof(hexagon_plt1)> { diff --git a/lib/Target/Mips/Android.mk b/lib/Target/Mips/Android.mk index 0bb2d40..17e93f5 100644 --- a/lib/Target/Mips/Android.mk +++ b/lib/Target/Mips/Android.mk @@ -1,6 +1,7 @@ LOCAL_PATH:= $(call my-dir) mcld_mips_target_SRC_FILES := \ + MipsAbiFlags.cpp \ MipsDiagnostic.cpp \ MipsELFDynamic.cpp \ MipsEmulation.cpp \ diff --git a/lib/Target/Mips/MipsAbiFlags.cpp b/lib/Target/Mips/MipsAbiFlags.cpp new file mode 100644 index 0000000..ff17284 --- /dev/null +++ b/lib/Target/Mips/MipsAbiFlags.cpp @@ -0,0 +1,298 @@ +//===- MipsAbiFlags.cpp ---------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "MipsAbiFlags.h" + +#include "mcld/Fragment/RegionFragment.h" +#include "mcld/LD/LDSection.h" +#include "mcld/LD/SectionData.h" +#include "mcld/MC/Input.h" +#include "mcld/Support/MsgHandling.h" + +#include <llvm/Support/Casting.h> +#include <llvm/Support/MipsABIFlags.h> + +namespace mcld { + +// SHT_MIPS_ABIFLAGS has the same format for both 32/64-bit targets. +// We do not support linking of big-endian code now so 32-bit LE +// combination is Okay. +typedef llvm::object::ELFType<llvm::support::little, false> ELF32LE; +typedef llvm::object::Elf_Mips_ABIFlags<ELF32LE> ElfMipsAbiFlags; + +uint64_t MipsAbiFlags::size() { + return sizeof(ElfMipsAbiFlags); +} + +uint64_t MipsAbiFlags::emit(const MipsAbiFlags& pInfo, MemoryRegion& pRegion) { + auto* buf = reinterpret_cast<ElfMipsAbiFlags*>(pRegion.begin()); + buf->version = 0; + buf->isa_level = pInfo.m_IsaLevel; + buf->isa_rev = pInfo.m_IsaRev; + buf->gpr_size = pInfo.m_GprSize; + buf->cpr1_size = pInfo.m_Cpr1Size; + buf->cpr2_size = pInfo.m_Cpr2Size; + buf->fp_abi = pInfo.m_FpAbi; + buf->isa_ext = pInfo.m_IsaExt; + buf->ases = pInfo.m_Ases; + buf->flags1 = pInfo.m_Flags1; + buf->flags2 = 0; + return size(); +} + +bool MipsAbiFlags::fillBySection(const Input& pInput, const LDSection& pSection, + MipsAbiFlags& mipsAbi) { + assert(pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS && + "Unexpected section type"); + + if (pSection.size() != size()) { + error(diag::error_Mips_abiflags_invalid_size) << pInput.name(); + return false; + } + + const SectionData* secData = pSection.getSectionData(); + if (secData->size() != 2 || !llvm::isa<RegionFragment>(secData->front())) { + error(diag::error_Mips_abiflags_invalid_size) << pInput.name(); + return false; + } + + const auto& frag = llvm::cast<RegionFragment>(secData->front()); + auto* data = + reinterpret_cast<const ElfMipsAbiFlags*>(frag.getRegion().data()); + if (data->version != 0) { + error(diag::error_Mips_abiflags_invalid_version) << int(data->version) + << pInput.name(); + return false; + } + + mipsAbi.m_IsaLevel = data->isa_level; + mipsAbi.m_IsaRev = data->isa_rev; + mipsAbi.m_GprSize = data->gpr_size; + mipsAbi.m_Cpr1Size = data->cpr1_size; + mipsAbi.m_Cpr2Size = data->cpr2_size; + mipsAbi.m_FpAbi = data->fp_abi; + mipsAbi.m_IsaExt = data->isa_ext; + mipsAbi.m_Ases = data->ases; + mipsAbi.m_Flags1 = data->flags1; + return true; +} + +static unsigned getIsaLevel(uint64_t flags) { + switch (flags & llvm::ELF::EF_MIPS_ARCH) { + case llvm::ELF::EF_MIPS_ARCH_1: + return 1; + case llvm::ELF::EF_MIPS_ARCH_2: + return 2; + case llvm::ELF::EF_MIPS_ARCH_3: + return 3; + case llvm::ELF::EF_MIPS_ARCH_4: + return 4; + case llvm::ELF::EF_MIPS_ARCH_5: + return 5; + case llvm::ELF::EF_MIPS_ARCH_32: + case llvm::ELF::EF_MIPS_ARCH_32R2: + case llvm::ELF::EF_MIPS_ARCH_32R6: + return 32; + case llvm::ELF::EF_MIPS_ARCH_64: + case llvm::ELF::EF_MIPS_ARCH_64R2: + case llvm::ELF::EF_MIPS_ARCH_64R6: + return 64; + default: + // We check ELF flags and show error in case + // of unknown value in other place. + llvm_unreachable("Unknown MIPS architecture flag"); + } +} + +static unsigned getIsaRev(uint64_t flags) { + switch (flags & llvm::ELF::EF_MIPS_ARCH) { + case llvm::ELF::EF_MIPS_ARCH_1: + case llvm::ELF::EF_MIPS_ARCH_2: + case llvm::ELF::EF_MIPS_ARCH_3: + case llvm::ELF::EF_MIPS_ARCH_4: + case llvm::ELF::EF_MIPS_ARCH_5: + return 0; + case llvm::ELF::EF_MIPS_ARCH_32: + case llvm::ELF::EF_MIPS_ARCH_64: + return 1; + case llvm::ELF::EF_MIPS_ARCH_32R2: + case llvm::ELF::EF_MIPS_ARCH_64R2: + return 2; + case llvm::ELF::EF_MIPS_ARCH_32R6: + case llvm::ELF::EF_MIPS_ARCH_64R6: + return 6; + default: + // We check ELF flags and show error in case + // of unknown value in other place. + llvm_unreachable("Unknown MIPS architecture flag"); + } +} + +static unsigned getIsaExt(uint64_t flags) { + switch (flags & llvm::ELF::EF_MIPS_MACH) { + case 0: + return llvm::Mips::AFL_EXT_NONE; + case llvm::ELF::EF_MIPS_MACH_3900: return llvm::Mips::AFL_EXT_3900; + case llvm::ELF::EF_MIPS_MACH_4010: return llvm::Mips::AFL_EXT_4010; + case llvm::ELF::EF_MIPS_MACH_4100: return llvm::Mips::AFL_EXT_4010; + case llvm::ELF::EF_MIPS_MACH_4111: return llvm::Mips::AFL_EXT_4111; + case llvm::ELF::EF_MIPS_MACH_4120: return llvm::Mips::AFL_EXT_4120; + case llvm::ELF::EF_MIPS_MACH_4650: return llvm::Mips::AFL_EXT_4650; + case llvm::ELF::EF_MIPS_MACH_5400: return llvm::Mips::AFL_EXT_5400; + case llvm::ELF::EF_MIPS_MACH_5500: return llvm::Mips::AFL_EXT_5500; + case llvm::ELF::EF_MIPS_MACH_5900: return llvm::Mips::AFL_EXT_5900; + case llvm::ELF::EF_MIPS_MACH_SB1: return llvm::Mips::AFL_EXT_SB1; + case llvm::ELF::EF_MIPS_MACH_LS2E: return llvm::Mips::AFL_EXT_LOONGSON_2E; + case llvm::ELF::EF_MIPS_MACH_LS2F: return llvm::Mips::AFL_EXT_LOONGSON_2F; + case llvm::ELF::EF_MIPS_MACH_LS3A: return llvm::Mips::AFL_EXT_LOONGSON_3A; + case llvm::ELF::EF_MIPS_MACH_OCTEON3: return llvm::Mips::AFL_EXT_OCTEON3; + case llvm::ELF::EF_MIPS_MACH_OCTEON2: return llvm::Mips::AFL_EXT_OCTEON2; + case llvm::ELF::EF_MIPS_MACH_OCTEON: return llvm::Mips::AFL_EXT_OCTEON; + case llvm::ELF::EF_MIPS_MACH_XLR: return llvm::Mips::AFL_EXT_XLR; + default: + // We check ELF flags and show error in case + // of unknown value in other place. + llvm_unreachable("Unknown MIPS extension flag"); + } +} + +static bool is32BitElfFlags(uint64_t flags) { + if (flags & llvm::ELF::EF_MIPS_32BITMODE) + return true; + + uint64_t arch = flags & llvm::ELF::EF_MIPS_ARCH; + if (arch == llvm::ELF::EF_MIPS_ARCH_1 || + arch == llvm::ELF::EF_MIPS_ARCH_2 || + arch == llvm::ELF::EF_MIPS_ARCH_32 || + arch == llvm::ELF::EF_MIPS_ARCH_32R2 || + arch == llvm::ELF::EF_MIPS_ARCH_32R6) + return true; + + uint64_t abi = flags & llvm::ELF::EF_MIPS_ABI; + if (abi == llvm::ELF::EF_MIPS_ABI_O32 || abi == llvm::ELF::EF_MIPS_ABI_EABI32) + return true; + + return false; +} + +bool MipsAbiFlags::fillByElfFlags(const Input& pInput, uint64_t elfFlags, + MipsAbiFlags& mipsAbi) { + mipsAbi.m_IsaLevel = getIsaLevel(elfFlags); + mipsAbi.m_IsaRev = getIsaRev(elfFlags); + mipsAbi.m_IsaExt = getIsaExt(elfFlags); + + mipsAbi.m_GprSize = is32BitElfFlags(elfFlags) ? + llvm::Mips::AFL_REG_32 : llvm::Mips::AFL_REG_64; + + mipsAbi.m_Cpr1Size = llvm::Mips::AFL_REG_NONE; + mipsAbi.m_Cpr2Size = llvm::Mips::AFL_REG_NONE; + mipsAbi.m_FpAbi = llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY; + + mipsAbi.m_Ases = 0; + if (elfFlags & llvm::ELF::EF_MIPS_MICROMIPS) + mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MICROMIPS; + if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16) + mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MIPS16; + if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_MDMX) + mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MDMX; + + mipsAbi.m_Flags1 = 0; + return true; +} + +bool MipsAbiFlags::isCompatible(const Input& pInput, const MipsAbiFlags& elf, + const MipsAbiFlags& abi) { + unsigned isaRev = abi.m_IsaRev; + if (isaRev == 3 || isaRev == 5) + isaRev = 2; + if (abi.m_IsaLevel != elf.m_IsaLevel || isaRev != elf.m_IsaRev) { + warning(diag::warn_Mips_isa_incompatible) << pInput.name(); + return false; + } + if (abi.m_IsaExt != elf.m_IsaExt) { + warning(diag::warn_Mips_isa_ext_incompatible) << pInput.name(); + return false; + } + if ((abi.m_Ases & elf.m_Ases) != elf.m_Ases) { + warning(diag::warn_Mips_ases_incompatible) << pInput.name(); + return false; + } + return true; +} + +static bool isFpGreater(uint64_t fpA, uint64_t fpB) { + if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY) + return true; + if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A && + fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64) + return true; + if (fpB != llvm::Mips::Val_GNU_MIPS_ABI_FP_XX) + return false; + return fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || + fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64 || + fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A; +} + +static llvm::StringRef getFpAbiName(uint64_t abi) { + switch (abi) { + case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY: + return "<any>"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64: + return "-mips32r2 -mfp64 (old)"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + default: + return "<unknown>"; + } +} + +bool MipsAbiFlags::merge(const Input& pInput, MipsAbiFlags& oldFlags, + const MipsAbiFlags& newFlags) { + if (oldFlags.m_IsaLevel == 0) { + oldFlags = newFlags; + return true; + } + + if (newFlags.m_IsaLevel > oldFlags.m_IsaLevel) + oldFlags.m_IsaLevel = newFlags.m_IsaLevel; + + oldFlags.m_IsaRev = std::max(oldFlags.m_IsaRev, newFlags.m_IsaRev); + oldFlags.m_GprSize = std::max(oldFlags.m_GprSize, newFlags.m_GprSize); + oldFlags.m_Cpr1Size = std::max(oldFlags.m_Cpr1Size, newFlags.m_Cpr1Size); + oldFlags.m_Cpr2Size = std::max(oldFlags.m_Cpr2Size, newFlags.m_Cpr2Size); + oldFlags.m_Ases |= newFlags.m_Ases; + oldFlags.m_Flags1 |= newFlags.m_Flags1; + + if (oldFlags.m_FpAbi == newFlags.m_FpAbi) + return true; + + if (isFpGreater(newFlags.m_FpAbi, oldFlags.m_FpAbi)) { + oldFlags.m_FpAbi = newFlags.m_FpAbi; + return true; + } + + if (isFpGreater(oldFlags.m_FpAbi, newFlags.m_FpAbi)) + return true; + + llvm::StringRef oldAbiName = getFpAbiName(oldFlags.m_FpAbi); + llvm::StringRef newAbiName = getFpAbiName(newFlags.m_FpAbi); + warning(diag::warn_Mips_fp_abi_incompatible) << oldAbiName << newAbiName + << pInput.name(); + return false; +} +} // namespace mcld diff --git a/lib/Target/Mips/MipsAbiFlags.h b/lib/Target/Mips/MipsAbiFlags.h new file mode 100644 index 0000000..4a55b4d --- /dev/null +++ b/lib/Target/Mips/MipsAbiFlags.h @@ -0,0 +1,63 @@ +//===- MipsAbiFlags.h -----------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef TARGET_MIPS_MIPSABIFLAGS_H_ +#define TARGET_MIPS_MIPSABIFLAGS_H_ + +#include "mcld/Support/MemoryRegion.h" + +#include <llvm/ADT/Optional.h> +#include <llvm/Object/ELFTypes.h> + +namespace mcld { + +class Input; +class LDSection; + +/** \class MipsAbiFlags + * \brief Representation of .MIPS.abiflags section. + */ +class MipsAbiFlags { + public: + /// size of underlaid ELF section structure + static uint64_t size(); + + /// write ELF section structure to the memory region + static uint64_t emit(const MipsAbiFlags& pInfo, MemoryRegion& pRegion); + + /// fill the structure by the data from the input section + static bool fillBySection(const Input& pInput, const LDSection& pSection, + MipsAbiFlags& mipsAbi); + + /// fill the structure by the data from ELF header flags + static bool fillByElfFlags(const Input& pInput, uint64_t elfFlags, + MipsAbiFlags& mipsAbi); + + /// check compatibility between two structures + static bool isCompatible(const Input& pInput, const MipsAbiFlags& elf, + const MipsAbiFlags& abi); + + /// merge new abi settings to the old structure + static bool merge(const Input& pInput, MipsAbiFlags& oldFlags, + const MipsAbiFlags& newFlags); + + private: + uint32_t m_IsaLevel; + uint32_t m_IsaRev; + uint32_t m_IsaExt; + uint32_t m_GprSize; + uint32_t m_Cpr1Size; + uint32_t m_Cpr2Size; + uint32_t m_FpAbi; + uint32_t m_Ases; + uint32_t m_Flags1; +}; + +} // namespace mcld + +#endif // TARGET_MIPS_MIPSABIFLAGS_H_ diff --git a/lib/Target/Mips/MipsGNUInfo.cpp b/lib/Target/Mips/MipsGNUInfo.cpp index 132e9c3..9a1804f 100644 --- a/lib/Target/Mips/MipsGNUInfo.cpp +++ b/lib/Target/Mips/MipsGNUInfo.cpp @@ -14,15 +14,15 @@ namespace mcld { // MipsGNUInfo //===----------------------------------------------------------------------===// MipsGNUInfo::MipsGNUInfo(const llvm::Triple& pTriple) - : GNUInfo(pTriple), m_ABIVersion(0), m_PICFlags(0) { + : GNUInfo(pTriple), m_ABIVersion(0), m_ElfFlags(0) { } void MipsGNUInfo::setABIVersion(uint8_t ver) { m_ABIVersion = ver; } -void MipsGNUInfo::setPICFlags(uint64_t flags) { - m_PICFlags = flags; +void MipsGNUInfo::setElfFlags(uint64_t flags) { + m_ElfFlags = flags; } uint32_t MipsGNUInfo::machine() const { @@ -41,14 +41,7 @@ uint64_t MipsGNUInfo::defaultTextSegmentAddr() const { } uint64_t MipsGNUInfo::flags() const { - uint64_t val = llvm::ELF::EF_MIPS_NOREORDER | m_PICFlags; - - if (m_Triple.isArch32Bit()) - val |= llvm::ELF::EF_MIPS_ARCH_32R2 | llvm::ELF::EF_MIPS_ABI_O32; - else - val |= llvm::ELF::EF_MIPS_ARCH_64R2; - - return val; + return m_ElfFlags; } const char* MipsGNUInfo::entry() const { diff --git a/lib/Target/Mips/MipsGNUInfo.h b/lib/Target/Mips/MipsGNUInfo.h index 673c39a..9ab907f 100644 --- a/lib/Target/Mips/MipsGNUInfo.h +++ b/lib/Target/Mips/MipsGNUInfo.h @@ -18,7 +18,7 @@ class MipsGNUInfo : public GNUInfo { explicit MipsGNUInfo(const llvm::Triple& pTriple); void setABIVersion(uint8_t ver); - void setPICFlags(uint64_t flags); + void setElfFlags(uint64_t flags); // GNUInfo uint32_t machine() const; @@ -31,7 +31,7 @@ class MipsGNUInfo : public GNUInfo { private: uint8_t m_ABIVersion; - uint64_t m_PICFlags; + uint64_t m_ElfFlags; }; } // namespace mcld diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp index 85d89c7..4234e87 100644 --- a/lib/Target/Mips/MipsGOT.cpp +++ b/lib/Target/Mips/MipsGOT.cpp @@ -33,14 +33,19 @@ namespace mcld { MipsGOT::GOTMultipart::GOTMultipart(size_t local, size_t global) : m_LocalNum(local), m_GlobalNum(global), + m_TLSNum(0), + m_TLSDynNum(0), m_ConsumedLocal(0), m_ConsumedGlobal(0), + m_ConsumedTLS(0), m_pLastLocal(NULL), - m_pLastGlobal(NULL) { + m_pLastGlobal(NULL), + m_pLastTLS(NULL) { } bool MipsGOT::GOTMultipart::isConsumed() const { - return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal; + return m_LocalNum == m_ConsumedLocal && m_GlobalNum == m_ConsumedGlobal && + m_TLSNum == m_ConsumedTLS; } void MipsGOT::GOTMultipart::consumeLocal() { @@ -56,6 +61,13 @@ void MipsGOT::GOTMultipart::consumeGlobal() { m_pLastGlobal = m_pLastGlobal->getNextNode(); } +void MipsGOT::GOTMultipart::consumeTLS(Relocation::Type pType) { + assert(m_ConsumedTLS < m_TLSNum && + "Consumed too many TLS GOT entries"); + m_ConsumedTLS += pType == llvm::ELF::R_MIPS_TLS_GOTTPREL ? 1 : 2; + m_pLastTLS = m_pLastTLS->getNextNode(); +} + //===----------------------------------------------------------------------===// // MipsGOT::LocalEntry //===----------------------------------------------------------------------===// @@ -79,7 +91,11 @@ bool MipsGOT::LocalEntry::operator<(const LocalEntry& O) const { // MipsGOT //===----------------------------------------------------------------------===// MipsGOT::MipsGOT(LDSection& pSection) - : GOT(pSection), m_pInput(NULL), m_CurrentGOTPart(0) { + : GOT(pSection), + m_pInput(NULL), + m_HasTLSLdmSymbol(false), + m_CurrentGOTPart(0), + m_GotTLSLdmEntry(nullptr) { } uint64_t MipsGOT::getGPDispAddress() const { @@ -108,6 +124,8 @@ void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) { reserve(it->m_LocalNum); it->m_pLastGlobal = &m_SectionData->back(); reserve(it->m_GlobalNum); + it->m_pLastTLS = &m_SectionData->back(); + reserve(it->m_TLSNum); if (it == m_MultipartList.begin()) { // Reserve entries in the second part of the primary GOT. @@ -122,6 +140,9 @@ void MipsGOT::finalizeScanning(OutputRelocSection& pRelDyn) { for (size_t i = 0; i < count; ++i) pRelDyn.reserveEntry(); } + + for (size_t i = 0; i < it->m_TLSDynNum; ++i) + pRelDyn.reserveEntry(); } } @@ -147,6 +168,8 @@ void MipsGOT::initGOTList() { m_InputGlobalSymbols.clear(); m_MergedLocalSymbols.clear(); m_InputLocalSymbols.clear(); + m_InputTLSGdSymbols.clear(); + m_HasTLSLdmSymbol = false; } void MipsGOT::changeInput() { @@ -262,6 +285,39 @@ bool MipsGOT::reserveGlobalEntry(ResolveInfo& pInfo) { return true; } +bool MipsGOT::reserveTLSGdEntry(ResolveInfo& pInfo) { + if (m_InputTLSGdSymbols.count(&pInfo)) + return false; + + m_InputTLSGdSymbols.insert(&pInfo); + m_MultipartList.back().m_TLSNum += 2; + m_MultipartList.back().m_TLSDynNum += 2; + + return true; +} + +bool MipsGOT::reserveTLSLdmEntry() { + if (m_HasTLSLdmSymbol) + return false; + + m_HasTLSLdmSymbol = true; + m_MultipartList.back().m_TLSNum += 2; + m_MultipartList.back().m_TLSDynNum += 1; + + return true; +} + +bool MipsGOT::reserveTLSGotEntry(ResolveInfo& pInfo) { + if (m_InputTLSGotSymbols.count(&pInfo)) + return false; + + m_InputTLSGotSymbols.insert(&pInfo); + m_MultipartList.back().m_TLSNum += 1; + m_MultipartList.back().m_TLSDynNum += 1; + + return true; +} + bool MipsGOT::isPrimaryGOTConsumed() { return m_CurrentGOTPart > 0; } @@ -290,6 +346,18 @@ Fragment* MipsGOT::consumeGlobal() { return m_MultipartList[m_CurrentGOTPart].m_pLastGlobal; } +Fragment* MipsGOT::consumeTLS(Relocation::Type pType) { + assert(m_CurrentGOTPart < m_MultipartList.size() && + "GOT number is out of range!"); + + if (m_MultipartList[m_CurrentGOTPart].isConsumed()) + ++m_CurrentGOTPart; + + m_MultipartList[m_CurrentGOTPart].consumeTLS(pType); + + return m_MultipartList[m_CurrentGOTPart].m_pLastTLS; +} + uint64_t MipsGOT::getGPAddr(const Input& pInput) const { uint64_t gotSize = 0; for (MultipartListType::const_iterator it = m_MultipartList.begin(), @@ -333,6 +401,50 @@ Fragment* MipsGOT::lookupGlobalEntry(const ResolveInfo* pInfo) { return it->second; } +void MipsGOT::recordTLSEntry(const ResolveInfo* pInfo, Fragment* pEntry, + Relocation::Type pType) { + if (pType == llvm::ELF::R_MIPS_TLS_LDM) { + m_GotTLSLdmEntry = pEntry; + } else if (pType == llvm::ELF::R_MIPS_TLS_GD) { + GotEntryKey key; + key.m_GOTPage = m_CurrentGOTPart; + key.m_pInfo = pInfo; + key.m_Addend = 0; + m_GotTLSGdEntriesMap[key] = pEntry; + } else if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { + GotEntryKey key; + key.m_GOTPage = m_CurrentGOTPart; + key.m_pInfo = pInfo; + key.m_Addend = 0; + m_GotTLSGotEntriesMap[key] = pEntry; + } else { + llvm_unreachable("Unexpected relocation"); + } +} + +Fragment* MipsGOT::lookupTLSEntry(const ResolveInfo* pInfo, + Relocation::Type pType) { + if (pType == llvm::ELF::R_MIPS_TLS_LDM) + return m_GotTLSLdmEntry; + if (pType == llvm::ELF::R_MIPS_TLS_GD) { + GotEntryKey key; + key.m_GOTPage = m_CurrentGOTPart; + key.m_pInfo = pInfo; + key.m_Addend = 0; + GotEntryMapType::iterator it = m_GotTLSGdEntriesMap.find(key); + return it == m_GotTLSGdEntriesMap.end() ? nullptr : it->second; + } + if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { + GotEntryKey key; + key.m_GOTPage = m_CurrentGOTPart; + key.m_pInfo = pInfo; + key.m_Addend = 0; + GotEntryMapType::iterator it = m_GotTLSGotEntriesMap.find(key); + return it == m_GotTLSGotEntriesMap.end() ? nullptr : it->second; + } + llvm_unreachable("Unexpected relocation"); +} + void MipsGOT::recordLocalEntry(const ResolveInfo* pInfo, Relocation::DWord pAddend, Fragment* pEntry) { diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h index 409347b..fc0e540 100644 --- a/lib/Target/Mips/MipsGOT.h +++ b/lib/Target/Mips/MipsGOT.h @@ -50,6 +50,9 @@ class MipsGOT : public GOT { int reloc, Relocation::DWord pAddend); bool reserveGlobalEntry(ResolveInfo& pInfo); + bool reserveTLSGdEntry(ResolveInfo& pInfo); + bool reserveTLSGotEntry(ResolveInfo& pInfo); + bool reserveTLSLdmEntry(); size_t getLocalNum() const; ///< number of local symbols in primary GOT size_t getGlobalNum() const; ///< total number of global symbols @@ -58,6 +61,7 @@ class MipsGOT : public GOT { Fragment* consumeLocal(); Fragment* consumeGlobal(); + Fragment* consumeTLS(Relocation::Type pType); uint64_t getGPAddr(const Input& pInput) const; uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const; @@ -65,6 +69,10 @@ class MipsGOT : public GOT { void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry); Fragment* lookupGlobalEntry(const ResolveInfo* pInfo); + void recordTLSEntry(const ResolveInfo* pInfo, Fragment* pEntry, + Relocation::Type pType); + Fragment* lookupTLSEntry(const ResolveInfo* pInfo, Relocation::Type pType); + void recordLocalEntry(const ResolveInfo* pInfo, Relocation::DWord pAddend, Fragment* pEntry); @@ -103,12 +111,16 @@ class MipsGOT : public GOT { size_t m_LocalNum; ///< number of reserved local entries size_t m_GlobalNum; ///< number of reserved global entries + size_t m_TLSNum; ///< number of reserved TLS entries + size_t m_TLSDynNum; ///< number of reserved TLS related dynamic relocations size_t m_ConsumedLocal; ///< consumed local entries size_t m_ConsumedGlobal; ///< consumed global entries + size_t m_ConsumedTLS; ///< consumed TLS entries Fragment* m_pLastLocal; ///< the last consumed local entry Fragment* m_pLastGlobal; ///< the last consumed global entry + Fragment* m_pLastTLS; ///< the last consumed TLS entry InputSetType m_Inputs; @@ -116,6 +128,7 @@ class MipsGOT : public GOT { void consumeLocal(); void consumeGlobal(); + void consumeTLS(Relocation::Type pType); }; /** \class LocalEntry @@ -153,6 +166,12 @@ class MipsGOT : public GOT { SymbolSetType m_MergedGlobalSymbols; // Global symbols from the current input. SymbolUniqueMapType m_InputGlobalSymbols; + // Set of symbols referenced by TLS GD relocations. + SymbolSetType m_InputTLSGdSymbols; + // Set of symbols referenced by TLS GOTTPREL relocation. + SymbolSetType m_InputTLSGotSymbols; + // There is a symbol referenced by TLS LDM relocations. + bool m_HasTLSLdmSymbol; // Local symbols merged to the current GOT // except symbols from the current input. LocalSymbolSetType m_MergedLocalSymbols; @@ -191,6 +210,9 @@ class MipsGOT : public GOT { typedef std::map<GotEntryKey, Fragment*> GotEntryMapType; GotEntryMapType m_GotLocalEntriesMap; GotEntryMapType m_GotGlobalEntriesMap; + GotEntryMapType m_GotTLSGdEntriesMap; + GotEntryMapType m_GotTLSGotEntriesMap; + Fragment* m_GotTLSLdmEntry; }; /** \class Mips32GOT diff --git a/lib/Target/Mips/MipsGOTPLT.cpp b/lib/Target/Mips/MipsGOTPLT.cpp index 745b258..dab4be5 100644 --- a/lib/Target/Mips/MipsGOTPLT.cpp +++ b/lib/Target/Mips/MipsGOTPLT.cpp @@ -25,12 +25,6 @@ MipsGOTPLT::MipsGOTPLT(LDSection& pSection) : GOT(pSection) { // Create header's entries. new GOTPLTEntry(0, m_SectionData); new GOTPLTEntry(0, m_SectionData); - m_Last = ++m_SectionData->begin(); -} - -void MipsGOTPLT::reserve(size_t pNum) { - for (size_t i = 0; i < pNum; ++i) - new GOTPLTEntry(0, m_SectionData); } uint64_t MipsGOTPLT::emit(MemoryRegion& pRegion) { @@ -45,11 +39,8 @@ uint64_t MipsGOTPLT::emit(MemoryRegion& pRegion) { return result; } -Fragment* MipsGOTPLT::consume() { - ++m_Last; - assert(m_Last != m_SectionData->end() && - "There is no reserved GOTPLT entries"); - return &(*m_Last); +Fragment* MipsGOTPLT::create() { + return new GOTPLTEntry(0, m_SectionData); } bool MipsGOTPLT::hasGOT1() const { diff --git a/lib/Target/Mips/MipsGOTPLT.h b/lib/Target/Mips/MipsGOTPLT.h index f5cd909..b585707 100644 --- a/lib/Target/Mips/MipsGOTPLT.h +++ b/lib/Target/Mips/MipsGOTPLT.h @@ -31,17 +31,9 @@ class MipsGOTPLT : public GOT { uint64_t emit(MemoryRegion& pRegion); - Fragment* consume(); + Fragment* create(); void applyAllGOTPLT(uint64_t pltAddr); - - public: - // GOT - void reserve(size_t pNum = 1); - - private: - // the last consumed entry. - SectionData::iterator m_Last; }; } // namespace mcld diff --git a/lib/Target/Mips/MipsLA25Stub.cpp b/lib/Target/Mips/MipsLA25Stub.cpp index 3127b37..9bcf85f 100644 --- a/lib/Target/Mips/MipsLA25Stub.cpp +++ b/lib/Target/Mips/MipsLA25Stub.cpp @@ -19,13 +19,6 @@ const uint32_t STUB[] = { 0x00000000 // nop }; -enum { - // Fake relocations for patching LA25 stubs. - R_MIPS_LA25_LUI = 200, - R_MIPS_LA25_J = 201, - R_MIPS_LA25_ADD = 202 -}; - } // anonymous namespace namespace mcld { @@ -39,9 +32,9 @@ MipsLA25Stub::MipsLA25Stub(const MipsGNULDBackend& pTarget) m_Name("MipsLA25_Prototype"), m_pData(STUB), m_Size(sizeof(STUB)) { - addFixup(0, 0x0, R_MIPS_LA25_LUI); - addFixup(4, 0x0, R_MIPS_LA25_J); - addFixup(8, 0x0, R_MIPS_LA25_ADD); + addFixup(0, 0x0, llvm::ELF::R_MIPS_HI16); + addFixup(4, 0x0, llvm::ELF::R_MIPS_26); + addFixup(8, 0x0, llvm::ELF::R_MIPS_LO16); } MipsLA25Stub::MipsLA25Stub(const MipsGNULDBackend& pTarget, diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp index c629edd..d4e8145 100644 --- a/lib/Target/Mips/MipsLDBackend.cpp +++ b/lib/Target/Mips/MipsLDBackend.cpp @@ -16,11 +16,14 @@ #include "mcld/IRBuilder.h" #include "mcld/LinkerConfig.h" #include "mcld/Module.h" +#include "mcld/Fragment/AlignFragment.h" #include "mcld/Fragment/FillFragment.h" #include "mcld/LD/BranchIslandFactory.h" #include "mcld/LD/LDContext.h" #include "mcld/LD/StubFactory.h" #include "mcld/LD/ELFFileFormat.h" +#include "mcld/LD/ELFSegment.h" +#include "mcld/LD/ELFSegmentFactory.h" #include "mcld/MC/Attribute.h" #include "mcld/Object/ObjectBuilder.h" #include "mcld/Support/MemoryRegion.h" @@ -30,9 +33,13 @@ #include "mcld/Target/OutputRelocSection.h" #include <llvm/ADT/Triple.h> +#include <llvm/Object/ELFTypes.h> #include <llvm/Support/Casting.h> #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> +#include <llvm/Support/MipsABIFlags.h> + +#include <vector> namespace mcld { @@ -50,6 +57,7 @@ MipsGNULDBackend::MipsGNULDBackend(const LinkerConfig& pConfig, m_pRelPlt(NULL), m_pRelDyn(NULL), m_pDynamic(NULL), + m_pAbiFlags(NULL), m_pGOTSymbol(NULL), m_pPLTSymbol(NULL), m_pGpDispSymbol(NULL) { @@ -99,6 +107,17 @@ void MipsGNULDBackend::initTargetSections(Module& pModule, // initialize .rel.dyn LDSection& reldyn = file_format->getRelDyn(); m_pRelDyn = new OutputRelocSection(pModule, reldyn); + + // initialize .sdata + m_psdata = pBuilder.CreateSection( + ".sdata", LDFileFormat::Target, llvm::ELF::SHT_PROGBITS, + llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_MIPS_GPREL, + 4); + + // initialize .MIPS.abiflags + m_pAbiFlags = pBuilder.CreateSection(".MIPS.abiflags", LDFileFormat::Target, + llvm::ELF::SHT_MIPS_ABIFLAGS, + llvm::ELF::SHF_ALLOC, 4); } void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) { @@ -163,6 +182,9 @@ void MipsGNULDBackend::doPreLayout(IRBuilder& pBuilder) { if (!config().isCodeStatic() && m_pDynamic == NULL) m_pDynamic = new MipsELFDynamic(*this, config()); + if (m_pAbiInfo.hasValue()) + m_pAbiFlags->setSize(m_pAbiInfo->size()); + // set .got size // when building shared object, the .got section is must. if (LinkerConfig::Object != config().codeGenType()) { @@ -219,18 +241,6 @@ void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) { } m_pInfo.setABIVersion(m_pPLT && m_pPLT->hasPLT1() ? 1 : 0); - - // FIXME: (simon) We need to iterate all input sections - // check that flags are consistent and merge them properly. - uint64_t picFlags = llvm::ELF::EF_MIPS_CPIC; - if (config().targets().triple().isArch64Bit()) { - picFlags |= llvm::ELF::EF_MIPS_PIC; - } else { - if (LinkerConfig::DynObj == config().codeGenType()) - picFlags |= llvm::ELF::EF_MIPS_PIC; - } - - m_pInfo.setPICFlags(picFlags); } /// dynamic - the dynamic section of the target machine. @@ -265,6 +275,60 @@ uint64_t MipsGNULDBackend::emitSectionData(const LDSection& pSection, return m_pGOTPLT->emit(pRegion); } + if (&pSection == m_pAbiFlags && m_pAbiInfo.hasValue()) + return MipsAbiFlags::emit(*m_pAbiInfo, pRegion); + + if (&pSection == m_psdata && m_psdata->hasSectionData()) { + const SectionData* sect_data = pSection.getSectionData(); + SectionData::const_iterator frag_iter, frag_end = sect_data->end(); + uint8_t* out_offset = pRegion.begin(); + for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) { + size_t size = frag_iter->size(); + switch (frag_iter->getKind()) { + case Fragment::Fillment: { + const FillFragment& fill_frag = llvm::cast<FillFragment>(*frag_iter); + if (fill_frag.getValueSize() == 0) { + // virtual fillment, ignore it. + break; + } + memset(out_offset, fill_frag.getValue(), fill_frag.size()); + break; + } + case Fragment::Region: { + const RegionFragment& region_frag = + llvm::cast<RegionFragment>(*frag_iter); + const char* start = region_frag.getRegion().begin(); + memcpy(out_offset, start, size); + break; + } + case Fragment::Alignment: { + const AlignFragment& align_frag = + llvm::cast<AlignFragment>(*frag_iter); + uint64_t count = size / align_frag.getValueSize(); + switch (align_frag.getValueSize()) { + case 1u: + std::memset(out_offset, align_frag.getValue(), count); + break; + default: + llvm::report_fatal_error( + "unsupported value size for align fragment emission yet.\n"); + break; + } // end switch + break; + } + case Fragment::Null: { + assert(0x0 == size); + break; + } + default: + llvm::report_fatal_error("unsupported fragment type.\n"); + break; + } // end switch + out_offset += size; + } + return pRegion.size(); + } + fatal(diag::unrecognized_output_sectoin) << pSection.name() << "mclinker@googlegroups.com"; return 0; @@ -335,10 +399,55 @@ struct Elf64_RegInfo { namespace mcld { -bool MipsGNULDBackend::readSection(Input& pInput, SectionData& pSD) { - llvm::StringRef name(pSD.getSection().name()); +static const char* ArchName(uint64_t flagBits) { + switch (flagBits) { + case llvm::ELF::EF_MIPS_ARCH_1: + return "mips1"; + case llvm::ELF::EF_MIPS_ARCH_2: + return "mips2"; + case llvm::ELF::EF_MIPS_ARCH_3: + return "mips3"; + case llvm::ELF::EF_MIPS_ARCH_4: + return "mips4"; + case llvm::ELF::EF_MIPS_ARCH_5: + return "mips5"; + case llvm::ELF::EF_MIPS_ARCH_32: + return "mips32"; + case llvm::ELF::EF_MIPS_ARCH_64: + return "mips64"; + case llvm::ELF::EF_MIPS_ARCH_32R2: + return "mips32r2"; + case llvm::ELF::EF_MIPS_ARCH_64R2: + return "mips64r2"; + case llvm::ELF::EF_MIPS_ARCH_32R6: + return "mips32r6"; + case llvm::ELF::EF_MIPS_ARCH_64R6: + return "mips64r6"; + default: + return "Unknown Arch"; + } +} + +void MipsGNULDBackend::mergeFlags(Input& pInput, const char* ELF_hdr) { + bool isTarget64Bit = config().targets().triple().isArch64Bit(); + bool isInput64Bit = ELF_hdr[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64; - if (name.startswith(".sdata")) { + if (isTarget64Bit != isInput64Bit) { + fatal(diag::error_Mips_incompatible_class) + << (isTarget64Bit ? "ELFCLASS64" : "ELFCLASS32") + << (isInput64Bit ? "ELFCLASS64" : "ELFCLASS32") << pInput.name(); + return; + } + + m_ElfFlagsMap[&pInput] = + isInput64Bit ? + reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(ELF_hdr)->e_flags : + reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(ELF_hdr)->e_flags; +} + +bool MipsGNULDBackend::readSection(Input& pInput, SectionData& pSD) { + if ((pSD.getSection().flag() & llvm::ELF::SHF_MIPS_GPREL) || + (pSD.getSection().type() == llvm::ELF::SHT_MIPS_ABIFLAGS)) { uint64_t offset = pInput.fileOffset() + pSD.getSection().offset(); uint64_t size = pSD.getSection().size(); @@ -449,6 +558,12 @@ unsigned int MipsGNULDBackend::getTargetSectionOrder( if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT())) return SHO_PLT; + if (&pSectHdr == m_psdata) + return SHO_SMALL_DATA; + + if (&pSectHdr == m_pAbiFlags) + return SHO_RO_NOTE; + return SHO_UNDEFINED; } @@ -558,6 +673,14 @@ bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule) { return true; } +uint64_t MipsGNULDBackend::getTPOffset(const Input& pInput) const { + return m_TpOffsetMap.lookup(&pInput); +} + +uint64_t MipsGNULDBackend::getDTPOffset(const Input& pInput) const { + return m_DtpOffsetMap.lookup(&pInput); +} + uint64_t MipsGNULDBackend::getGP0(const Input& pInput) const { return m_GP0Map.lookup(&pInput); } @@ -620,7 +743,24 @@ void MipsGNULDBackend::defineGOTPLTSymbol(IRBuilder& pBuilder) { /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule) { - // TODO + if (!m_pAbiFlags || m_pAbiFlags->size() == 0) + return; + + // create PT_MIPS_ABIFLAGS segment + ELFSegmentFactory::iterator sit = + elfSegmentTable().find(llvm::ELF::PT_INTERP, 0x0, 0x0); + if (sit == elfSegmentTable().end()) + sit = elfSegmentTable().find(llvm::ELF::PT_PHDR, 0x0, 0x0); + if (sit == elfSegmentTable().end()) + sit = elfSegmentTable().begin(); + else + ++sit; + + ELFSegment* abiSeg = elfSegmentTable().insert(sit, + llvm::ELF::PT_MIPS_ABIFLAGS, + llvm::ELF::PF_R); + abiSeg->setAlign(8); + abiSeg->append(m_pAbiFlags); } bool MipsGNULDBackend::relaxRelocation(IRBuilder& pBuilder, Relocation& pRel) { @@ -640,6 +780,9 @@ bool MipsGNULDBackend::relaxRelocation(IRBuilder& pBuilder, Relocation& pRel) { return false; assert(stub->symInfo() != NULL); + // reset the branch target of the reloc to this stub instead + pRel.setSymInfo(stub->symInfo()); + // increase the size of .symtab and .strtab LDSection& symtab = getOutputFormat()->getSymTab(); LDSection& strtab = getOutputFormat()->getStrTab(); @@ -681,38 +824,65 @@ bool MipsGNULDBackend::doRelax(Module& pModule, } } - SectionData* textData = getOutputFormat()->getText().getSectionData(); - // find the first fragment w/ invalid offset due to stub insertion - Fragment* invalid = NULL; + std::vector<Fragment*> invalid_frags; pFinished = true; for (BranchIslandFactory::iterator ii = getBRIslandFactory()->begin(), ie = getBRIslandFactory()->end(); ii != ie; ++ii) { BranchIsland& island = *ii; - if (island.end() == textData->end()) - break; + if (island.size() > stubGroupSize()) { + error(diag::err_no_space_to_place_stubs) << stubGroupSize(); + return false; + } + + if (island.numOfStubs() == 0) { + continue; + } + + Fragment* exit = &*island.end(); + if (exit == island.begin()->getParent()->end()) { + continue; + } - Fragment* exit = island.end(); if ((island.offset() + island.size()) > exit->getOffset()) { - invalid = exit; - pFinished = false; - break; + if (invalid_frags.empty() || + (invalid_frags.back()->getParent() != island.getParent())) { + invalid_frags.push_back(exit); + pFinished = false; + } + continue; } } // reset the offset of invalid fragments - while (invalid != NULL) { - invalid->setOffset(invalid->getPrevNode()->getOffset() + - invalid->getPrevNode()->size()); - invalid = invalid->getNextNode(); + for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie; + ++it) { + Fragment* invalid = *it; + while (invalid != NULL) { + invalid->setOffset(invalid->getPrevNode()->getOffset() + + invalid->getPrevNode()->size()); + invalid = invalid->getNextNode(); + } } - // reset the size of .text - if (isRelaxed) - getOutputFormat()->getText().setSize(textData->back().getOffset() + - textData->back().size()); + // reset the size of section that has stubs inserted. + if (isRelaxed) { + SectionData* prev = NULL; + for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), + island_end = getBRIslandFactory()->end(); + island != island_end; + ++island) { + SectionData* sd = (*island).begin()->getParent(); + if ((*island).numOfStubs() != 0) { + if (sd != prev) { + sd->getSection().setSize(sd->back().getOffset() + sd->back().size()); + } + } + prev = sd; + } + } return isRelaxed; } @@ -824,6 +994,253 @@ void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel, pRel.r_addend = pAddend; } +namespace { +struct ISATreeEdge { + unsigned child; + unsigned parent; +}; +} + +static ISATreeEdge isaTree[] = { + // MIPS32R6 and MIPS64R6 are not compatible with other extensions + + // MIPS64 extensions. + {llvm::ELF::EF_MIPS_ARCH_64R2, llvm::ELF::EF_MIPS_ARCH_64}, + // MIPS V extensions. + {llvm::ELF::EF_MIPS_ARCH_64, llvm::ELF::EF_MIPS_ARCH_5}, + // MIPS IV extensions. + {llvm::ELF::EF_MIPS_ARCH_5, llvm::ELF::EF_MIPS_ARCH_4}, + // MIPS III extensions. + {llvm::ELF::EF_MIPS_ARCH_4, llvm::ELF::EF_MIPS_ARCH_3}, + // MIPS32 extensions. + {llvm::ELF::EF_MIPS_ARCH_32R2, llvm::ELF::EF_MIPS_ARCH_32}, + // MIPS II extensions. + {llvm::ELF::EF_MIPS_ARCH_3, llvm::ELF::EF_MIPS_ARCH_2}, + {llvm::ELF::EF_MIPS_ARCH_32, llvm::ELF::EF_MIPS_ARCH_2}, + // MIPS I extensions. + {llvm::ELF::EF_MIPS_ARCH_2, llvm::ELF::EF_MIPS_ARCH_1}, +}; + +static bool isIsaMatched(uint32_t base, uint32_t ext) { + if (base == ext) + return true; + if (base == llvm::ELF::EF_MIPS_ARCH_32 && + isIsaMatched(llvm::ELF::EF_MIPS_ARCH_64, ext)) + return true; + if (base == llvm::ELF::EF_MIPS_ARCH_32R2 && + isIsaMatched(llvm::ELF::EF_MIPS_ARCH_64R2, ext)) + return true; + for (const auto &edge : isaTree) { + if (ext == edge.child) { + ext = edge.parent; + if (ext == base) + return true; + } + } + return false; +} + +static bool getAbiFlags(const Input& pInput, uint64_t elfFlags, bool& hasFlags, + MipsAbiFlags& pFlags) { + MipsAbiFlags pElfFlags = {}; + if (!MipsAbiFlags::fillByElfFlags(pInput, elfFlags, pElfFlags)) + return false; + + const LDContext* ctx = pInput.context(); + for (auto it = ctx->sectBegin(), ie = ctx->sectEnd(); it != ie; ++it) + if ((*it)->type() == llvm::ELF::SHT_MIPS_ABIFLAGS) { + if (!MipsAbiFlags::fillBySection(pInput, **it, pFlags)) + return false; + if (!MipsAbiFlags::isCompatible(pInput, pElfFlags, pFlags)) + return false; + hasFlags = true; + return true; + } + + pFlags = pElfFlags; + return true; +} + +static const char* getNanName(uint64_t flags) { + return flags & llvm::ELF::EF_MIPS_NAN2008 ? "2008" : "legacy"; +} + +static bool mergeElfFlags(const Input& pInput, uint64_t& oldElfFlags, + uint64_t newElfFlags) { + // PIC code is inherently CPIC and may not set CPIC flag explicitly. + // Ensure that this flag will exist in the linked file. + if (newElfFlags & llvm::ELF::EF_MIPS_PIC) + newElfFlags |= llvm::ELF::EF_MIPS_CPIC; + + if (newElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16) { + error(diag::error_Mips_m16_unsupported) << pInput.name(); + return false; + } + + if (!oldElfFlags) { + oldElfFlags = newElfFlags; + return true; + } + + uint64_t newPic = + newElfFlags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC); + uint64_t oldPic = + oldElfFlags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC); + + // Check PIC / CPIC flags compatibility. + if ((newPic != 0) != (oldPic != 0)) + warning(diag::warn_Mips_abicalls_linking) << pInput.name(); + + if (!(newPic & llvm::ELF::EF_MIPS_PIC)) + oldElfFlags &= ~llvm::ELF::EF_MIPS_PIC; + if (newPic) + oldElfFlags |= llvm::ELF::EF_MIPS_CPIC; + + // Check ISA compatibility. + uint64_t newArch = newElfFlags & llvm::ELF::EF_MIPS_ARCH; + uint64_t oldArch = oldElfFlags & llvm::ELF::EF_MIPS_ARCH; + if (!isIsaMatched(newArch, oldArch)) { + if (!isIsaMatched(oldArch, newArch)) { + error(diag::error_Mips_inconsistent_arch) + << ArchName(oldArch) << ArchName(newArch) << pInput.name(); + return false; + } + oldElfFlags &= ~llvm::ELF::EF_MIPS_ARCH; + oldElfFlags |= newArch; + } + + // Check ABI compatibility. + uint32_t newAbi = newElfFlags & llvm::ELF::EF_MIPS_ABI; + uint32_t oldAbi = oldElfFlags & llvm::ELF::EF_MIPS_ABI; + if (newAbi != oldAbi && newAbi && oldAbi) { + error(diag::error_Mips_inconsistent_abi) << pInput.name(); + return false; + } + + // Check -mnan flags compatibility. + if ((newElfFlags & llvm::ELF::EF_MIPS_NAN2008) != + (oldElfFlags & llvm::ELF::EF_MIPS_NAN2008)) { + // Linking -mnan=2008 and -mnan=legacy modules + error(diag::error_Mips_inconsistent_mnan) + << getNanName(oldElfFlags) << getNanName(newElfFlags) << pInput.name(); + return false; + } + + // Check ASE compatibility. + uint64_t newAse = newElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE; + uint64_t oldAse = oldElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE; + if (newAse != oldAse) + oldElfFlags |= newAse; + + // Check FP64 compatibility. + if ((newElfFlags & llvm::ELF::EF_MIPS_FP64) != + (oldElfFlags & llvm::ELF::EF_MIPS_FP64)) { + // Linking -mnan=2008 and -mnan=legacy modules + error(diag::error_Mips_inconsistent_fp64) << pInput.name(); + return false; + } + + oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_NOREORDER; + oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_MICROMIPS; + oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_NAN2008; + oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_32BITMODE; + + return true; +} + +void MipsGNULDBackend::saveTPOffset(const Input& pInput) { + const LDContext* ctx = pInput.context(); + for (auto it = ctx->sectBegin(), ie = ctx->sectEnd(); it != ie; ++it) { + LDSection* sect = *it; + if (sect->flag() & llvm::ELF::SHF_TLS) { + m_TpOffsetMap[&pInput] = sect->addr() + 0x7000; + m_DtpOffsetMap[&pInput] = sect->addr() + 0x8000; + break; + } + } +} + +void MipsGNULDBackend::preMergeSections(Module& pModule) { + uint64_t elfFlags = 0; + bool hasAbiFlags = false; + MipsAbiFlags abiFlags = {}; + for (const Input *input : pModule.getObjectList()) { + if (input->type() != Input::Object) + continue; + + uint64_t newElfFlags = m_ElfFlagsMap[input]; + + MipsAbiFlags newAbiFlags = {}; + if (!getAbiFlags(*input, newElfFlags, hasAbiFlags, newAbiFlags)) + continue; + + if (!mergeElfFlags(*input, elfFlags, newElfFlags)) + continue; + + if (!MipsAbiFlags::merge(*input, abiFlags, newAbiFlags)) + continue; + + saveTPOffset(*input); + } + + m_pInfo.setElfFlags(elfFlags); + if (hasAbiFlags) + m_pAbiInfo = abiFlags; +} + +bool MipsGNULDBackend::mergeSection(Module& pModule, const Input& pInput, + LDSection& pSection) { + if (pSection.flag() & llvm::ELF::SHF_MIPS_GPREL) { + SectionData* sd = NULL; + if (!m_psdata->hasSectionData()) { + sd = IRBuilder::CreateSectionData(*m_psdata); + m_psdata->setSectionData(sd); + } + sd = m_psdata->getSectionData(); + moveSectionData(*pSection.getSectionData(), *sd); + } else if (pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS) { + // Nothing to do because we handle all .MIPS.abiflags sections + // in the preMergeSections method. + } else { + ObjectBuilder builder(pModule); + builder.MergeSection(pInput, pSection); + } + return true; +} + +void MipsGNULDBackend::moveSectionData(SectionData& pFrom, SectionData& pTo) { + assert(&pFrom != &pTo && "Cannot move section data to itself!"); + + uint64_t offset = pTo.getSection().size(); + AlignFragment* align = NULL; + if (pFrom.getSection().align() > 1) { + // if the align constraint is larger than 1, append an alignment + unsigned int alignment = pFrom.getSection().align(); + align = new AlignFragment(/*alignment*/ alignment, + /*the filled value*/ 0x0, + /*the size of filled value*/ 1u, + /*max bytes to emit*/ alignment - 1); + align->setOffset(offset); + align->setParent(&pTo); + pTo.getFragmentList().push_back(align); + offset += align->size(); + } + + // move fragments from pFrom to pTO + SectionData::FragmentListType& from_list = pFrom.getFragmentList(); + SectionData::FragmentListType& to_list = pTo.getFragmentList(); + SectionData::FragmentListType::iterator frag, fragEnd = from_list.end(); + for (frag = from_list.begin(); frag != fragEnd; ++frag) { + frag->setParent(&pTo); + frag->setOffset(offset); + offset += frag->size(); + } + to_list.splice(to_list.end(), from_list); + + // set up pTo's header + pTo.getSection().setSize(offset); +} + //===----------------------------------------------------------------------===// // Mips32GNULDBackend //===----------------------------------------------------------------------===// diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h index 2dbf8d1..92e9926 100644 --- a/lib/Target/Mips/MipsLDBackend.h +++ b/lib/Target/Mips/MipsLDBackend.h @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #ifndef TARGET_MIPS_MIPSLDBACKEND_H_ #define TARGET_MIPS_MIPSLDBACKEND_H_ +#include <llvm/Support/ELF.h> #include "mcld/Target/GNULDBackend.h" +#include "MipsAbiFlags.h" #include "MipsELFDynamic.h" #include "MipsGOT.h" #include "MipsGOTPLT.h" @@ -123,6 +125,14 @@ class MipsGNULDBackend : public GNULDBackend { /// sections. bool allocateCommonSymbols(Module& pModule); + /// getTPOffset - return TP_OFFSET against the SHF_TLS + /// section in the specified input. + uint64_t getTPOffset(const Input& pInput) const; + + /// getDTPOffset - return DTP_OFFSET against the SHF_TLS + /// section in the specified input. + uint64_t getDTPOffset(const Input& pInput) const; + /// getGP0 - the gp value used to create the relocatable objects /// in the specified input. uint64_t getGP0(const Input& pInput) const; @@ -208,9 +218,19 @@ class MipsGNULDBackend : public GNULDBackend { uint64_t pOffset, int64_t pAddend) const; + /// preMergeSections - hooks to be executed before merging sections + void preMergeSections(Module& pModule); + + /// mergeSection - merge target dependent sections + bool mergeSection(Module& pModule, const Input& pInput, LDSection& pSection); + + protected: + virtual void mergeFlags(Input& pInput, const char* ELF_hdr); + private: typedef llvm::DenseSet<const ResolveInfo*> ResolveInfoSetType; - typedef llvm::DenseMap<const Input*, llvm::ELF::Elf64_Addr> GP0MapType; + typedef llvm::DenseMap<const Input*, llvm::ELF::Elf64_Addr> InputNumMapType; + typedef llvm::DenseMap<const Input*, uint64_t> ElfFlagsMapType; protected: Relocator* m_pRelocator; @@ -220,18 +240,27 @@ class MipsGNULDBackend : public GNULDBackend { private: MipsGNUInfo& m_pInfo; + llvm::Optional<MipsAbiFlags> m_pAbiInfo; OutputRelocSection* m_pRelPlt; // .rel.plt OutputRelocSection* m_pRelDyn; // .rel.dyn MipsELFDynamic* m_pDynamic; + LDSection* m_psdata; + LDSection* m_pAbiFlags; LDSymbol* m_pGOTSymbol; LDSymbol* m_pPLTSymbol; LDSymbol* m_pGpDispSymbol; SymbolListType m_GlobalGOTSyms; ResolveInfoSetType m_HasNonPICBranchSyms; - GP0MapType m_GP0Map; + InputNumMapType m_GP0Map; + InputNumMapType m_TpOffsetMap; + InputNumMapType m_DtpOffsetMap; + ElfFlagsMapType m_ElfFlagsMap; + + void moveSectionData(SectionData& pFrom, SectionData& pTo); + void saveTPOffset(const Input& pInput); }; /** \class Mips32GNULDBackend diff --git a/lib/Target/Mips/MipsPLT.cpp b/lib/Target/Mips/MipsPLT.cpp index aef25f9..c0a02f6 100644 --- a/lib/Target/Mips/MipsPLT.cpp +++ b/lib/Target/Mips/MipsPLT.cpp @@ -57,7 +57,6 @@ class MipsPLTA : public PLT::Entry<sizeof(PLTA)> { //===----------------------------------------------------------------------===// MipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) { new MipsPLT0(*m_pSectionData); - m_Last = m_pSectionData->begin(); } void MipsPLT::finalizeSectionSize() { @@ -94,20 +93,8 @@ uint64_t MipsPLT::emit(MemoryRegion& pRegion) { return result; } -void MipsPLT::reserveEntry(size_t pNum) { - for (size_t i = 0; i < pNum; ++i) { - Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData); - - if (entry == NULL) - fatal(diag::fail_allocate_memory_plt); - } -} - -Fragment* MipsPLT::consume() { - ++m_Last; - assert(m_Last != m_pSectionData->end() && - "The number of PLT Entries and ResolveInfo doesn't match"); - return &(*m_Last); +PLTEntryBase* MipsPLT::create() { + return new MipsPLTA(*m_pSectionData); } void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) { diff --git a/lib/Target/Mips/MipsPLT.h b/lib/Target/Mips/MipsPLT.h index 7c26b8e..a509e0b 100644 --- a/lib/Target/Mips/MipsPLT.h +++ b/lib/Target/Mips/MipsPLT.h @@ -26,23 +26,16 @@ class MipsPLT : public PLT { public: explicit MipsPLT(LDSection& pSection); + void finalizeSectionSize(); + // hasPLT1 - return if this PLT has any PLTA/PLTB entries bool hasPLT1() const; uint64_t emit(MemoryRegion& pRegion); - Fragment* consume(); + PLTEntryBase* create(); void applyAllPLT(MipsGOTPLT& pGOTPLT); - - public: - // PLT - void reserveEntry(size_t pNum = 1); - void finalizeSectionSize(); - - private: - // the last consumed entry. - SectionData::iterator m_Last; }; } // namespace mcld diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h index 06c9a0e..c11e67f 100644 --- a/lib/Target/Mips/MipsRelocationFunctions.h +++ b/lib/Target/Mips/MipsRelocationFunctions.h @@ -21,6 +21,7 @@ DECL_MIPS_APPLY_RELOC_FUNC(lo16) \ DECL_MIPS_APPLY_RELOC_FUNC(gprel16) \ DECL_MIPS_APPLY_RELOC_FUNC(got16) \ + DECL_MIPS_APPLY_RELOC_FUNC(pc16) \ DECL_MIPS_APPLY_RELOC_FUNC(call16) \ DECL_MIPS_APPLY_RELOC_FUNC(gprel32) \ DECL_MIPS_APPLY_RELOC_FUNC(abs64) \ @@ -30,10 +31,16 @@ DECL_MIPS_APPLY_RELOC_FUNC(gotlo16) \ DECL_MIPS_APPLY_RELOC_FUNC(sub) \ DECL_MIPS_APPLY_RELOC_FUNC(jalr) \ - DECL_MIPS_APPLY_RELOC_FUNC(la25lui) \ - DECL_MIPS_APPLY_RELOC_FUNC(la25j) \ - DECL_MIPS_APPLY_RELOC_FUNC(la25add) \ DECL_MIPS_APPLY_RELOC_FUNC(pc32) \ + DECL_MIPS_APPLY_RELOC_FUNC(pc18_s3) \ + DECL_MIPS_APPLY_RELOC_FUNC(pc21_s2) \ + DECL_MIPS_APPLY_RELOC_FUNC(pc19_s2) \ + DECL_MIPS_APPLY_RELOC_FUNC(pc26_s2) \ + DECL_MIPS_APPLY_RELOC_FUNC(pchi16) \ + DECL_MIPS_APPLY_RELOC_FUNC(pclo16) \ + DECL_MIPS_APPLY_RELOC_FUNC(tlshi16) \ + DECL_MIPS_APPLY_RELOC_FUNC(tlslo16) \ + DECL_MIPS_APPLY_RELOC_FUNC(tlsgot) \ DECL_MIPS_APPLY_RELOC_FUNC(unsupported) #define DECL_MIPS_APPLY_RELOC_FUNC_PTRS \ @@ -47,7 +54,7 @@ { &gprel16, 7, "R_MIPS_GPREL16", 16}, \ { &unsupported, 8, "R_MIPS_LITERAL", 16}, \ { &got16, 9, "R_MIPS_GOT16", 16}, \ - { &unsupported, 10, "R_MIPS_PC16", 16}, \ + { &pc16, 10, "R_MIPS_PC16", 16}, \ { &call16, 11, "R_MIPS_CALL16", 16}, \ { &gprel32, 12, "R_MIPS_GPREL32", 32}, \ { &none, 13, "R_MIPS_UNUSED1", 0}, \ @@ -79,15 +86,15 @@ { &unsupported, 39, "R_MIPS_TLS_DTPREL32", 32}, \ { &unsupported, 40, "R_MIPS_TLS_DTPMOD64", 0}, \ { &unsupported, 41, "R_MIPS_TLS_DTPREL64", 0}, \ - { &unsupported, 42, "R_MIPS_TLS_GD", 16}, \ - { &unsupported, 43, "R_MIPS_TLS_LDM", 16}, \ - { &unsupported, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \ - { &unsupported, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \ - { &unsupported, 46, "R_MIPS_TLS_GOTTPREL", 16}, \ + { &tlsgot, 42, "R_MIPS_TLS_GD", 16}, \ + { &tlsgot, 43, "R_MIPS_TLS_LDM", 16}, \ + { &tlshi16, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \ + { &tlslo16, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \ + { &tlsgot, 46, "R_MIPS_TLS_GOTTPREL", 16}, \ { &unsupported, 47, "R_MIPS_TLS_TPREL32", 32}, \ { &unsupported, 48, "R_MIPS_TLS_TPREL64", 0}, \ - { &unsupported, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \ - { &unsupported, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \ + { &tlshi16, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \ + { &tlslo16, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \ { &unsupported, 51, "R_MIPS_GLOB_DAT", 0}, \ { &unsupported, 52, "", 0}, \ { &unsupported, 53, "", 0}, \ @@ -97,12 +104,12 @@ { &unsupported, 57, "", 0}, \ { &unsupported, 58, "", 0}, \ { &unsupported, 59, "", 0}, \ - { &unsupported, 60, "", 0}, \ - { &unsupported, 61, "", 0}, \ - { &unsupported, 62, "", 0}, \ - { &unsupported, 63, "", 0}, \ - { &unsupported, 64, "", 0}, \ - { &unsupported, 65, "", 0}, \ + { &pc21_s2, 60, "R_MIPS_PC21_S2", 21}, \ + { &pc26_s2, 61, "R_MIPS_PC26_S2", 26}, \ + { &pc18_s3, 62, "R_MIPS_PC18_S3", 18}, \ + { &pc19_s2, 63, "R_MIPS_PC19_S2", 19}, \ + { &pchi16, 64, "R_MIPS_PCHI16", 16}, \ + { &pclo16, 65, "R_MIPS_PCLO16", 16}, \ { &unsupported, 66, "", 0}, \ { &unsupported, 67, "", 0}, \ { &unsupported, 68, "", 0}, \ @@ -237,9 +244,9 @@ { &unsupported, 197, "", 0}, \ { &unsupported, 198, "", 0}, \ { &unsupported, 199, "", 0}, \ - { &la25lui, 200, "R_MIPS_LA25_LUI", 16}, \ - { &la25j, 201, "R_MIPS_LA25_J", 26}, \ - { &la25add, 202, "R_MIPS_LA25_ADD", 16}, \ + { &unsupported, 200, "", 0}, \ + { &unsupported, 201, "", 0}, \ + { &unsupported, 202, "", 0}, \ { &unsupported, 203, "", 0}, \ { &unsupported, 204, "", 0}, \ { &unsupported, 205, "", 0}, \ @@ -285,7 +292,7 @@ { &unsupported, 245, "", 0}, \ { &unsupported, 246, "", 0}, \ { &unsupported, 247, "", 0}, \ - { &pc32, 248, "R_MIPS_PC32", 0}, \ + { &pc32, 248, "R_MIPS_PC32", 32}, \ { &unsupported, 249, "", 0}, \ { &unsupported, 250, "R_MIPS_GNU_REL16_S2", 0}, \ { &unsupported, 251, "", 0}, \ diff --git a/lib/Target/Mips/MipsRelocator.cpp b/lib/Target/Mips/MipsRelocator.cpp index 701a876..0f39a11 100644 --- a/lib/Target/Mips/MipsRelocator.cpp +++ b/lib/Target/Mips/MipsRelocator.cpp @@ -19,19 +19,6 @@ #include <llvm/ADT/Twine.h> #include <llvm/Support/ELF.h> -namespace llvm { -namespace ELF { - -// FIXME: Consider upstream these relocation types to LLVM. -enum { - R_MIPS_LA25_LUI = 200, - R_MIPS_LA25_J = 201, - R_MIPS_LA25_ADD = 202, -}; - -} // namespace ELF -} // namespace llvm - namespace mcld { //===----------------------------------------------------------------------===// @@ -56,22 +43,16 @@ class MipsRelocationInfo { MipsRelocationInfo(Relocation& pParent, bool pIsRel) : m_Parent(&pParent), m_Type(pParent.type()), - m_Addend(0), + m_Addend(pIsRel ? pParent.target() : pParent.addend()), m_Symbol(pParent.symValue()), - m_Result(pParent.target()) { - if (pIsRel && (type() < llvm::ELF::R_MIPS_LA25_LUI || - type() > llvm::ELF::R_MIPS_LA25_ADD)) - m_Addend = pParent.target(); - else - m_Addend = pParent.addend(); - } + m_Result(pParent.target()) {} bool isNone() const { return llvm::ELF::R_MIPS_NONE == type(); } - + bool isFirst() const { return type() == (parent().type() & 0xff); } bool isLast() const { return llvm::ELF::R_MIPS_NONE == (m_Type >> 8); } MipsRelocationInfo next() const { - return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result(), 0); + return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result()); } const Relocation& parent() const { return *m_Parent; } @@ -97,20 +78,42 @@ class MipsRelocationInfo { Relocation::DWord m_Symbol; Relocation::DWord m_Result; - MipsRelocationInfo(Relocation& pParent, - Relocation::Type pType, - Relocation::DWord pResult, - Relocation::DWord pAddend, - Relocation::DWord pSymbol) + MipsRelocationInfo(Relocation& pParent, Relocation::Type pType, + Relocation::DWord pResult, Relocation::DWord pAddend) : m_Parent(&pParent), m_Type(pType), m_Addend(pAddend), - m_Symbol(pSymbol), + m_Symbol(0), m_Result(pResult) {} - - bool isFirst() const { return m_Type == parent().type(); } }; +static void helper_PLT_init(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + ResolveInfo* rsym = pReloc.parent().symInfo(); + assert(pParent.getSymPLTMap().lookUp(*rsym) == NULL && "PLT entry exists"); + + MipsGNULDBackend& backend = pParent.getTarget(); + PLTEntryBase* pltEntry = backend.getPLT().create(); + pParent.getSymPLTMap().record(*rsym, *pltEntry); + + assert(pParent.getSymGOTPLTMap().lookUp(*rsym) == NULL && + "PLT entry not exist, but DynRel entry exist!"); + Fragment* gotpltEntry = backend.getGOTPLT().create(); + pParent.getSymGOTPLTMap().record(*rsym, *gotpltEntry); + + Relocation* relEntry = backend.getRelPLT().create(); + relEntry->setType(llvm::ELF::R_MIPS_JUMP_SLOT); + relEntry->targetRef().assign(*gotpltEntry); + relEntry->setSymInfo(rsym); +} + +static Relocator::Address helper_get_PLT_address(ResolveInfo& pSym, + MipsRelocator& pParent) { + PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym); + assert(plt_entry != NULL); + return pParent.getTarget().getPLT().addr() + plt_entry->getOffset(); +} + //===----------------------------------------------------------------------===// // Relocation Functions and Tables //===----------------------------------------------------------------------===// @@ -177,10 +180,6 @@ const char* MipsRelocator::getName(Relocation::Type pType) const { return ApplyFunctions[pType & 0xff].name; } -Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const { - return ApplyFunctions[pType & 0xff].size; -} - void MipsRelocator::scanRelocation(Relocation& pReloc, IRBuilder& pBuilder, Module& pModule, @@ -253,7 +252,7 @@ void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc, break; case llvm::ELF::R_MIPS_32: case llvm::ELF::R_MIPS_64: - if (LinkerConfig::DynObj == config().codeGenType()) { + if (pReloc.isFirst() && LinkerConfig::DynObj == config().codeGenType()) { // TODO: (simon) The gold linker does not create an entry in .rel.dyn // section if the symbol section flags contains SHF_EXECINSTR. // 1. Find the reason of this condition. @@ -267,7 +266,6 @@ void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc, case llvm::ELF::R_MIPS_26: case llvm::ELF::R_MIPS_HI16: case llvm::ELF::R_MIPS_LO16: - case llvm::ELF::R_MIPS_PC16: case llvm::ELF::R_MIPS_SHIFT5: case llvm::ELF::R_MIPS_SHIFT6: case llvm::ELF::R_MIPS_SUB: @@ -306,21 +304,37 @@ void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc, case llvm::ELF::R_MIPS_GPREL16: case llvm::ELF::R_MIPS_LITERAL: break; + case llvm::ELF::R_MIPS_TLS_GD: + getTarget().getGOT().reserveTLSGdEntry(*rsym); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; + case llvm::ELF::R_MIPS_TLS_LDM: + getTarget().getGOT().reserveTLSLdmEntry(); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; + case llvm::ELF::R_MIPS_TLS_GOTTPREL: + getTarget().getGOT().reserveTLSGotEntry(*rsym); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; case llvm::ELF::R_MIPS_TLS_DTPMOD32: case llvm::ELF::R_MIPS_TLS_DTPREL32: case llvm::ELF::R_MIPS_TLS_DTPMOD64: case llvm::ELF::R_MIPS_TLS_DTPREL64: - case llvm::ELF::R_MIPS_TLS_GD: - case llvm::ELF::R_MIPS_TLS_LDM: case llvm::ELF::R_MIPS_TLS_DTPREL_HI16: case llvm::ELF::R_MIPS_TLS_DTPREL_LO16: - case llvm::ELF::R_MIPS_TLS_GOTTPREL: case llvm::ELF::R_MIPS_TLS_TPREL32: case llvm::ELF::R_MIPS_TLS_TPREL64: case llvm::ELF::R_MIPS_TLS_TPREL_HI16: case llvm::ELF::R_MIPS_TLS_TPREL_LO16: break; + case llvm::ELF::R_MIPS_PC16: case llvm::ELF::R_MIPS_PC32: + case llvm::ELF::R_MIPS_PC18_S3: + case llvm::ELF::R_MIPS_PC19_S2: + case llvm::ELF::R_MIPS_PC21_S2: + case llvm::ELF::R_MIPS_PC26_S2: + case llvm::ELF::R_MIPS_PCHI16: + case llvm::ELF::R_MIPS_PCLO16: break; default: fatal(diag::unknown_relocation) << static_cast<int>(pReloc.type()) @@ -332,6 +346,7 @@ void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, IRBuilder& pBuilder, const LDSection& pSection) { ResolveInfo* rsym = pReloc.parent().symInfo(); + bool hasPLT = rsym->reserved() & ReservePLT; switch (pReloc.type()) { case llvm::ELF::R_MIPS_NONE: @@ -348,18 +363,22 @@ void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, break; case llvm::ELF::R_MIPS_32: case llvm::ELF::R_MIPS_64: + if (pReloc.isFirst() && + getTarget().symbolNeedsDynRel(*rsym, hasPLT, true)) { + getTarget().getRelDyn().reserveEntry(); + rsym->setReserved(rsym->reserved() | ReserveRel); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + if (!getTarget().symbolFinalValueIsKnown(*rsym)) + getTarget().getGOT().reserveGlobalEntry(*rsym); + } + break; case llvm::ELF::R_MIPS_HI16: case llvm::ELF::R_MIPS_LO16: - if (getTarget().symbolNeedsDynRel(*rsym, false, true)) { + if (getTarget().symbolNeedsDynRel(*rsym, hasPLT, true) || + getTarget().symbolNeedsCopyReloc(pReloc.parent(), *rsym)) { getTarget().getRelDyn().reserveEntry(); - if (getTarget().symbolNeedsCopyReloc(pReloc.parent(), *rsym)) { - LDSymbol& cpySym = defineSymbolforCopyReloc(pBuilder, *rsym); - addCopyReloc(*cpySym.resolveInfo()); - } else { - // set Rel bit - rsym->setReserved(rsym->reserved() | ReserveRel); - getTarget().checkAndSetHasTextRel(*pSection.getLink()); - } + LDSymbol& cpySym = defineSymbolforCopyReloc(pBuilder, *rsym); + addCopyReloc(*cpySym.resolveInfo()); } break; case llvm::ELF::R_MIPS_GOT16: @@ -385,16 +404,11 @@ void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, break; case llvm::ELF::R_MIPS_26: // Create a PLT entry if the symbol requires it and does not have it. - if (getTarget().symbolNeedsPLT(*rsym) && - !(rsym->reserved() & ReservePLT)) { - getTarget().getPLT().reserveEntry(); - getTarget().getGOTPLT().reserve(); - getTarget().getRelPLT().reserveEntry(); + if (getTarget().symbolNeedsPLT(*rsym) && !hasPLT) { + helper_PLT_init(pReloc, *this); rsym->setReserved(rsym->reserved() | ReservePLT); } break; - case llvm::ELF::R_MIPS_PC16: - break; case llvm::ELF::R_MIPS_16: case llvm::ELF::R_MIPS_SHIFT5: case llvm::ELF::R_MIPS_SHIFT6: @@ -403,19 +417,35 @@ void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, case llvm::ELF::R_MIPS_HIGHEST: case llvm::ELF::R_MIPS_SCN_DISP: break; - case llvm::ELF::R_MIPS_TLS_DTPREL32: case llvm::ELF::R_MIPS_TLS_GD: + getTarget().getGOT().reserveTLSGdEntry(*rsym); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; case llvm::ELF::R_MIPS_TLS_LDM: + getTarget().getGOT().reserveTLSLdmEntry(); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; + case llvm::ELF::R_MIPS_TLS_GOTTPREL: + getTarget().getGOT().reserveTLSGotEntry(*rsym); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + break; + case llvm::ELF::R_MIPS_TLS_DTPREL32: case llvm::ELF::R_MIPS_TLS_DTPREL_HI16: case llvm::ELF::R_MIPS_TLS_DTPREL_LO16: - case llvm::ELF::R_MIPS_TLS_GOTTPREL: case llvm::ELF::R_MIPS_TLS_TPREL32: case llvm::ELF::R_MIPS_TLS_TPREL_HI16: case llvm::ELF::R_MIPS_TLS_TPREL_LO16: break; case llvm::ELF::R_MIPS_REL32: case llvm::ELF::R_MIPS_JALR: + case llvm::ELF::R_MIPS_PC16: case llvm::ELF::R_MIPS_PC32: + case llvm::ELF::R_MIPS_PC18_S3: + case llvm::ELF::R_MIPS_PC19_S2: + case llvm::ELF::R_MIPS_PC21_S2: + case llvm::ELF::R_MIPS_PC26_S2: + case llvm::ELF::R_MIPS_PCHI16: + case llvm::ELF::R_MIPS_PCLO16: break; case llvm::ELF::R_MIPS_COPY: case llvm::ELF::R_MIPS_GLOB_DAT: @@ -429,7 +459,11 @@ void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, } bool MipsRelocator::isPostponed(const Relocation& pReloc) const { - if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_HI16)) + if (isN64ABI()) + return false; + + if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_HI16) || + MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_PCHI16)) return true; if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_GOT16) && @@ -549,6 +583,14 @@ Relocator::Address MipsRelocator::getGPAddress() { return getTarget().getGOT().getGPAddr(getApplyingInput()); } +Relocator::Address MipsRelocator::getTPOffset() { + return getTarget().getTPOffset(getApplyingInput()); +} + +Relocator::Address MipsRelocator::getDTPOffset() { + return getTarget().getDTPOffset(getApplyingInput()); +} + Relocator::Address MipsRelocator::getGP0() { return getTarget().getGP0(getApplyingInput()); } @@ -572,7 +614,7 @@ Fragment& MipsRelocator::getLocalGOTEntry(MipsRelocationInfo& pReloc, got_entry = got.consumeLocal(); if (got.isPrimaryGOTConsumed()) - setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), NULL); + setupRel32DynEntry(*FragmentRef::Create(*got_entry, 0), NULL); else got.setEntryValue(got_entry, entryValue); @@ -599,7 +641,7 @@ Fragment& MipsRelocator::getGlobalGOTEntry(MipsRelocationInfo& pReloc) { got_entry = got.consumeGlobal(); if (got.isPrimaryGOTConsumed()) - setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), rsym); + setupRel32DynEntry(*FragmentRef::Create(*got_entry, 0), rsym); else got.setEntryValue(got_entry, pReloc.parent().symValue()); @@ -608,6 +650,25 @@ Fragment& MipsRelocator::getGlobalGOTEntry(MipsRelocationInfo& pReloc) { return *got_entry; } +Fragment& MipsRelocator::getTLSGOTEntry(MipsRelocationInfo& pReloc) { + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.parent().symInfo(); + MipsGOT& got = getTarget().getGOT(); + + Fragment* modEntry = got.lookupTLSEntry(rsym, pReloc.type()); + + // Found a mapping, then return the mapped entry immediately. + if (modEntry != NULL) + return *modEntry; + + // Not found. + modEntry = got.consumeTLS(pReloc.type()); + setupTLSDynEntry(*modEntry, rsym, pReloc.type()); + got.recordTLSEntry(rsym, modEntry, pReloc.type()); + + return *modEntry; +} + Relocator::Address MipsRelocator::getGOTOffset(MipsRelocationInfo& pReloc) { ResolveInfo* rsym = pReloc.parent().symInfo(); MipsGOT& got = getTarget().getGOT(); @@ -625,23 +686,34 @@ Relocator::Address MipsRelocator::getGOTOffset(MipsRelocationInfo& pReloc) { } } +Relocator::Address MipsRelocator::getTLSGOTOffset(MipsRelocationInfo& pReloc) { + MipsGOT& got = getTarget().getGOT(); + return got.getGPRelOffset(getApplyingInput(), getTLSGOTEntry(pReloc)); +} + void MipsRelocator::createDynRel(MipsRelocationInfo& pReloc) { Relocator::DWord A = pReloc.A(); Relocator::DWord S = pReloc.S(); ResolveInfo* rsym = pReloc.parent().symInfo(); - if (isLocalReloc(*rsym)) { - setupRelDynEntry(pReloc.parent().targetRef(), NULL); - pReloc.result() = A + S; - } else { - setupRelDynEntry(pReloc.parent().targetRef(), rsym); + if (getTarget().isDynamicSymbol(*rsym)) { + setupRel32DynEntry(pReloc.parent().targetRef(), rsym); // Don't add symbol value that will be resolved by the dynamic linker. pReloc.result() = A; + } else { + setupRel32DynEntry(pReloc.parent().targetRef(), NULL); + pReloc.result() = A + S; } + + if (!isLocalReloc(*rsym) && !getTarget().symbolFinalValueIsKnown(*rsym)) + getGlobalGOTEntry(pReloc); } uint64_t MipsRelocator::calcAHL(const MipsRelocationInfo& pHiReloc) { + if (isN64ABI()) + return pHiReloc.A(); + assert(m_CurrentLo16Reloc != NULL && "There is no saved R_MIPS_LO16 relocation"); @@ -656,32 +728,6 @@ bool MipsRelocator::isN64ABI() const { return config().targets().is64Bits(); } -uint64_t MipsRelocator::getPLTAddress(ResolveInfo& rsym) { - assert((rsym.reserved() & MipsRelocator::ReservePLT) && - "Symbol does not require a PLT entry"); - - SymPLTMap::const_iterator it = m_SymPLTMap.find(&rsym); - - Fragment* plt; - - if (it != m_SymPLTMap.end()) { - plt = it->second.first; - } else { - plt = getTarget().getPLT().consume(); - - Fragment* got = getTarget().getGOTPLT().consume(); - Relocation* rel = getTarget().getRelPLT().consumeEntry(); - - rel->setType(llvm::ELF::R_MIPS_JUMP_SLOT); - rel->targetRef().assign(*got); - rel->setSymInfo(&rsym); - - m_SymPLTMap[&rsym] = PLTDescriptor(plt, got); - } - - return getTarget().getPLT().addr() + plt->getOffset(); -} - uint32_t MipsRelocator::getDebugStringOffset(Relocation& pReloc) const { if (pReloc.type() != llvm::ELF::R_MIPS_32) error(diag::unsupport_reloc_for_debug_string) @@ -698,6 +744,13 @@ void MipsRelocator::applyDebugStringOffset(Relocation& pReloc, pReloc.target() = pOffset; } +void MipsRelocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym, + Relocation::Type pType) { + Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); + relEntry.setType(pType); + relEntry.targetRef() = pFragRef; + relEntry.setSymInfo(pSym); +} //===----------------------------------------------------------------------===// // Mips32Relocator @@ -707,12 +760,32 @@ Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent, : MipsRelocator(pParent, pConfig) { } -void Mips32Relocator::setupRelDynEntry(FragmentRef& pFragRef, - ResolveInfo* pSym) { - Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); - relEntry.setType(llvm::ELF::R_MIPS_REL32); - relEntry.targetRef() = pFragRef; - relEntry.setSymInfo(pSym); +void Mips32Relocator::setupRel32DynEntry(FragmentRef& pFragRef, + ResolveInfo* pSym) { + setupRelDynEntry(pFragRef, pSym, llvm::ELF::R_MIPS_REL32); +} + +void Mips32Relocator::setupTLSDynEntry(Fragment& pFrag, ResolveInfo* pSym, + Relocation::Type pType) { + pSym = pSym->isLocal() ? nullptr : pSym; + if (pType == llvm::ELF::R_MIPS_TLS_GD) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPMOD32); + FragmentRef& relFrag = *FragmentRef::Create(*pFrag.getNextNode(), 0); + setupRelDynEntry(relFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPREL32); + } else if (pType == llvm::ELF::R_MIPS_TLS_LDM) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPMOD32); + } else if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_TPREL32); + } else { + llvm_unreachable("Unexpected relocation"); + } +} + +Relocator::Size Mips32Relocator::getSize(Relocation::Type pType) const { + return ApplyFunctions[pType & 0xff].size; } //===----------------------------------------------------------------------===// @@ -723,16 +796,37 @@ Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent, : MipsRelocator(pParent, pConfig) { } -void Mips64Relocator::setupRelDynEntry(FragmentRef& pFragRef, - ResolveInfo* pSym) { +void Mips64Relocator::setupRel32DynEntry(FragmentRef& pFragRef, + ResolveInfo* pSym) { Relocation::Type type = llvm::ELF::R_MIPS_REL32 | llvm::ELF::R_MIPS_64 << 8; - // FIXME (simon): Fix dynamic relocations. - type = llvm::ELF::R_MIPS_NONE; + setupRelDynEntry(pFragRef, pSym, type); +} - Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); - relEntry.setType(type); - relEntry.targetRef() = pFragRef; - relEntry.setSymInfo(pSym); +void Mips64Relocator::setupTLSDynEntry(Fragment& pFrag, ResolveInfo* pSym, + Relocation::Type pType) { + pSym = pSym->isLocal() ? nullptr : pSym; + if (pType == llvm::ELF::R_MIPS_TLS_GD) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPMOD64); + FragmentRef& relFrag = *FragmentRef::Create(*pFrag.getNextNode(), 0); + setupRelDynEntry(relFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPREL64); + } else if (pType == llvm::ELF::R_MIPS_TLS_LDM) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_DTPMOD64); + } else if (pType == llvm::ELF::R_MIPS_TLS_GOTTPREL) { + FragmentRef& modFrag = *FragmentRef::Create(pFrag, 0); + setupRelDynEntry(modFrag, pSym, llvm::ELF::R_MIPS_TLS_TPREL64); + } else { + llvm_unreachable("Unexpected relocation"); + } +} + +Relocator::Size Mips64Relocator::getSize(Relocation::Type pType) const { + if (((pType >> 16) & 0xff) != llvm::ELF::R_MIPS_NONE) + return ApplyFunctions[(pType >> 16) & 0xff].size; + if (((pType >> 8) & 0xff) != llvm::ELF::R_MIPS_NONE) + return ApplyFunctions[(pType >> 8) & 0xff].size; + return ApplyFunctions[pType & 0xff].size; } //=========================================// @@ -784,7 +878,7 @@ static MipsRelocator::Result rel26(MipsRelocationInfo& pReloc, int32_t A = pParent.isN64ABI() ? pReloc.A() : (pReloc.A() & 0x03FFFFFF) << 2; int32_t P = pReloc.P(); int32_t S = rsym->reserved() & MipsRelocator::ReservePLT - ? pParent.getPLTAddress(*rsym) + ? helper_get_PLT_address(*rsym, pParent) : pReloc.S(); if (rsym->isLocal()) @@ -992,37 +1086,133 @@ static MipsRelocator::Result jalr(MipsRelocationInfo& pReloc, return Relocator::OK; } -// R_MIPS_LA25_LUI -static MipsRelocator::Result la25lui(MipsRelocationInfo& pReloc, +// R_MIPS_PC16 +static MipsRelocator::Result pc16(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int64_t A = signExtend<18>(pReloc.A() << 2); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = (A + S - P) >> 2; + return Relocator::OK; +} + +// R_MIPS_PC32 +static MipsRelocator::Result pc32(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int64_t A = pReloc.A(); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = A + S - P; + return Relocator::OK; +} + +// R_MIPS_PC18_S3 +static MipsRelocator::Result pc18_s3(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int64_t A = signExtend<21>(pReloc.A() << 3); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = (S + A - ((P | 7) ^ 7)) >> 3; + return Relocator::OK; +} + +// R_MIPS_PC19_S2 +static MipsRelocator::Result pc19_s2(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int64_t A = signExtend<21>(pReloc.A() << 2); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = (A + S - P) >> 2; + return Relocator::OK; +} + +// R_MIPS_PC21_S2 +static MipsRelocator::Result pc21_s2(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { + int32_t A = signExtend<23>(pReloc.A() << 2); int32_t S = pReloc.S(); + int32_t P = pReloc.P(); + pReloc.result() = (A + S - P) >> 2; + return Relocator::OK; +} + +// R_MIPS_PC26_S2 +static MipsRelocator::Result pc26_s2(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int64_t A = signExtend<28>(pReloc.A() << 2); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = (A + S - P) >> 2; + return Relocator::OK; +} - pReloc.result() = (S + 0x8000) >> 16; +// R_MIPS_PCHI16 +static MipsRelocator::Result pchi16(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + uint64_t AHL = pParent.calcAHL(pReloc); + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = (S + AHL - P + 0x8000) >> 16; + return Relocator::OK; +} +// R_MIPS_PCLO16 +static MipsRelocator::Result pclo16(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + int32_t AHL = pReloc.A() & 0xFFFF; + int64_t S = pReloc.S(); + int64_t P = pReloc.P(); + pReloc.result() = S + AHL - P; + pParent.applyPostponedRelocations(pReloc); return Relocator::OK; } -// R_MIPS_LA25_J -static MipsRelocator::Result la25j(MipsRelocationInfo& pReloc, - MipsRelocator& pParent) { - int32_t S = pReloc.S(); +// R_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_DTPREL_HI16 +// local/external: (A + S - TP Offset) >> 16 +// _gp_disp : (A + GP - P - TP Offset) >> 16 +static MipsRelocator::Result tlshi16(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + uint64_t A = pReloc.A() & 0xFFFF; + if (pReloc.type() == llvm::ELF::R_MIPS_TLS_TPREL_HI16) + A -= pParent.getTPOffset(); + else if (pReloc.type() == llvm::ELF::R_MIPS_TLS_DTPREL_HI16) + A -= pParent.getDTPOffset(); + else + llvm_unreachable("Unexpected relocation"); - pReloc.result() = S >> 2; + if (pParent.isGpDisp(pReloc.parent())) + pReloc.result() = (A + pReloc.S() - pReloc.P() + 0x8000) >> 16; + else + pReloc.result() = (A + pReloc.S() + 0x8000) >> 16; return Relocator::OK; } -// R_MIPS_LA25_ADD -static MipsRelocator::Result la25add(MipsRelocationInfo& pReloc, +// R_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_DTPREL_LO16 +// local/external: A + S - TP Offset +// _gp_disp : A + GP - P + 4 - TP Offset +static MipsRelocator::Result tlslo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - pReloc.result() = pReloc.S(); + uint64_t A = pReloc.A() & 0xFFFF; + if (pReloc.type() == llvm::ELF::R_MIPS_TLS_TPREL_LO16) + A -= pParent.getTPOffset(); + else if (pReloc.type() == llvm::ELF::R_MIPS_TLS_DTPREL_LO16) + A -= pParent.getDTPOffset(); + else + llvm_unreachable("Unexpected relocation"); + + if (pParent.isGpDisp(pReloc.parent())) + pReloc.result() = A + pReloc.S() - pReloc.P() + 4; + else + pReloc.result() = A + pReloc.S(); return Relocator::OK; } -// R_MIPS_PC32: -static MipsRelocator::Result pc32(MipsRelocationInfo& pReloc, - MipsRelocator& pParent) { +// R_MIPS_TLS_GD, R_MIPS_TLS_LDM +static MipsRelocator::Result tlsgot(MipsRelocationInfo& pReloc, + MipsRelocator& pParent) { + pReloc.result() = pParent.getTLSGOTOffset(pReloc); return Relocator::OK; } diff --git a/lib/Target/Mips/MipsRelocator.h b/lib/Target/Mips/MipsRelocator.h index 27d5896..093718f 100644 --- a/lib/Target/Mips/MipsRelocator.h +++ b/lib/Target/Mips/MipsRelocator.h @@ -11,6 +11,7 @@ #include "mcld/LD/Relocator.h" #include "mcld/Support/GCFactory.h" +#include "mcld/Target/KeyEntryMap.h" #include "MipsLDBackend.h" #include <llvm/ADT/DenseMapInfo.h> @@ -31,6 +32,9 @@ class MipsRelocator : public Relocator { ReservePLT = 4 // reserve a PLT entry }; + typedef KeyEntryMap<ResolveInfo, PLTEntryBase> SymPLTMap; + typedef KeyEntryMap<ResolveInfo, Fragment> SymGOTPLTMap; + public: MipsRelocator(MipsGNULDBackend& pParent, const LinkerConfig& pConfig); @@ -89,6 +93,14 @@ class MipsRelocator : public Relocator { /// getGPAddress - return address of _gp symbol. Address getGPAddress(); + /// getTPOffset - return TP_OFFSET against the SHF_TLS + /// section in the processing input. + Address getTPOffset(); + + /// getDTPOffset - return DTP_OFFSET against the SHF_TLS + /// section in the processing input. + Address getDTPOffset(); + /// getGP0 - the gp value used to create the relocatable objects /// in the processing input. Address getGP0(); @@ -102,16 +114,19 @@ class MipsRelocator : public Relocator { /// for this relocation. Fragment& getGlobalGOTEntry(MipsRelocationInfo& pReloc); + /// getTLSGOTEntry - initialize and return a TLS GOT entry + /// for this relocation. + Fragment& getTLSGOTEntry(MipsRelocationInfo& pReloc); + /// getGOTOffset - return offset of corresponded GOT entry. Address getGOTOffset(MipsRelocationInfo& pReloc); + /// getTLSGOTOffset - return offset of corresponded TLS GOT entry. + Address getTLSGOTOffset(MipsRelocationInfo& pReloc); + /// createDynRel - initialize dynamic relocation for the relocation. void createDynRel(MipsRelocationInfo& pReloc); - /// getPLTOffset - initialize PLT-related entries for the symbol - /// @return - return address of PLT entry - uint64_t getPLTAddress(ResolveInfo& rsym); - /// calcAHL - calculate combined addend used /// by R_MIPS_HI16 and R_MIPS_GOT16 relocations. uint64_t calcAHL(const MipsRelocationInfo& pHiReloc); @@ -121,24 +136,34 @@ class MipsRelocator : public Relocator { const char* getName(Relocation::Type pType) const; - Size getSize(Relocation::Type pType) const; + const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; } + SymPLTMap& getSymPLTMap() { return m_SymPLTMap; } + + const SymGOTPLTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; } + SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; } protected: /// setupRelDynEntry - create dynamic relocation entry. - virtual void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym) = 0; + virtual void setupRel32DynEntry(FragmentRef& pFragRef, ResolveInfo* pSym) = 0; + /// setupTLSDynEntry - create DTPMOD / DTPREL relocation entries + virtual void setupTLSDynEntry(Fragment& pFrag, ResolveInfo* pSym, + Relocation::Type pType) = 0; /// isLocalReloc - handle relocation as a local symbol bool isLocalReloc(ResolveInfo& pSym) const; + /// setupRelDynEntry - create dynamic relocation entry with specified type. + void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym, + Relocation::Type pType); + private: - typedef std::pair<Fragment*, Fragment*> PLTDescriptor; - typedef llvm::DenseMap<const ResolveInfo*, PLTDescriptor> SymPLTMap; typedef llvm::DenseSet<Relocation*> RelocationSet; typedef llvm::DenseMap<const ResolveInfo*, RelocationSet> SymRelocSetMap; private: MipsGNULDBackend& m_Target; SymPLTMap m_SymPLTMap; + SymGOTPLTMap m_SymGOTPLTMap; Input* m_pApplyingInput; SymRelocSetMap m_PostponedRelocs; MipsRelocationInfo* m_CurrentLo16Reloc; @@ -178,7 +203,10 @@ class Mips32Relocator : public MipsRelocator { private: // MipsRelocator - void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym); + void setupRel32DynEntry(FragmentRef& pFragRef, ResolveInfo* pSym); + void setupTLSDynEntry(Fragment& pFrag, ResolveInfo* pSym, + Relocation::Type pType); + Size getSize(Relocation::Type pType) const; }; /** \class Mips64Relocator @@ -190,7 +218,10 @@ class Mips64Relocator : public MipsRelocator { private: // MipsRelocator - void setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym); + void setupRel32DynEntry(FragmentRef& pFragRef, ResolveInfo* pSym); + void setupTLSDynEntry(Fragment& pFrag, ResolveInfo* pSym, + Relocation::Type pType); + Size getSize(Relocation::Type pType) const; }; } // namespace mcld diff --git a/tools/mcld/Main.cpp b/tools/mcld/Main.cpp index 7231d3c..b24d1a9 100644 --- a/tools/mcld/Main.cpp +++ b/tools/mcld/Main.cpp @@ -85,9 +85,8 @@ class Driver { }; private: - Driver(const char* prog_name, std::unique_ptr<llvm::opt::InputArgList> args) + explicit Driver(const char* prog_name) : prog_name_(prog_name), - args_(std::move(args)), module_(script_), ir_builder_(module_, config_) { return; @@ -99,13 +98,11 @@ class Driver { bool Run(); private: - bool TranslateArguments(); + bool TranslateArguments(llvm::opt::InputArgList& args); private: const char* prog_name_; - std::unique_ptr<llvm::opt::InputArgList> args_; - mcld::LinkerScript script_; mcld::LinkerConfig config_; @@ -131,12 +128,12 @@ const llvm::opt::OptTable::Info Driver::OptTable::InfoTable[] = { { PREFIX, NAME, HELPTEXT, METAVAR, kOpt_ ## ID, \ llvm::opt::Option::KIND ## Class, PARAM, FLAGS, kOpt_ ## GROUP, \ kOpt_ ## ALIAS, ALIASARGS }, -#include "Options.inc" +#include "Options.inc" // NOLINT #undef OPTION }; Driver::OptTable::OptTable() - : llvm::opt::OptTable(InfoTable, llvm::array_lengthof(InfoTable)) { } + : llvm::opt::OptTable(InfoTable) { } inline bool ShouldColorize() { const char* term = getenv("TERM"); @@ -258,13 +255,13 @@ bool InitializeInputs(mcld::IRBuilder& ir_builder, return true; } -bool Driver::TranslateArguments() { +bool Driver::TranslateArguments(llvm::opt::InputArgList& args) { //===--------------------------------------------------------------------===// // Preference //===--------------------------------------------------------------------===// // --color=mode - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Color)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Color)) { bool res = llvm::StringSwitch<bool>(arg->getValue()) .Case("never", false) .Case("always", true) @@ -278,10 +275,10 @@ bool Driver::TranslateArguments() { } // --trace - config_.options().setTrace(args_->hasArg(kOpt_Trace)); + config_.options().setTrace(args.hasArg(kOpt_Trace)); // --verbose=level - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Verbose)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Verbose)) { llvm::StringRef value = arg->getValue(); int level; if (value.getAsInteger(0, level)) { @@ -293,7 +290,7 @@ bool Driver::TranslateArguments() { } // --error-limit NUMBER - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_ErrorLimit)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ErrorLimit)) { llvm::StringRef value = arg->getValue(); int num; if (value.getAsInteger(0, num) || (num < 0)) { @@ -305,7 +302,7 @@ bool Driver::TranslateArguments() { } // --warning-limit NUMBER - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_WarningLimit)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_WarningLimit)) { llvm::StringRef value = arg->getValue(); int num; if (value.getAsInteger(0, num) || (num < 0)) { @@ -317,13 +314,13 @@ bool Driver::TranslateArguments() { } // --warn-shared-textrel - config_.options().setWarnSharedTextrel(args_->hasArg(kOpt_WarnSharedTextrel)); + config_.options().setWarnSharedTextrel(args.hasArg(kOpt_WarnSharedTextrel)); //===--------------------------------------------------------------------===// // Target //===--------------------------------------------------------------------===// llvm::Triple triple; - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Triple)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Triple)) { // 1. Use the triple from command. // -mtriple=value triple.setTriple(arg->getValue()); @@ -339,22 +336,22 @@ bool Driver::TranslateArguments() { } // If a specific emulation was requested, apply it now. - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Emulation)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Emulation)) { // -m emulation ParseEmulation(triple, arg->getValue()); - } else if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Arch)) { + } else if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Arch)) { // -march=value config_.targets().setArch(arg->getValue()); } - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_CPU)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_CPU)) { config_.targets().setTargetCPU(arg->getValue()); } config_.targets().setTriple(triple); // --gpsize=value - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_GPSize)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_GPSize)) { llvm::StringRef value = arg->getValue(); int size; if (value.getAsInteger(0, size) || (size< 0)) { @@ -362,41 +359,61 @@ bool Driver::TranslateArguments() { << ": " << arg->getValue() << "\n"; return false; } - config_.options().setGPSize(size); + config_.targets().setGPSize(size); } + // --stub-group-size=value + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_StubGroupSize)) { + llvm::StringRef value = arg->getValue(); + int size; + if (value.getAsInteger(0, size) || (size< 0)) { + mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName() + << ": " << arg->getValue() << "\n"; + return false; + } + config_.targets().setStubGroupSize(size); + } + + // --fix-cortex-a53-835769 + config_.targets().setFixCA53Erratum835769( + args.hasArg(kOpt_FixCA53Erratum835769)); + + // --fix-cortex-a53-843419 + config_.targets().setFixCA53Erratum843419( + args.hasArg(kOpt_FixCA53Erratum843419)); + //===--------------------------------------------------------------------===// // Dynamic //===--------------------------------------------------------------------===// // --entry=entry - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Entry)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Entry)) { script_.setEntry(arg->getValue()); } // -Bsymbolic - config_.options().setBsymbolic(args_->hasArg(kOpt_Bsymbolic)); + config_.options().setBsymbolic(args.hasArg(kOpt_Bsymbolic)); // -Bgroup - config_.options().setBgroup(args_->hasArg(kOpt_Bgroup)); + config_.options().setBgroup(args.hasArg(kOpt_Bgroup)); // -soname=name - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_SOName)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_SOName)) { config_.options().setSOName(arg->getValue()); } // --no-undefined - if (args_->hasArg(kOpt_NoUndef)) { + if (args.hasArg(kOpt_NoUndef)) { config_.options().setNoUndefined(true); } // --allow-multiple-definition - if (args_->hasArg(kOpt_AllowMulDefs)) { + if (args.hasArg(kOpt_AllowMulDefs)) { config_.options().setMulDefs(true); } // -z options - for (llvm::opt::Arg* arg : args_->filtered(kOpt_Z)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_Z)) { llvm::StringRef value = arg->getValue(); mcld::ZOption z_opt = llvm::StringSwitch<mcld::ZOption>(value) @@ -440,15 +457,15 @@ bool Driver::TranslateArguments() { } // --dynamic-linker=file - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Dyld)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Dyld)) { config_.options().setDyld(arg->getValue()); } // --enable-new-dtags - config_.options().setNewDTags(args_->hasArg(kOpt_EnableNewDTags)); + config_.options().setNewDTags(args.hasArg(kOpt_EnableNewDTags)); // --spare-dyanmic-tags COUNT - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_SpareDTags)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_SpareDTags)) { llvm::StringRef value = arg->getValue(); int num; if (value.getAsInteger(0, num) || (num < 0)) { @@ -464,13 +481,13 @@ bool Driver::TranslateArguments() { //===--------------------------------------------------------------------===// // Setup the codegen type. - if (args_->hasArg(kOpt_Shared) || args_->hasArg(kOpt_PIE)) { + if (args.hasArg(kOpt_Shared) || args.hasArg(kOpt_PIE)) { // -shared, -pie config_.setCodeGenType(mcld::LinkerConfig::DynObj); - } else if (args_->hasArg(kOpt_Relocatable)) { + } else if (args.hasArg(kOpt_Relocatable)) { // -r config_.setCodeGenType(mcld::LinkerConfig::Object); - } else if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_OutputFormat)) { + } else if (llvm::opt::Arg* arg = args.getLastArg(kOpt_OutputFormat)) { // --oformat=value llvm::StringRef value = arg->getValue(); if (value.equals("binary")) { @@ -482,20 +499,20 @@ bool Driver::TranslateArguments() { // Setup the output filename. llvm::StringRef output_name; - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Output)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Output)) { output_name = arg->getValue(); } if (!ConfigureOutputName(output_name, module_, config_)) { mcld::unreachable(mcld::diag::unrecognized_output_file) << module_.name(); return false; } else { - if (!args_->hasArg(kOpt_SOName)) { + if (!args.hasArg(kOpt_SOName)) { config_.options().setSOName(module_.name()); } } // --format=value - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_InputFormat)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_InputFormat)) { llvm::StringRef value = arg->getValue(); if (value.equals("binary")) { config_.options().setBinaryInput(); @@ -503,17 +520,17 @@ bool Driver::TranslateArguments() { } // Setup debug info stripping. - config_.options().setStripDebug(args_->hasArg(kOpt_StripDebug) || - args_->hasArg(kOpt_StripAll)); + config_.options().setStripDebug(args.hasArg(kOpt_StripDebug) || + args.hasArg(kOpt_StripAll)); // Setup symbol stripping mode. - if (args_->hasArg(kOpt_StripAll)) { + if (args.hasArg(kOpt_StripAll)) { config_.options().setStripSymbols( mcld::GeneralOptions::StripSymbolMode::StripAllSymbols); - } else if (args_->hasArg(kOpt_DiscardAll)) { + } else if (args.hasArg(kOpt_DiscardAll)) { config_.options().setStripSymbols( mcld::GeneralOptions::StripSymbolMode::StripLocals); - } else if (args_->hasArg(kOpt_DiscardLocals)) { + } else if (args.hasArg(kOpt_DiscardLocals)) { config_.options().setStripSymbols( mcld::GeneralOptions::StripSymbolMode::StripTemporaries); } else { @@ -522,19 +539,19 @@ bool Driver::TranslateArguments() { } // --eh-frame-hdr - config_.options().setEhFrameHdr(args_->hasArg(kOpt_EHFrameHdr)); + config_.options().setEhFrameHdr(args.hasArg(kOpt_EHFrameHdr)); // -pie - config_.options().setPIE(args_->hasArg(kOpt_PIE)); + config_.options().setPIE(args.hasArg(kOpt_PIE)); // --nmagic - config_.options().setNMagic(args_->hasArg(kOpt_NMagic)); + config_.options().setNMagic(args.hasArg(kOpt_NMagic)); // --omagic - config_.options().setOMagic(args_->hasArg(kOpt_OMagic)); + config_.options().setOMagic(args.hasArg(kOpt_OMagic)); // --hash-style=style - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_HashStyle)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_HashStyle)) { mcld::GeneralOptions::HashStyle style = llvm::StringSwitch<mcld::GeneralOptions::HashStyle>(arg->getValue()) .Case("sysv", mcld::GeneralOptions::HashStyle::SystemV) @@ -547,7 +564,7 @@ bool Driver::TranslateArguments() { } // --[no]-export-dynamic - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_ExportDynamic, + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ExportDynamic, kOpt_NoExportDynamic)) { if (arg->getOption().matches(kOpt_ExportDynamic)) { config_.options().setExportDynamic(true); @@ -557,10 +574,10 @@ bool Driver::TranslateArguments() { } // --no-warn-mismatch - config_.options().setWarnMismatch(!args_->hasArg(kOpt_NoWarnMismatch)); + config_.options().setWarnMismatch(!args.hasArg(kOpt_NoWarnMismatch)); // --exclude-libs - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_ExcludeLibs)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ExcludeLibs)) { llvm::StringRef value = arg->getValue(); do { std::pair<llvm::StringRef, llvm::StringRef> res = value.split(','); @@ -574,7 +591,7 @@ bool Driver::TranslateArguments() { //===--------------------------------------------------------------------===// // --sysroot - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Sysroot)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Sysroot)) { mcld::sys::fs::Path path(arg->getValue()); if (mcld::sys::fs::exists(path) && mcld::sys::fs::is_directory(path)) { script_.setSysroot(path); @@ -582,19 +599,16 @@ bool Driver::TranslateArguments() { } // -L searchdir - for (llvm::opt::Arg* arg : args_->filtered(kOpt_LibraryPath)) { - if (!script_.directories().insert(arg->getValue())) { - // FIXME: need a warning function - mcld::errs() << "WARNING: can not open search directory `-L" - << arg->getValue() << "'.\n"; - } + for (llvm::opt::Arg* arg : args.filtered(kOpt_LibraryPath)) { + if (!script_.directories().insert(arg->getValue())) + mcld::warning(mcld::diag::warn_cannot_open_search_dir) << arg->getValue(); } // -nostdlib - config_.options().setNoStdlib(args_->hasArg(kOpt_NoStdlib)); + config_.options().setNoStdlib(args.hasArg(kOpt_NoStdlib)); // -rpath=path - for (llvm::opt::Arg* arg : args_->filtered(kOpt_RPath)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_RPath)) { config_.options().getRpathList().push_back(arg->getValue()); } @@ -603,10 +617,10 @@ bool Driver::TranslateArguments() { //===--------------------------------------------------------------------===// // -d/-dc/-dp - config_.options().setDefineCommon(args_->hasArg(kOpt_DefineCommon)); + config_.options().setDefineCommon(args.hasArg(kOpt_DefineCommon)); // -u symbol - for (llvm::opt::Arg* arg : args_->filtered(kOpt_Undefined)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_Undefined)) { config_.options().getUndefSymList().push_back(arg->getValue()); } @@ -615,7 +629,7 @@ bool Driver::TranslateArguments() { //===--------------------------------------------------------------------===// // --wrap=symbol - for (llvm::opt::Arg* arg : args_->filtered(kOpt_Wrap)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_Wrap)) { bool exist = false; const char* symbol = arg->getValue(); // symbol -> __wrap_symbol @@ -643,7 +657,7 @@ bool Driver::TranslateArguments() { } // --portalbe=symbol - for (llvm::opt::Arg* arg : args_->filtered(kOpt_Wrap)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_Portable)) { bool exist = false; const char* symbol = arg->getValue(); // symbol -> symbol_portable @@ -671,7 +685,7 @@ bool Driver::TranslateArguments() { } // --section-start=section=addr - for (llvm::opt::Arg* arg : args_->filtered(kOpt_SectionStart)) { + for (llvm::opt::Arg* arg : args.filtered(kOpt_SectionStart)) { llvm::StringRef value = arg->getValue(); const size_t pos = value.find('='); uint64_t addr = 0; @@ -683,7 +697,7 @@ bool Driver::TranslateArguments() { } // -Tbss=value - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Tbss)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Tbss)) { llvm::StringRef value = arg->getValue(); uint64_t addr = 0; if (value.getAsInteger(0, addr)) { @@ -698,7 +712,7 @@ bool Driver::TranslateArguments() { } // -Tdata=value - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Tdata)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Tdata)) { llvm::StringRef value = arg->getValue(); uint64_t addr = 0; if (value.getAsInteger(0, addr)) { @@ -713,7 +727,7 @@ bool Driver::TranslateArguments() { } // -Ttext=value - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_Ttext)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Ttext)) { llvm::StringRef value = arg->getValue(); uint64_t addr = 0; if (value.getAsInteger(0, addr)) { @@ -732,7 +746,7 @@ bool Driver::TranslateArguments() { //===--------------------------------------------------------------------===// // --[no-]gc-sections - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_GCSections, + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_GCSections, kOpt_NoGCSections)) { if (arg->getOption().matches(kOpt_GCSections)) { config_.options().setGCSections(true); @@ -742,7 +756,7 @@ bool Driver::TranslateArguments() { } // --[no-]print-gc-sections - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_PrintGCSections, + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_PrintGCSections, kOpt_NoPrintGCSections)) { if (arg->getOption().matches(kOpt_PrintGCSections)) { config_.options().setPrintGCSections(true); @@ -752,7 +766,7 @@ bool Driver::TranslateArguments() { } // --[no-]ld-generated-unwind-info - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_LDGeneratedUnwindInfo, + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_LDGeneratedUnwindInfo, kOpt_NoLDGeneratedUnwindInfo)) { if (arg->getOption().matches(kOpt_LDGeneratedUnwindInfo)) { config_.options().setGenUnwindInfo(true); @@ -762,7 +776,7 @@ bool Driver::TranslateArguments() { } // --icf=mode - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_ICF)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ICF)) { mcld::GeneralOptions::ICF mode = llvm::StringSwitch<mcld::GeneralOptions::ICF>(arg->getValue()) .Case("none", mcld::GeneralOptions::ICF::None) @@ -778,7 +792,7 @@ bool Driver::TranslateArguments() { } // --icf-iterations - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_ICFIters)) { + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ICFIters)) { llvm::StringRef value = arg->getValue(); int num; if (value.getAsInteger(0, num) || (num < 0)) { @@ -790,7 +804,7 @@ bool Driver::TranslateArguments() { } // --[no-]print-icf-sections - if (llvm::opt::Arg* arg = args_->getLastArg(kOpt_PrintICFSections, + if (llvm::opt::Arg* arg = args.getLastArg(kOpt_PrintICFSections, kOpt_NoPrintICFSections)) { if (arg->getOption().matches(kOpt_PrintICFSections)) { config_.options().setPrintICFSections(true); @@ -811,7 +825,7 @@ bool Driver::TranslateArguments() { Action action; actions.reserve(32); - for (llvm::opt::Arg* arg : *args_) { + for (llvm::opt::Arg* arg : args) { const unsigned index = arg->getIndex(); switch (arg->getOption().getID()) { @@ -975,53 +989,47 @@ bool Driver::TranslateArguments() { return false; } + + //===--------------------------------------------------------------------===// + // Unknown + //===--------------------------------------------------------------------===// + std::vector<std::string> unknown_args = args.getAllArgValues(kOpt_UNKNOWN); + for (std::string arg : unknown_args) + mcld::warning(mcld::diag::warn_unsupported_option) << arg; + return true; } -std::unique_ptr<llvm::opt::InputArgList> -ParseArgs(const llvm::opt::OptTable& opt_table, - llvm::ArrayRef<const char*> argv) { +std::unique_ptr<Driver> Driver::Create(llvm::ArrayRef<const char*> argv) { + // Parse command line options. + OptTable opt_table; unsigned missing_arg_idx; unsigned missing_arg_count; - - std::unique_ptr<llvm::opt::InputArgList> args( - opt_table.ParseArgs(argv.begin(), argv.end(), missing_arg_idx, - missing_arg_count)); + llvm::opt::InputArgList args = + opt_table.ParseArgs(argv.slice(1), missing_arg_idx, missing_arg_count); if (missing_arg_count > 0) { - mcld::errs() << "Argument to '" << args->getArgString(missing_arg_idx) + mcld::errs() << "Argument to '" << args.getArgString(missing_arg_idx) << "' is missing (expected " << missing_arg_count << ((missing_arg_count > 1) ? " values" : " value") << ")\n"; return nullptr; } - return args; -} - -std::unique_ptr<Driver> Driver::Create(llvm::ArrayRef<const char*> argv) { - // Parse command line options. - OptTable opt_table; - std::unique_ptr<llvm::opt::InputArgList> args = ParseArgs(opt_table, - argv.slice(1)); - if (args == nullptr) { - return nullptr; - } - - std::unique_ptr<Driver> result(new Driver(argv[0], std::move(args))); + std::unique_ptr<Driver> result(new Driver(argv[0])); // Return quickly if -help is specified. - if (result->args_->hasArg(kOpt_Help)) { + if (args.hasArg(kOpt_Help)) { opt_table.PrintHelp(mcld::outs(), argv[0], "MCLinker", /* FlagsToInclude */0, /* FlagsToExclude */0); return nullptr; } // Print version information if requested. - if (result->args_->hasArg(kOpt_Version)) { + if (args.hasArg(kOpt_Version)) { mcld::outs() << result->config_.options().getVersionString() << "\n"; } // Setup instance from arguments. - if (!result->TranslateArguments()) { + if (!result->TranslateArguments(args)) { return nullptr; } diff --git a/tools/mcld/Options.td b/tools/mcld/Options.td index 80655a7..d8bc050 100644 --- a/tools/mcld/Options.td +++ b/tools/mcld/Options.td @@ -247,10 +247,6 @@ def ExcludeLibs : Separate<["--"], "exclude-libs">, Group<OutputGroup>, HelpText<"Allow linking together mismatched input files">; -def BuildID : Flag<["--"], "build-id">, - Group<OutputGroup>, - HelpText<"Request creation of .note.gnu.build-id ELF note section">; - //===----------------------------------------------------------------------===// // Positional //===----------------------------------------------------------------------===// @@ -324,7 +320,7 @@ def EndGroupAlias : Flag<["-"], ")">, def PreferenceGroup : OptionGroup<"preference">, HelpText<"PREFERENCE OPTIONS">; -def Color : Joined<["--"], "colormc=">, +def Color : Joined<["--"], "color=">, Group<PreferenceGroup>, HelpText<"Surround the result strings with the marker">; @@ -435,10 +431,6 @@ def RPath : Joined<["-"], "rpath=">, Group<SearchpathGroup>, HelpText<"Add a directory to the runtime library search path">; -def RPathLink : Joined<["-"], "rpath-link=">, - Group<SearchpathGroup>, - HelpText<"Add a directory to the link time library search path">; - //===----------------------------------------------------------------------===// // Symbol //===----------------------------------------------------------------------===// @@ -490,3 +482,15 @@ def CPU : Joined<["-"], "mcpu=">, def Emulation : Separate<["-"], "m">, Group<TargetGroup>, HelpText<"Set GNU linker emulation">; + +def StubGroupSize : Joined<["--"], "stub-group-size=">, + Group<TargetGroup>, + HelpText<"Set the group size to place stubs between sections">; + +def FixCA53Erratum835769 : Flag<["--"], "fix-cortex-a53-835769">, + Group<TargetGroup>, + HelpText<"Enable fix for cortex a53 erratum 835769">; + +def FixCA53Erratum843419 : Flag<["--"], "fix-cortex-a53-843419">, + Group<TargetGroup>, + HelpText<"Enable fix for cortex a53 erratum 843419">; |