summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPirama Arumuga Nainar <pirama@google.com>2016-03-18 21:54:50 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-03-18 21:54:52 +0000
commite1ebaae92243025b384676c97f8c012a850e337a (patch)
treea7befed71dbf26f45a068ee673db6d79e8b3e404
parenta4e968f7c0528fb5bc8d80d83ae0b061f965f2b1 (diff)
parent07177ff8032d136567f3e99d372cb67713f1bba8 (diff)
downloadmclinker-n-iot-preview-2.tar.gz
* changes: Fix up mclinker so that it builds/runs for LLVM rebase to r256229. Rebase mclinker for LLVM update to r256229.
-rw-r--r--include/mcld/Fragment/Fragment.h2
-rw-r--r--include/mcld/Fragment/Stub.h25
-rw-r--r--include/mcld/GeneralOptions.h6
-rw-r--r--include/mcld/IRBuilder.h3
-rw-r--r--include/mcld/LD/BranchIsland.h6
-rw-r--r--include/mcld/LD/BranchIslandFactory.h5
-rw-r--r--include/mcld/LD/DiagCommonKinds.inc8
-rw-r--r--include/mcld/LD/DiagLayouts.inc6
-rw-r--r--include/mcld/LD/DiagMips.inc53
-rw-r--r--include/mcld/LD/DiagnosticInfos.h1
-rw-r--r--include/mcld/LD/ELFSegmentFactory.h4
-rw-r--r--include/mcld/LD/SectionData.h4
-rw-r--r--include/mcld/LD/StubFactory.h9
-rw-r--r--include/mcld/Script/ScriptScanner.h6
-rw-r--r--include/mcld/Target/GNUInfo.h7
-rw-r--r--include/mcld/Target/GNULDBackend.h10
-rw-r--r--include/mcld/TargetOptions.h25
-rw-r--r--lib/Core/GeneralOptions.cpp1
-rw-r--r--lib/Core/IRBuilder.cpp30
-rw-r--r--lib/Core/TargetOptions.cpp14
-rw-r--r--lib/Fragment/Stub.cpp50
-rw-r--r--lib/LD/BranchIsland.cpp28
-rw-r--r--lib/LD/BranchIslandFactory.cpp40
-rw-r--r--lib/LD/DiagnosticInfos.cpp2
-rw-r--r--lib/LD/ELFObjectReader.cpp1
-rw-r--r--lib/LD/ELFSegmentFactory.cpp6
-rw-r--r--lib/LD/EhFrameReader.cpp10
-rw-r--r--lib/LD/IdenticalCodeFolding.cpp17
-rw-r--r--lib/LD/StubFactory.cpp93
-rw-r--r--lib/Object/ObjectLinker.cpp5
-rw-r--r--lib/Support/Unix/FileSystem.inc1
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum835769Stub.cpp93
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum835769Stub.h63
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum843419Stub.cpp93
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum843419Stub.h68
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum843419Stub2.cpp84
-rw-r--r--lib/Target/AArch64/AArch64CA53Erratum843419Stub2.h63
-rw-r--r--lib/Target/AArch64/AArch64CA53ErratumStub.cpp149
-rw-r--r--lib/Target/AArch64/AArch64CA53ErratumStub.h71
-rw-r--r--lib/Target/AArch64/AArch64GNUInfo.h2
-rw-r--r--lib/Target/AArch64/AArch64InsnHelpers.h278
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.cpp218
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.h16
-rw-r--r--lib/Target/AArch64/AArch64LongBranchStub.cpp145
-rw-r--r--lib/Target/AArch64/AArch64LongBranchStub.h70
-rw-r--r--lib/Target/AArch64/AArch64RelocationFunctions.h1
-rw-r--r--lib/Target/AArch64/AArch64Relocator.cpp31
-rw-r--r--lib/Target/AArch64/AArch64Relocator.h9
-rw-r--r--lib/Target/AArch64/Android.mk5
-rw-r--r--lib/Target/ARM/ARMException.cpp258
-rw-r--r--lib/Target/ARM/ARMException.h161
-rw-r--r--lib/Target/ARM/ARMLDBackend.cpp247
-rw-r--r--lib/Target/ARM/ARMLDBackend.h19
-rw-r--r--lib/Target/ARM/ARMRelocator.cpp6
-rw-r--r--lib/Target/GNULDBackend.cpp24
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.cpp63
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.h2
-rw-r--r--lib/Target/Hexagon/HexagonPLT.cpp8
-rw-r--r--lib/Target/Hexagon/HexagonPLT.h2
-rw-r--r--lib/Target/Mips/Android.mk1
-rw-r--r--lib/Target/Mips/MipsAbiFlags.cpp298
-rw-r--r--lib/Target/Mips/MipsAbiFlags.h63
-rw-r--r--lib/Target/Mips/MipsGNUInfo.cpp15
-rw-r--r--lib/Target/Mips/MipsGNUInfo.h4
-rw-r--r--lib/Target/Mips/MipsGOT.cpp118
-rw-r--r--lib/Target/Mips/MipsGOT.h22
-rw-r--r--lib/Target/Mips/MipsGOTPLT.cpp13
-rw-r--r--lib/Target/Mips/MipsGOTPLT.h10
-rw-r--r--lib/Target/Mips/MipsLA25Stub.cpp13
-rw-r--r--lib/Target/Mips/MipsLDBackend.cpp483
-rw-r--r--lib/Target/Mips/MipsLDBackend.h33
-rw-r--r--lib/Target/Mips/MipsPLT.cpp17
-rw-r--r--lib/Target/Mips/MipsPLT.h13
-rw-r--r--lib/Target/Mips/MipsRelocationFunctions.h49
-rw-r--r--lib/Target/Mips/MipsRelocator.cpp432
-rw-r--r--lib/Target/Mips/MipsRelocator.h51
-rw-r--r--tools/mcld/Main.cpp202
-rw-r--r--tools/mcld/Options.td22
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">;