summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-07-15 18:33:32 -0700
committerStephen Hines <srhines@google.com>2014-07-25 00:47:58 -0700
commita790f0a8f3175183bea088389b3e4ae41813e192 (patch)
tree80cb1165eb946f770210ef2c662c6459af15ffb0
parent717b462e8648e6e62ab9d39128a2f7e776bdf8ab (diff)
downloadmclinker-a790f0a8f3175183bea088389b3e4ae41813e192.tar.gz
Update mclinker for LLVM rebase.
commit 6824c791204cf5daabdfe008ee8808799f348815 Author: Pete Chou <petechou@gmail.com> Date: Tue Jul 15 10:15:12 2014 +0800 Fix typo in README. Change-Id: Id7a525732ba33b5ac81a0da4c8d8f02d1f8c3a16
-rw-r--r--include/mcld/Config/Config.h7
-rw-r--r--include/mcld/Config/Config.h.in1
-rw-r--r--include/mcld/GeneralOptions.h66
-rw-r--r--include/mcld/LD/BinaryReader.h1
-rw-r--r--include/mcld/LD/BranchIsland.h27
-rw-r--r--include/mcld/LD/BranchIslandFactory.h20
-rw-r--r--include/mcld/LD/DiagCommonKinds.inc1
-rw-r--r--include/mcld/LD/DiagLayouts.inc2
-rw-r--r--include/mcld/LD/DynObjReader.h1
-rw-r--r--include/mcld/LD/ELFDynObjReader.h1
-rw-r--r--include/mcld/LD/ELFObjectWriter.h3
-rw-r--r--include/mcld/LD/IdenticalCodeFolding.h79
-rw-r--r--include/mcld/LD/LDFileFormat.h6
-rw-r--r--include/mcld/LD/LDSymbol.h3
-rw-r--r--include/mcld/LD/ObjectReader.h1
-rw-r--r--include/mcld/LD/ObjectWriter.h6
-rw-r--r--include/mcld/LD/Relocator.h7
-rw-r--r--include/mcld/MC/Input.h7
-rw-r--r--include/mcld/Object/ObjectLinker.h3
-rw-r--r--include/mcld/Script/FlexLexer.h4
-rw-r--r--include/mcld/Support/CXADemangle.tcc4976
-rw-r--r--include/mcld/Support/Demangle.h22
-rw-r--r--include/mcld/Support/FileOutputBuffer.h11
-rw-r--r--include/mcld/Support/MemoryArea.h1
-rw-r--r--include/mcld/Target/GNULDBackend.h18
-rw-r--r--include/mcld/Target/TargetLDBackend.h11
-rw-r--r--lib/CodeGen/MCLDTargetMachine.cpp11
-rw-r--r--lib/Core/GeneralOptions.cpp28
-rw-r--r--lib/Core/IRBuilder.cpp15
-rw-r--r--lib/Core/Linker.cpp14
-rw-r--r--lib/LD/BranchIslandFactory.cpp58
-rw-r--r--lib/LD/DiagnosticInfos.cpp11
-rw-r--r--lib/LD/ELFBinaryReader.cpp2
-rw-r--r--lib/LD/ELFDynObjReader.cpp1
-rw-r--r--lib/LD/ELFFileFormat.cpp32
-rw-r--r--lib/LD/ELFObjectReader.cpp8
-rw-r--r--lib/LD/ELFObjectWriter.cpp16
-rw-r--r--lib/LD/GNUArchiveReader.cpp5
-rw-r--r--lib/LD/GarbageCollection.cpp27
-rw-r--r--lib/LD/Relocator.cpp35
-rw-r--r--lib/LD/StaticResolver.cpp24
-rw-r--r--lib/LD/StubFactory.cpp103
-rw-r--r--lib/MC/Input.cpp4
-rw-r--r--lib/Object/ObjectLinker.cpp48
-rw-r--r--lib/Object/SectionMap.cpp8
-rw-r--r--lib/Support/Demangle.cpp76
-rw-r--r--lib/Support/FileOutputBuffer.cpp18
-rw-r--r--lib/Support/MemoryArea.cpp11
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.cpp6
-rw-r--r--lib/Target/AArch64/AArch64LDBackend.h11
-rw-r--r--lib/Target/ARM/ARMELFAttributeData.cpp18
-rw-r--r--lib/Target/ARM/ARMELFAttributeData.h4
-rw-r--r--lib/Target/ARM/ARMLDBackend.cpp63
-rw-r--r--lib/Target/ARM/ARMLDBackend.h13
-rw-r--r--lib/Target/ARM/ARMRelocationFunctions.h3
-rw-r--r--lib/Target/ARM/ARMRelocator.cpp44
-rw-r--r--lib/Target/ARM/ARMRelocator.h5
-rw-r--r--lib/Target/ARM/ARMToARMStub.cpp5
-rw-r--r--lib/Target/ARM/ARMToARMStub.h2
-rw-r--r--lib/Target/ARM/ARMToTHMStub.cpp5
-rw-r--r--lib/Target/ARM/ARMToTHMStub.h2
-rw-r--r--lib/Target/ARM/THMToARMStub.cpp41
-rw-r--r--lib/Target/ARM/THMToARMStub.h9
-rw-r--r--lib/Target/ARM/THMToTHMStub.cpp41
-rw-r--r--lib/Target/ARM/THMToTHMStub.h9
-rw-r--r--lib/Target/GNULDBackend.cpp37
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.cpp10
-rw-r--r--lib/Target/Hexagon/HexagonLDBackend.h4
-rw-r--r--lib/Target/Mips/MipsLDBackend.cpp15
-rw-r--r--lib/Target/Mips/MipsLDBackend.h1
-rw-r--r--lib/Target/X86/X86LDBackend.cpp6
-rw-r--r--lib/Target/X86/X86LDBackend.h1
-rw-r--r--lib/Target/X86/X86Relocator.cpp51
-rw-r--r--lib/Target/X86/X86Relocator.h8
-rw-r--r--tools/llvm-mcld/llvm-mcld.cpp1552
-rw-r--r--tools/mcld/include/mcld/OptimizationOptions.h13
-rw-r--r--tools/mcld/include/mcld/SymbolOptions.h2
-rw-r--r--tools/mcld/lib/DynamicSectionOptions.cpp2
-rw-r--r--tools/mcld/lib/OptimizationOptions.cpp52
-rw-r--r--tools/mcld/lib/OutputFormatOptions.cpp10
-rw-r--r--tools/mcld/lib/PreferenceOptions.cpp16
-rw-r--r--tools/mcld/lib/SymbolOptions.cpp9
82 files changed, 6020 insertions, 1890 deletions
diff --git a/include/mcld/Config/Config.h b/include/mcld/Config/Config.h
index 9e52d54..2973426 100644
--- a/include/mcld/Config/Config.h
+++ b/include/mcld/Config/Config.h
@@ -27,11 +27,14 @@
#define MCLD_DEFAULT_TARGET_TRIPLE "x86_64-unknown-linux-gnu"
/* MCLINKER version */
-#define MCLD_VERSION "2.3.0.RC-WhiteStone"
+#define MCLD_VERSION "2.9.0.dev-"
+
+/* Name of package */
+#define PACKAGE "mclinker"
/* Version number of package */
-#define VERSION "WhiteStone"
+#define VERSION "dev"
#define MCLD_REGION_CHUNK_SIZE 32
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
index 39df682..4a38cbf 100644
--- a/include/mcld/Config/Config.h.in
+++ b/include/mcld/Config/Config.h.in
@@ -108,6 +108,7 @@
#define MCLD_SECTIONS_PER_INPUT 16
#define MCLD_SYMBOLS_PER_INPUT 128
#define MCLD_RELOCATIONS_PER_INPUT 1024
+#define MCLD_SEGMENTS_PER_OUTPUT 8
#endif
diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h
index 226e5d1..1d6c9a3 100644
--- a/include/mcld/GeneralOptions.h
+++ b/include/mcld/GeneralOptions.h
@@ -8,10 +8,11 @@
//===----------------------------------------------------------------------===//
#ifndef MCLD_GENERALOPTIONS_H
#define MCLD_GENERALOPTIONS_H
-#include <string>
-#include <vector>
#include <mcld/Support/RealPath.h>
#include <mcld/Support/FileSystem.h>
+#include <string>
+#include <vector>
+#include <set>
namespace mcld {
@@ -39,6 +40,12 @@ public:
Both = 0x3
};
+ enum ICF {
+ ICF_None,
+ ICF_All,
+ ICF_Safe
+ };
+
typedef std::vector<std::string> RpathList;
typedef RpathList::iterator rpath_iterator;
typedef RpathList::const_iterator const_rpath_iterator;
@@ -51,6 +58,12 @@ public:
typedef AuxiliaryList::iterator aux_iterator;
typedef AuxiliaryList::const_iterator const_aux_iterator;
+ typedef std::vector<std::string> UndefSymList;
+ typedef UndefSymList::iterator undef_sym_iterator;
+ typedef UndefSymList::const_iterator const_undef_sym_iterator;
+
+ typedef std::set<std::string> ExcludeLIBS;
+
public:
GeneralOptions();
~GeneralOptions();
@@ -284,6 +297,13 @@ public:
bool GCSections() const
{ return m_bGCSections; }
+ // --print-gc-sections
+ void setPrintGCSections(bool pEnable = true)
+ { m_bPrintGCSections = pEnable; }
+
+ bool getPrintGCSections() const
+ { return m_bPrintGCSections; }
+
// --ld-generated-unwind-info
void setGenUnwindInfo(bool pEnable = true)
{ m_bGenUnwindInfo = pEnable; }
@@ -303,6 +323,21 @@ public:
void setHashStyle(unsigned int pStyle)
{ m_HashStyle = pStyle; }
+ ICF getICFMode() const { return m_ICF; }
+
+ void setICFMode(ICF pMode)
+ { m_ICF = pMode; }
+
+ size_t getICFIterations() const { return m_ICFIterations; }
+
+ void setICFIterations(size_t pNum)
+ { m_ICFIterations = pNum; }
+
+ bool printICFSections() const { return m_bPrintICFSections; }
+
+ void setPrintICFSections(bool pPrintICFSections)
+ { m_bPrintICFSections = pPrintICFSections; }
+
// ----- link-in rpath ----- //
const RpathList& getRpathList() const { return m_RpathList; }
RpathList& getRpathList() { return m_RpathList; }
@@ -321,6 +356,20 @@ public:
const_script_iterator script_end () const { return m_ScriptList.end(); }
script_iterator script_end () { return m_ScriptList.end(); }
+ // ----- -u/--undefined, undefined symbols ----- //
+ const UndefSymList& getUndefSymList() const { return m_UndefSymList; }
+ UndefSymList& getUndefSymList() { return m_UndefSymList; }
+
+ const_undef_sym_iterator undef_sym_begin() const
+ { return m_UndefSymList.begin(); }
+ undef_sym_iterator undef_sym_begin()
+ { return m_UndefSymList.begin(); }
+
+ const_undef_sym_iterator undef_sym_end() const
+ { return m_UndefSymList.end(); }
+ undef_sym_iterator undef_sym_end()
+ { return m_UndefSymList.end(); }
+
// ----- filter and auxiliary filter ----- //
void setFilter(const std::string& pFilter)
{ m_Filter = pFilter; }
@@ -339,6 +388,13 @@ public:
const_aux_iterator aux_end () const { return m_AuxiliaryList.end(); }
aux_iterator aux_end () { return m_AuxiliaryList.end(); }
+ // ----- exclude libs ----- //
+ ExcludeLIBS& excludeLIBS()
+ { return m_ExcludeLIBS; }
+
+ bool isInExcludeLIBS(const Input& pInput) const;
+
+
private:
enum status {
YES,
@@ -389,14 +445,20 @@ private:
bool m_bPrintMap: 1; // --print-map
bool m_bWarnMismatch: 1; // --no-warn-mismatch
bool m_bGCSections: 1; // --gc-sections
+ bool m_bPrintGCSections:1; // --print-gc-sections
bool m_bGenUnwindInfo: 1; // --ld-generated-unwind-info
+ 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;
+ UndefSymList m_UndefSymList; // -u [symbol], --undefined [symbol]
unsigned int m_HashStyle;
std::string m_Filter;
AuxiliaryList m_AuxiliaryList;
+ ExcludeLIBS m_ExcludeLIBS;
};
} // namespace of mcld
diff --git a/include/mcld/LD/BinaryReader.h b/include/mcld/LD/BinaryReader.h
index b713b06..26dab6f 100644
--- a/include/mcld/LD/BinaryReader.h
+++ b/include/mcld/LD/BinaryReader.h
@@ -9,7 +9,6 @@
#ifndef MCLD_LD_BINARYREADER_H
#define MCLD_LD_BINARYREADER_H
#include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
namespace mcld {
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
index 09ac9dc..8733ddb 100644
--- a/include/mcld/LD/BranchIsland.h
+++ b/include/mcld/LD/BranchIsland.h
@@ -9,14 +9,15 @@
#ifndef MCLD_LD_BRANCHISLAND_H
#define MCLD_LD_BRANCHISLAND_H
-#include <llvm/Support/DataTypes.h>
-#include <llvm/ADT/StringRef.h>
#include <mcld/ADT/HashEntry.h>
#include <mcld/ADT/HashTable.h>
#include <mcld/ADT/StringHash.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/LDSymbol.h>
+#include <mcld/Fragment/FragmentRef.h>
#include <mcld/Fragment/Stub.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/ADT/StringRef.h>
#include <string>
namespace mcld {
@@ -133,9 +134,25 @@ private:
{
bool operator() (const Key& KEY1, const Key& KEY2) const
{
- return (KEY1.prototype() == KEY2.prototype()) &&
- (KEY1.symbol() == KEY2.symbol()) &&
- (KEY1.addend() == KEY2.addend());
+ bool res = false;
+ if ((KEY1.prototype() == KEY2.prototype()) &&
+ (KEY1.addend() == KEY2.addend())) {
+
+ if (KEY1.symbol() == KEY2.symbol()) {
+ res = true;
+ } else {
+ // Folded symbols may use the existing stub.
+ if (KEY1.symbol()->hasFragRef() && KEY2.symbol()->hasFragRef()) {
+ const FragmentRef* ref1 = KEY1.symbol()->fragRef();
+ const FragmentRef* ref2 = KEY2.symbol()->fragRef();
+ if ((ref1->offset() == ref2->offset()) &&
+ (ref1->frag()->getOffset() == ref2->frag()->getOffset())) {
+ res = true;
+ }
+ }
+ }
+ }
+ return res;
}
};
diff --git a/include/mcld/LD/BranchIslandFactory.h b/include/mcld/LD/BranchIslandFactory.h
index ef263b0..61a13ad 100644
--- a/include/mcld/LD/BranchIslandFactory.h
+++ b/include/mcld/LD/BranchIslandFactory.h
@@ -27,11 +27,13 @@ class BranchIslandFactory : public GCFactory<BranchIsland, 0>
{
public:
/// ctor
- /// @param pMaxBranchRange - the max branch range of the target backend
+ /// @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
- BranchIslandFactory(uint64_t pMaxBranchRange,
- uint64_t pMaxIslandSize = 65536U);
+ BranchIslandFactory(int64_t pMaxFwdBranchRange,
+ int64_t pMaxBwdBranchRange,
+ size_t pMaxIslandSize = 65536U);
~BranchIslandFactory();
@@ -43,13 +45,15 @@ public:
/// @param pFragment - the fragment needs a branch island
BranchIsland* produce(Fragment& pFragment);
- /// find - find a island for the given fragment
- /// @param pFragment - the fragment needs a branch isladn
- BranchIsland* find(const Fragment& pFragment);
+ /// getIsland - find fwd and bwd islands for the fragment
+ /// @param pFragment - the fragment needs a branch island
+ /// @return - return the pair of <fwd island, bwd island>
+ std::pair<BranchIsland*, BranchIsland*> getIslands(const Fragment& pFragment);
private:
- uint64_t m_MaxBranchRange;
- uint64_t m_MaxIslandSize;
+ int64_t m_MaxFwdBranchRange;
+ int64_t m_MaxBwdBranchRange;
+ size_t m_MaxIslandSize;
};
} // namespace of mcld
diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc
index 539eafb..6bb1461 100644
--- a/include/mcld/LD/DiagCommonKinds.inc
+++ b/include/mcld/LD/DiagCommonKinds.inc
@@ -51,3 +51,4 @@ DIAG(err_invalid_emulation, DiagnosticEngine::Error, "Invalid target emulation:
DIAG(err_cannot_find_scriptfile, DiagnosticEngine::Fatal, "cannot open %0 file %1", "cannot open %0 file %1")
DIAG(err_unsupported_archive, DiagnosticEngine::Error, "Unsupported archive type.", "Unsupported archive type.")
DIAG(unexpected_frag_type, DiagnosticEngine::Unreachable, "Unexpected fragment type `%0' when constructing FG", "Unexpected fragment type `%0' when constructing FG")
+DIAG(debug_print_gc_sections, DiagnosticEngine::Debug, "removing unused section from '%0' in file '%1'", "removing unused section from '%0' in file '%1'")
diff --git a/include/mcld/LD/DiagLayouts.inc b/include/mcld/LD/DiagLayouts.inc
index fac7a32..513ee33 100644
--- a/include/mcld/LD/DiagLayouts.inc
+++ b/include/mcld/LD/DiagLayouts.inc
@@ -4,3 +4,5 @@ DIAG(err_section_not_laid_out, DiagnosticEngine::Unreachable, "section %0 has no
DIAG(warn_duplicate_std_sectmap, DiagnosticEngine::Warning, "Duplicated definition of section map \"from %0 to %0\".", "Duplicated definition of section map \"from %0 to %0\".")
DIAG(warn_rules_check_failed, DiagnosticEngine::Warning, "Illegal section mapping rule: %0 -> %1. (conflict with %2 -> %3)", "Illegal section mapping rule: %0 -> %1. (conflict with %2 -> %3)")
DIAG(err_cannot_merge_section, DiagnosticEngine::Error, "Cannot merge section %0 of %1", "Cannot merge section %0 of %1")
+DIAG(debug_icf_iterations, DiagnosticEngine::Debug, "ICF converged after `%0' iteration(s).", "ICF converged after `%0' iteration(s).")
+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'")
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
index 56cf5e9..1817c4a 100644
--- a/include/mcld/LD/DynObjReader.h
+++ b/include/mcld/LD/DynObjReader.h
@@ -9,7 +9,6 @@
#ifndef MCLD_LD_DYNOBJREADER_H
#define MCLD_LD_DYNOBJREADER_H
#include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
namespace mcld {
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
index b534fc1..0beeecd 100644
--- a/include/mcld/LD/ELFDynObjReader.h
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -9,7 +9,6 @@
#ifndef MCLD_LD_ELFDYNOBJREADER_H
#define MCLD_LD_ELFDYNOBJREADER_H
#include <mcld/LD/DynObjReader.h>
-#include <llvm/Support/system_error.h>
namespace mcld {
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
index 7ab73fd..b83fb01 100644
--- a/include/mcld/LD/ELFObjectWriter.h
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -12,7 +12,6 @@
#include <cassert>
#include <mcld/Support/FileOutputBuffer.h>
-#include <llvm/Support/system_error.h>
namespace mcld {
@@ -39,7 +38,7 @@ public:
~ELFObjectWriter();
- llvm::error_code writeObject(Module& pModule, FileOutputBuffer& pOutput);
+ std::error_code writeObject(Module& pModule, FileOutputBuffer& pOutput);
size_t getOutputSize(const Module& pModule) const;
diff --git a/include/mcld/LD/IdenticalCodeFolding.h b/include/mcld/LD/IdenticalCodeFolding.h
new file mode 100644
index 0000000..e26315e
--- /dev/null
+++ b/include/mcld/LD/IdenticalCodeFolding.h
@@ -0,0 +1,79 @@
+//===- IdenticalCodeFolding.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LD_IDENTICALCODEFOLDING_H
+#define MCLD_LD_IDENTICALCODEFOLDING_H
+
+#include <llvm/ADT/MapVector.h>
+#include <string>
+#include <vector>
+
+namespace mcld {
+class Input;
+class LDSection;
+class LinkerConfig;
+class Module;
+class Relocation;
+class TargetLDBackend;
+
+/** \class IdenticalCodeFolding
+ * \brief Implementation of identical code folding for --icf=[none|all|safe]
+ * @ref Safe ICF: Pointer Safe and Unwinding Aware Identical Code Folding in
+ * Gold, http://research.google.com/pubs/pub36912.html
+ */
+class IdenticalCodeFolding {
+public:
+ typedef std::pair<Input*, size_t> ObjectAndId;
+ typedef llvm::MapVector<LDSection*, ObjectAndId> KeptSections;
+
+private:
+ class FoldingCandidate {
+ public:
+ FoldingCandidate()
+ : sect(NULL), reloc_sect(NULL), obj(NULL)
+ { }
+ FoldingCandidate(LDSection* pCode, LDSection* pReloc, Input* pInput)
+ : sect(pCode), reloc_sect(pReloc), obj(pInput)
+ { }
+
+ void initConstantContent(const TargetLDBackend& pBackend,
+ const IdenticalCodeFolding::KeptSections& pKeptSections);
+ std::string getContentWithVariables(const TargetLDBackend& pBackend,
+ const IdenticalCodeFolding::KeptSections& pKeptSections);
+
+ LDSection* sect;
+ LDSection* reloc_sect;
+ Input* obj;
+ std::string content;
+ std::vector<Relocation*> variable_relocs;
+ };
+
+ typedef std::vector<FoldingCandidate> FoldingCandidates;
+
+public:
+ IdenticalCodeFolding(const LinkerConfig& pConfig,
+ const TargetLDBackend& pBackend,
+ Module& pModule);
+
+ void foldIdenticalCode();
+
+private:
+ void findCandidates(FoldingCandidates& pCandidateList);
+
+ bool matchCandidates(FoldingCandidates& pCandidateList);
+
+private:
+ const LinkerConfig& m_Config;
+ const TargetLDBackend& m_Backend;
+ Module& m_Module;
+ KeptSections m_KeptSections;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
index 41ee0d8..44d3bfc 100644
--- a/include/mcld/LD/LDFileFormat.h
+++ b/include/mcld/LD/LDFileFormat.h
@@ -25,7 +25,8 @@ class LDFileFormat
public:
enum Kind {
Null,
- Regular,
+ TEXT, // Executable regular sections
+ DATA, // Non-executable regular sections
BSS,
NamePool,
Relocation,
@@ -41,7 +42,8 @@ public:
LinkOnce,
StackNote,
Ignore,
- Exclude
+ Exclude,
+ Folded
};
protected:
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
index 5cfb2ef..45c10a8 100644
--- a/include/mcld/LD/LDSymbol.h
+++ b/include/mcld/LD/LDSymbol.h
@@ -105,6 +105,9 @@ public:
const FragmentRef* fragRef() const
{ return m_pFragRef; }
+ FragmentRef* fragRef()
+ { return m_pFragRef; }
+
SizeType size() const
{ return m_pResolveInfo->size(); }
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
index 7ecbd9d..32a8c0a 100644
--- a/include/mcld/LD/ObjectReader.h
+++ b/include/mcld/LD/ObjectReader.h
@@ -9,7 +9,6 @@
#ifndef MCLD_LD_OBJECTREADER_H
#define MCLD_LD_OBJECTREADER_H
#include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
#include <mcld/ADT/HashTable.h>
#include <mcld/ADT/StringHash.h>
#include <mcld/LD/ResolveInfo.h>
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
index d5d124b..b58661a 100644
--- a/include/mcld/LD/ObjectWriter.h
+++ b/include/mcld/LD/ObjectWriter.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#ifndef MCLD_LD_OBJECTWRITER_H
#define MCLD_LD_OBJECTWRITER_H
-#include <llvm/Support/system_error.h>
+#include <system_error>
namespace mcld {
@@ -26,8 +26,8 @@ protected:
public:
virtual ~ObjectWriter();
- virtual llvm::error_code writeObject(Module& pModule,
- FileOutputBuffer& pOutput) = 0;
+ virtual std::error_code writeObject(Module& pModule,
+ FileOutputBuffer& pOutput) = 0;
virtual size_t getOutputSize(const Module& pModule) const = 0;
};
diff --git a/include/mcld/LD/Relocator.h b/include/mcld/LD/Relocator.h
index 8c9dfb6..82bdf8a 100644
--- a/include/mcld/LD/Relocator.h
+++ b/include/mcld/LD/Relocator.h
@@ -115,6 +115,13 @@ public:
/// getSize - get the size of a relocation in bit
virtual Size getSize(Type pType) const = 0;
+ /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+ /// access a function pointer.
+ /// Note: Each target relocator should override this function, or be
+ /// conservative and return true to avoid getting folded.
+ virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+ { return true; }
+
protected:
const LinkerConfig& config() const { return m_Config; }
diff --git a/include/mcld/MC/Input.h b/include/mcld/MC/Input.h
index 1c8ccba..da3a647 100644
--- a/include/mcld/MC/Input.h
+++ b/include/mcld/MC/Input.h
@@ -94,6 +94,12 @@ public:
void setNeeded()
{ m_bNeeded = true; }
+ bool noExport() const
+ { return m_bNoExport; }
+
+ void setNoExport()
+ { m_bNoExport = true; }
+
off_t fileOffset() const
{ return m_fileOffset; }
@@ -126,6 +132,7 @@ private:
sys::fs::Path m_Path;
Attribute *m_pAttr;
bool m_bNeeded;
+ bool m_bNoExport;
off_t m_fileOffset;
MemoryArea* m_pMemArea;
LDContext* m_pContext;
diff --git a/include/mcld/Object/ObjectLinker.h b/include/mcld/Object/ObjectLinker.h
index 0462414..9d54d2e 100644
--- a/include/mcld/Object/ObjectLinker.h
+++ b/include/mcld/Object/ObjectLinker.h
@@ -45,6 +45,9 @@ public:
/// initStdSections - initialize standard sections of the output file.
bool initStdSections();
+ /// addUndefinedSymbols - add symbols set by -u
+ void addUndefinedSymbols();
+
/// normalize - normalize the input files
void normalize();
diff --git a/include/mcld/Script/FlexLexer.h b/include/mcld/Script/FlexLexer.h
index 1e49b83..f09ab20 100644
--- a/include/mcld/Script/FlexLexer.h
+++ b/include/mcld/Script/FlexLexer.h
@@ -141,10 +141,6 @@ public:
protected:
virtual int LexerInput( char* buf, int max_size );
virtual void LexerOutput( const char* buf, int size );
- /* BEGIN ANDROID WAR - Mac builds use size_t until we switch to prebuilts */
- virtual size_t LexerInput( char* buf, size_t max_size );
- virtual void LexerOutput( const char* buf, size_t size );
- /* END ANDROID WAR */
virtual void LexerError( const char* msg );
void yyunput( int c, char* buf_ptr );
diff --git a/include/mcld/Support/CXADemangle.tcc b/include/mcld/Support/CXADemangle.tcc
new file mode 100644
index 0000000..4e66f84
--- /dev/null
+++ b/include/mcld/Support/CXADemangle.tcc
@@ -0,0 +1,4976 @@
+//===- CXADemangle.tcc ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ * Note: This file is imported from cxa_demangle.cpp in llvm libcxxabi.
+ */
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+namespace mcld
+{
+
+enum
+{
+ unknown_error = -4,
+ invalid_args = -3,
+ invalid_mangled_name,
+ memory_alloc_failure,
+ success
+};
+
+template <class C>
+ const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args = 0);
+template <class C>
+ const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_decltype(const char* first, const char* last, C& db);
+
+template <class C>
+void
+print_stack(const C& db)
+{
+ printf("---------\n");
+ printf("names:\n");
+ for (auto& s : db.names)
+ printf("{%s#%s}\n", s.first.c_str(), s.second.c_str());
+ int i = -1;
+ printf("subs:\n");
+ for (auto& v : db.subs)
+ {
+ if (i >= 0)
+ printf("S%i_ = {", i);
+ else
+ printf("S_ = {");
+ for (auto& s : v)
+ printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+ printf("}\n");
+ ++i;
+ }
+ printf("template_param:\n");
+ for (auto& t : db.template_param)
+ {
+ printf("--\n");
+ i = -1;
+ for (auto& v : t)
+ {
+ if (i >= 0)
+ printf("T%i_ = {", i);
+ else
+ printf("T_ = {");
+ for (auto& s : v)
+ printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+ printf("}\n");
+ ++i;
+ }
+ }
+ printf("---------\n\n");
+}
+
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
+{
+ printf("%s: ", msg);
+ for (; first != last; ++first)
+ printf("%c", *first);
+ printf("\n");
+ print_stack(db);
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+parse_number(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ if (*t == 'n')
+ ++t;
+ if (t != last)
+ {
+ if (*t == '0')
+ {
+ first = t+1;
+ }
+ else if ('1' <= *t && *t <= '9')
+ {
+ first = t+1;
+ while (first != last && std::isdigit(*first))
+ ++first;
+ }
+ }
+ }
+ return first;
+}
+
+template <class Float>
+struct float_data;
+
+template <>
+struct float_data<float>
+{
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static constexpr const char* spec = "%af";
+};
+
+constexpr const char* float_data<float>::spec;
+
+template <>
+struct float_data<double>
+{
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static constexpr const char* spec = "%a";
+};
+
+constexpr const char* float_data<double>::spec;
+
+template <>
+struct float_data<long double>
+{
+#if defined(__arm__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static constexpr const char* spec = "%LaL";
+};
+
+constexpr const char* float_data<long double>::spec;
+
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
+{
+ const size_t N = float_data<Float>::mangled_size;
+ if (static_cast<std::size_t>(last - first) > N)
+ {
+ last = first + N;
+ union
+ {
+ Float value;
+ char buf[sizeof(Float)];
+ };
+ const char* t = first;
+ char* e = buf;
+ for (; t != last; ++t, ++e)
+ {
+ if (!isxdigit(*t))
+ return first;
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ *e = static_cast<char>((d1 << 4) + d0);
+ }
+ if (*t == 'E')
+ {
+#if __LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[float_data<Float>::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+ if (static_cast<std::size_t>(n) >= sizeof(num))
+ return first;
+ db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ char c = *first;
+ if (isdigit(c) && first+1 != last)
+ {
+ const char* t = first+1;
+ size_t n = static_cast<size_t>(c - '0');
+ for (c = *t; isdigit(c); c = *t)
+ {
+ n = n * 10 + static_cast<size_t>(c - '0');
+ if (++t == last)
+ return first;
+ }
+ if (static_cast<size_t>(last - t) >= n)
+ {
+ typename C::String r(t, n);
+ if (r.substr(0, 10) == "_GLOBAL__N")
+ db.names.push_back("(anonymous namespace)");
+ else
+ db.names.push_back(std::move(r));
+ first = t + n;
+ }
+ }
+ }
+ return first;
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+
+template <class C>
+const char*
+parse_substitution(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'S')
+ {
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("std::allocator");
+ first += 2;
+ break;
+ case 'b':
+ db.names.push_back("std::basic_string");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("std::string");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("std::istream");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("std::ostream");
+ first += 2;
+ break;
+ case 'd':
+ db.names.push_back("std::iostream");
+ first += 2;
+ break;
+ case '_':
+ if (!db.subs.empty())
+ {
+ for (const auto& n : db.subs.front())
+ db.names.push_back(n);
+ first += 2;
+ }
+ break;
+ default:
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < db.subs.size())
+ {
+ for (const auto& n : db.subs[sub])
+ db.names.push_back(n);
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <builtin-type> ::= v # void
+// ::= w # wchar_t
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= n # __int128
+// ::= o # unsigned __int128
+// ::= f # float
+// ::= d # double
+// ::= e # long double, __float80
+// ::= g # __float128
+// ::= z # ellipsis
+// ::= Dd # IEEE 754r decimal floating point (64 bits)
+// ::= De # IEEE 754r decimal floating point (128 bits)
+// ::= Df # IEEE 754r decimal floating point (32 bits)
+// ::= Dh # IEEE 754r half-precision floating point (16 bits)
+// ::= Di # char32_t
+// ::= Ds # char16_t
+// ::= Da # auto (in dependent new-expressions)
+// ::= Dc # decltype(auto)
+// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+// ::= u <source-name> # vendor extended type
+
+template <class C>
+const char*
+parse_builtin_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'v':
+ db.names.push_back("void");
+ ++first;
+ break;
+ case 'w':
+ db.names.push_back("wchar_t");
+ ++first;
+ break;
+ case 'b':
+ db.names.push_back("bool");
+ ++first;
+ break;
+ case 'c':
+ db.names.push_back("char");
+ ++first;
+ break;
+ case 'a':
+ db.names.push_back("signed char");
+ ++first;
+ break;
+ case 'h':
+ db.names.push_back("unsigned char");
+ ++first;
+ break;
+ case 's':
+ db.names.push_back("short");
+ ++first;
+ break;
+ case 't':
+ db.names.push_back("unsigned short");
+ ++first;
+ break;
+ case 'i':
+ db.names.push_back("int");
+ ++first;
+ break;
+ case 'j':
+ db.names.push_back("unsigned int");
+ ++first;
+ break;
+ case 'l':
+ db.names.push_back("long");
+ ++first;
+ break;
+ case 'm':
+ db.names.push_back("unsigned long");
+ ++first;
+ break;
+ case 'x':
+ db.names.push_back("long long");
+ ++first;
+ break;
+ case 'y':
+ db.names.push_back("unsigned long long");
+ ++first;
+ break;
+ case 'n':
+ db.names.push_back("__int128");
+ ++first;
+ break;
+ case 'o':
+ db.names.push_back("unsigned __int128");
+ ++first;
+ break;
+ case 'f':
+ db.names.push_back("float");
+ ++first;
+ break;
+ case 'd':
+ db.names.push_back("double");
+ ++first;
+ break;
+ case 'e':
+ db.names.push_back("long double");
+ ++first;
+ break;
+ case 'g':
+ db.names.push_back("__float128");
+ ++first;
+ break;
+ case 'z':
+ db.names.push_back("...");
+ ++first;
+ break;
+ case 'u':
+ {
+ const char*t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ first = t;
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'd':
+ db.names.push_back("decimal64");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("decimal128");
+ first += 2;
+ break;
+ case 'f':
+ db.names.push_back("decimal32");
+ first += 2;
+ break;
+ case 'h':
+ db.names.push_back("decimal16");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("char32_t");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("char16_t");
+ first += 2;
+ break;
+ case 'a':
+ db.names.push_back("auto");
+ first += 2;
+ break;
+ case 'c':
+ db.names.push_back("decltype(auto)");
+ first += 2;
+ break;
+ case 'n':
+ db.names.push_back("std::nullptr_t");
+ first += 2;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+
+const char*
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
+{
+ cv = 0;
+ if (first != last)
+ {
+ if (*first == 'r')
+ {
+ cv |= 4;
+ ++first;
+ }
+ if (*first == 'V')
+ {
+ cv |= 2;
+ ++first;
+ }
+ if (*first == 'K')
+ {
+ cv |= 1;
+ ++first;
+ }
+ }
+ return first;
+}
+
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
+template <class C>
+const char*
+parse_template_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'T')
+ {
+ if (first[1] == '_')
+ {
+ if (db.template_param.empty())
+ return first;
+ if (!db.template_param.back().empty())
+ {
+ for (auto& t : db.template_param.back().front())
+ db.names.push_back(t);
+ first += 2;
+ }
+ else
+ {
+ db.names.push_back("T_");
+ first += 2;
+ db.fix_forward_references = true;
+ }
+ }
+ else if (isdigit(first[1]))
+ {
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
+ {
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
+ }
+ if (t == last || *t != '_' || db.template_param.empty())
+ return first;
+ ++sub;
+ if (sub < db.template_param.back().size())
+ {
+ for (auto& temp : db.template_param.back()[sub])
+ db.names.push_back(temp);
+ first = t+1;
+ }
+ else
+ {
+ db.names.push_back(typename C::String(first, t+1));
+ first = t+1;
+ db.fix_forward_references = true;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// cc <type> <expression> # const_cast<type> (expression)
+
+template <class C>
+const char*
+parse_const_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dc <type> <expression> # dynamic_cast<type> (expression)
+
+template <class C>
+const char*
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+
+template <class C>
+const char*
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sc <type> <expression> # static_cast<type> (expression)
+
+template <class C>
+const char*
+parse_static_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sp <expression> # pack expansion
+
+template <class C>
+const char*
+parse_pack_expansion(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ return first;
+}
+
+// st <type> # sizeof (a type)
+
+template <class C>
+const char*
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sz <expr> # sizeof (a expression)
+
+template <class C>
+const char*
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <template-param> # size of a parameter pack
+
+template <class C>
+const char*
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+ {
+ size_t k0 = db.names.size();
+ const char* t = parse_template_param(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ typename C::String tmp("sizeof...(");
+ size_t k = k0;
+ if (k != k1)
+ {
+ tmp += db.names[k].move_full();
+ for (++k; k != k1; ++k)
+ tmp += ", " + db.names[k].move_full();
+ }
+ tmp += ")";
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ db.names.push_back(std::move(tmp));
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+
+template <class C>
+const char*
+parse_function_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && *first == 'f')
+ {
+ if (first[1] == 'p')
+ {
+ unsigned cv;
+ const char* t = parse_cv_qualifiers(first+2, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ else if (first[1] == 'L')
+ {
+ unsigned cv;
+ const char* t0 = parse_number(first+2, last);
+ if (t0 != last && *t0 == 'p')
+ {
+ ++t0;
+ const char* t = parse_cv_qualifiers(t0, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// sZ <function-param> # size of a function parameter pack
+
+template <class C>
+const char*
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ {
+ const char* t = parse_function_param(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+ {
+ const char* t;
+ if (first[1] == 'e')
+ t = parse_expression(first+2, last, db);
+ else
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// tw <expression> # throw expression
+
+template <class C>
+const char*
+parse_throw_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "throw " + db.names.back().move_full();
+ first = t;
+ }
+ }
+ return first;
+}
+
+// ds <expression> <expression> # expr.*expr
+
+template <class C>
+const char*
+parse_dot_star_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += ".*" + expr;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+template <class C>
+const char*
+parse_simple_id(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ first = t1;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_unresolved_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ switch (*first)
+ {
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first && k1 == k0 + 1)
+ {
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ else
+ {
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ }
+ break;
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ break;
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
+ {
+ if (last - first > 2 && first[1] == 't')
+ {
+ t = parse_unqualified_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+
+template <class C>
+const char*
+parse_destructor_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "~");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= on <operator-name> <template-args> # unresolved operator template-id
+// ::= dn <destructor-name> # destructor or pseudo-destructor;
+// # e.g. ~X or ~X<N-1>
+
+template <class C>
+const char*
+parse_base_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+ {
+ if (first[0] == 'o')
+ {
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <unresolved-qualifier-level> ::= <simple-id>
+
+template <class C>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
+{
+ return parse_simple_id(first, last, db);
+}
+
+// <unresolved-name>
+// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ global = true;
+ t += 2;
+ }
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
+ {
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// dt <expression> <unresolved-name> # expr.name
+
+template <class C>
+const char*
+parse_dot_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_unresolved_name(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "." + name;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// cl <expression>+ E # call
+
+template <class C>
+const char*
+parse_call_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (t == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += db.names.back().second;
+ db.names.back().second = typename C::String();
+ db.names.back().first.append("(");
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_expr)
+ {
+ db.names.back().first.append(", ");
+ first_expr = false;
+ }
+ db.names.back().first.append(tmp);
+ }
+ t = t1;
+ }
+ ++t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+
+template <class C>
+const char*
+parse_new_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
+ {
+ bool is_array = t[1] == 'a';
+ t += 2;
+ if (t == last)
+ return first;
+ bool has_expr_list = false;
+ bool first_expr = true;
+ while (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ has_expr_list = true;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ ++t;
+ const char* t1 = parse_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ bool has_init = false;
+ if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+ {
+ t += 2;
+ has_init = true;
+ first_expr = true;
+ while (*t != 'E')
+ {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ if (*t != 'E')
+ return first;
+ typename C::String init_list;
+ if (has_init)
+ {
+ if (db.names.empty())
+ return first;
+ init_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ if (db.names.empty())
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ typename C::String expr_list;
+ if (has_expr_list)
+ {
+ if (db.names.empty())
+ return first;
+ expr_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ typename C::String r;
+ if (parsed_gs)
+ r = "::";
+ if (is_array)
+ r += "[] ";
+ else
+ r += " ";
+ if (has_expr_list)
+ r += "(" + expr_list + ") ";
+ r += type;
+ if (has_init)
+ r += " (" + init_list + ")";
+ db.names.push_back(std::move(r));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+
+template <class C>
+const char*
+parse_conversion_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2 && t != last)
+ {
+ if (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ db.names.emplace_back();
+ else
+ {
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ ++t;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pt <expression> <expression> # expr->name
+
+template <class C>
+const char*
+parse_arrow_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "->";
+ db.names.back().first += tmp;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+
+template <class C>
+const char*
+parse_function_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'F')
+ {
+ const char* t = first+1;
+ if (t != last)
+ {
+ bool externC = false;
+ if (*t == 'Y')
+ {
+ externC = true;
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ typename C::String sig("(");
+ int ref_qual = 0;
+ while (true)
+ {
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (*t == 'E')
+ {
+ ++t;
+ break;
+ }
+ if (*t == 'v')
+ {
+ ++t;
+ continue;
+ }
+ if (*t == 'R' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 1;
+ ++t;
+ continue;
+ }
+ if (*t == 'O' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 2;
+ ++t;
+ continue;
+ }
+ size_t k0 = db.names.size();
+ t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 == t || t1 == last)
+ return first;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (sig.size() > 1)
+ sig += ", ";
+ sig += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ t = t1;
+ }
+ sig += ")";
+ switch (ref_qual)
+ {
+ case 1:
+ sig += " &";
+ break;
+ case 2:
+ sig += " &&";
+ break;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " ";
+ db.names.back().second.insert(0, sig);
+ first = t;
+ }
+ }
+ }
+ return first;
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+template <class C>
+const char*
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'M')
+ {
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto func = std::move(db.names.back());
+ db.names.pop_back();
+ auto class_type = std::move(db.names.back());
+ if (func.second.front() == '(')
+ {
+ db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+ db.names.back().second = ")" + std::move(func.second);
+ }
+ else
+ {
+ db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+ db.names.back().second = std::move(func.second);
+ }
+ first = t2;
+ }
+ }
+ }
+ return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+
+template <class C>
+const char*
+parse_array_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'A' && first+1 != last)
+ {
+ if (first[1] == '_')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " []");
+ first = t;
+ }
+ }
+ else if ('1' <= first[1] && first[1] <= '9')
+ {
+ const char* t = parse_number(first+1, last);
+ if (t != last && *t == '_')
+ {
+ const char* t2 = parse_type(t+1, last, db);
+ if (t2 != t+1)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_expression(first+1, last, db);
+ if (t != first+1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_type(++t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = std::move(db.names.back());
+ db.names.pop_back();
+ auto expr = std::move(db.names.back());
+ db.names.back().first = std::move(type.first);
+ if (type.second.substr(0, 2) == " [")
+ type.second.erase(0, 1);
+ db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+
+template <class C>
+const char*
+parse_decltype(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'D')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'T':
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+
+template <class C>
+const char*
+parse_vector_type(const char* first, const char* last, C& db)
+{
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+ {
+ if ('1' <= first[2] && first[2] <= '9')
+ {
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
+ const char* num = first + 2;
+ size_t sz = static_cast<size_t>(t - num);
+ if (++t != last)
+ {
+ if (*t != 'p')
+ {
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+ first = t1;
+ }
+ }
+ else
+ {
+ ++t;
+ db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ typename C::String num;
+ const char* t1 = first+2;
+ if (*t1 != '_')
+ {
+ const char* t = parse_expression(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ num = db.names.back().move_full();
+ db.names.pop_back();
+ t1 = t;
+ }
+ }
+ if (t1 != last && *t1 == '_' && ++t1 != last)
+ {
+ const char* t = parse_type(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + num + "]";
+ first = t;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <type> ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= <substitution>
+// ::= <CV-qualifiers> <type>
+// ::= P <type> # pointer-to
+// ::= R <type> # reference-to
+// ::= O <type> # rvalue reference-to (C++0x)
+// ::= C <type> # complex pair (C 2000)
+// ::= G <type> # imaginary (C 2000)
+// ::= Dp <type> # pack expansion (C++0x)
+// ::= U <source-name> <type> # vendor extended type qualifier
+// extension := U <objc-name> <objc-type> # objc-type<identifier>
+// extension := <vector-type> # <vector-type> starts with Dv
+
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+
+template <class C>
+const char*
+parse_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ unsigned cv = 0;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
+ {
+ bool is_function = *t == 'F';
+ size_t k0 = db.names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 != t)
+ {
+ if (is_function)
+ db.subs.pop_back();
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (is_function)
+ {
+ size_t p = db.names[k].second.size();
+ if (db.names[k].second[p-2] == '&')
+ p -= 3;
+ else if (db.names[k].second.back() == '&')
+ p -= 2;
+ if (cv & 1)
+ {
+ db.names[k].second.insert(p, " const");
+ p += 6;
+ }
+ if (cv & 2)
+ {
+ db.names[k].second.insert(p, " volatile");
+ p += 9;
+ }
+ if (cv & 4)
+ db.names[k].second.insert(p, " restrict");
+ }
+ else
+ {
+ if (cv & 1)
+ db.names[k].first.append(" const");
+ if (cv & 2)
+ db.names[k].first.append(" volatile");
+ if (cv & 4)
+ db.names[k].first.append(" restrict");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" complex");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'G':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" imaginary");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'O':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'P':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+ {
+ db.names[k].first.append("*");
+ }
+ else
+ {
+ db.names[k].first.replace(0, 11, "id");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'R':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ if (db.try_to_parse_template_args && k1 == k0+1)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t = t1;
+ }
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'U':
+ if (first+1 != last)
+ {
+ t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.back().first.substr(0, 9) != "objcproto")
+ {
+ db.names.back() = type + " " + db.names.back().move_full();
+ }
+ else
+ {
+ auto proto = db.names.back().move_full();
+ db.names.pop_back();
+ t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+ if (t != proto.data() + 9)
+ {
+ db.names.back() = type + "<" + db.names.back().move_full() + ">";
+ }
+ else
+ {
+ db.names.push_back(type + " " + proto);
+ }
+ }
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t2;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ else
+ {
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = parse_template_args(first, last, db);
+ if (t != first)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto template_args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += template_args;
+ // Need to create substitution for <template-template-param> <template-args>
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ first = t;
+ return first;
+ }
+ break;
+ }
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ switch (first[0])
+ {
+ case 'a':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator&&");
+ first += 2;
+ break;
+ case 'd':
+ case 'n':
+ db.names.push_back("operator&");
+ first += 2;
+ break;
+ case 'N':
+ db.names.push_back("operator&=");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'c':
+ switch (first[1])
+ {
+ case 'l':
+ db.names.push_back("operator()");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator,");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("operator~");
+ first += 2;
+ break;
+ case 'v':
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+#if UPSTREAM_CODE
+ db.parsed_ctor_dtor_cv = true;
+#else
+ db.parsed_ctor_dtor_cv = false;
+#endif
+ first = t;
+ }
+ }
+ break;
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator delete[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator delete");
+ first += 2;
+ break;
+ case 'v':
+ db.names.push_back("operator/");
+ first += 2;
+ break;
+ case 'V':
+ db.names.push_back("operator/=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'e':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator^");
+ first += 2;
+ break;
+ case 'O':
+ db.names.push_back("operator^=");
+ first += 2;
+ break;
+ case 'q':
+ db.names.push_back("operator==");
+ first += 2;
+ break;
+ }
+ break;
+ case 'g':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator>=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator>");
+ first += 2;
+ break;
+ }
+ break;
+ case 'i':
+ if (first[1] == 'x')
+ {
+ db.names.push_back("operator[]");
+ first += 2;
+ }
+ break;
+ case 'l':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator<=");
+ first += 2;
+ break;
+ case 'i':
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator\"\" ");
+ first = t;
+ }
+ }
+ break;
+ case 's':
+ db.names.push_back("operator<<");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator<<=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator<");
+ first += 2;
+ break;
+ }
+ break;
+ case 'm':
+ switch (first[1])
+ {
+ case 'i':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 'I':
+ db.names.push_back("operator-=");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator*=");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator--");
+ first += 2;
+ break;
+ }
+ break;
+ case 'n':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator new[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator!=");
+ first += 2;
+ break;
+ case 'g':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator!");
+ first += 2;
+ break;
+ case 'w':
+ db.names.push_back("operator new");
+ first += 2;
+ break;
+ }
+ break;
+ case 'o':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator||");
+ first += 2;
+ break;
+ case 'r':
+ db.names.push_back("operator|");
+ first += 2;
+ break;
+ case 'R':
+ db.names.push_back("operator|=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator->*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator+=");
+ first += 2;
+ break;
+ case 'p':
+ db.names.push_back("operator++");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator->");
+ first += 2;
+ break;
+ }
+ break;
+ case 'q':
+ if (first[1] == 'u')
+ {
+ db.names.push_back("operator?");
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator%");
+ first += 2;
+ break;
+ case 'M':
+ db.names.push_back("operator%=");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator>>");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator>>=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+ const char* t = parse_number(first, last);
+ if (t != first && t != last && *t == 'E')
+ {
+ if (lit.size() > 3)
+ db.names.push_back("(" + lit + ")");
+ else
+ db.names.emplace_back();
+ if (*first == 'n')
+ {
+ db.names.back().first += '-';
+ ++first;
+ }
+ db.names.back().first.append(first, t);
+ if (lit.size() <= 3)
+ db.names.back().first += lit;
+ first = t+1;
+ }
+ return first;
+}
+
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
+ {
+ const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
+ {
+ case '0':
+ db.names.push_back("false");
+ first += 4;
+ break;
+ case '1':
+ db.names.push_back("true");
+ first += 4;
+ break;
+ }
+ }
+ break;
+ case 'c':
+ {
+ const char* t = parse_integer_literal(first+2, last, "char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'a':
+ {
+ const char* t = parse_integer_literal(first+2, last, "signed char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'h':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 's':
+ {
+ const char* t = parse_integer_literal(first+2, last, "short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 't':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'i':
+ {
+ const char* t = parse_integer_literal(first+2, last, "", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'j':
+ {
+ const char* t = parse_integer_literal(first+2, last, "u", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'l':
+ {
+ const char* t = parse_integer_literal(first+2, last, "l", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'm':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ul", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'x':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ll", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'y':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ull", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'n':
+ {
+ const char* t = parse_integer_literal(first+2, last, "__int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'o':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'f':
+ {
+ const char* t = parse_floating_number<float>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'd':
+ {
+ const char* t = parse_floating_number<double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'e':
+ {
+ const char* t = parse_floating_number<long double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = parse_encoding(first+3, last, db);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1 && t != last)
+ {
+ if (*t != 'E')
+ {
+ const char* n = t;
+ for (; n != last && isdigit(*n); ++n)
+ ;
+ if (n != t && n != last && *n == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+ first = n+1;
+ break;
+ }
+ }
+ else
+ {
+ first = t+1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+template <class String>
+String
+base_name(String& s)
+{
+ if (s.empty())
+ return s;
+ if (s == "std::string")
+ {
+ s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+ return "basic_string";
+ }
+ if (s == "std::istream")
+ {
+ s = "std::basic_istream<char, std::char_traits<char> >";
+ return "basic_istream";
+ }
+ if (s == "std::ostream")
+ {
+ s = "std::basic_ostream<char, std::char_traits<char> >";
+ return "basic_ostream";
+ }
+ if (s == "std::iostream")
+ {
+ s = "std::basic_iostream<char, std::char_traits<char> >";
+ return "basic_iostream";
+ }
+ const char* const pf = s.data();
+ const char* pe = pf + s.size();
+ if (pe[-1] == '>')
+ {
+ unsigned c = 1;
+ while (true)
+ {
+ if (--pe == pf)
+ return String();
+ if (pe[-1] == '<')
+ {
+ if (--c == 0)
+ {
+ --pe;
+ break;
+ }
+ }
+ else if (pe[-1] == '>')
+ ++c;
+ }
+ }
+ const char* p0 = pe - 1;
+ for (; p0 != pf; --p0)
+ {
+ if (*p0 == ':')
+ {
+ ++p0;
+ break;
+ }
+ }
+ return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+
+template <class C>
+const char*
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
+{
+ if (last-first >= 2 && !db.names.empty())
+ {
+ switch (first[0])
+ {
+ case 'C':
+ switch (first[1])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back(base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ case 'D':
+ switch (first[1])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back("~" + base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+
+template <class C>
+const char*
+parse_unnamed_type_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2 && first[0] == 'U')
+ {
+ char type = first[1];
+ switch (type)
+ {
+ case 't':
+ {
+ db.names.push_back(typename C::String("'unnamed"));
+ const char* t0 = first+2;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.append(t0, t1);
+ t0 = t1;
+ }
+ db.names.back().first.push_back('\'');
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ case 'l':
+ {
+ db.names.push_back(typename C::String("'lambda'("));
+ const char* t0 = first+2;
+ if (first[2] == 'v')
+ {
+ db.names.back().first += ')';
+ ++t0;
+ }
+ else
+ {
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append(tmp);
+ t0 = t1;
+ while (true)
+ {
+ t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ break;
+ if (db.names.size() < 2)
+ return first;
+ tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ }
+ t0 = t1;
+ }
+ db.names.back().first.append(")");
+ }
+ if (t0 == last || *t0 != 'E')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ ++t0;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+ t0 = t1;
+ }
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+template <class C>
+const char*
+parse_unqualified_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ }
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// az <expression> # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = op + "(" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ auto& nm = db.names.back().first;
+ nm.clear();
+ if (op == ">")
+ nm += '(';
+ nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+ if (op == ">")
+ nm += ')';
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= sz <expression> # sizeof (an expression)
+// ::= at <type> # alignof (a type)
+// ::= az <expression> # alignof (an expression)
+// ::= nx <expression> # noexcept (expression)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= sp <expression> # pack expansion
+// ::= tw <expression> # throw expression
+// ::= tr # throw with no operand (rethrow)
+// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+// # freestanding dependent name (e.g., T::x),
+// # objectless nonstatic member reference
+// ::= <expr-primary>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ switch (*t)
+ {
+ case 'L':
+ first = parse_expr_primary(first, last, db);
+ break;
+ case 'T':
+ first = parse_template_param(first, last, db);
+ break;
+ case 'f':
+ first = parse_function_param(first, last, db);
+ break;
+ case 'a':
+ switch (t[1])
+ {
+ case 'a':
+ t = parse_binary_expression(first+2, last, "&&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'd':
+ t = parse_prefix_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'n':
+ t = parse_binary_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'N':
+ t = parse_binary_expression(first+2, last, "&=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_alignof_type(first, last, db);
+ break;
+ case 'z':
+ first = parse_alignof_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'c':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_const_cast_expr(first, last, db);
+ break;
+ case 'l':
+ first = parse_call_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, ",", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'o':
+ t = parse_prefix_expression(first+2, last, "~", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'v':
+ first = parse_conversion_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'd':
+ switch (t[1])
+ {
+ case 'a':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete[] " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'c':
+ first = parse_dynamic_cast_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_prefix_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 's':
+ first = parse_dot_star_expr(first, last, db);
+ break;
+ case 't':
+ first = parse_dot_expr(first, last, db);
+ break;
+ case 'v':
+ t = parse_binary_expression(first+2, last, "/", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'V':
+ t = parse_binary_expression(first+2, last, "/=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'e':
+ switch (t[1])
+ {
+ case 'o':
+ t = parse_binary_expression(first+2, last, "^", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'O':
+ t = parse_binary_expression(first+2, last, "^=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'q':
+ t = parse_binary_expression(first+2, last, "==", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'g':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, ">=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, ">", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'i':
+ if (t[1] == 'x')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ")[" + op2 + "]";
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'l':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, "<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, "<<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "<<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, "<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'm':
+ switch (t[1])
+ {
+ case 'i':
+ t = parse_binary_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'I':
+ t = parse_binary_expression(first+2, last, "-=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "*=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'm':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "--", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")--";
+ first = t1;
+ }
+ }
+ break;
+ }
+ break;
+ case 'n':
+ switch (t[1])
+ {
+ case 'a':
+ case 'w':
+ first = parse_new_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_binary_expression(first+2, last, "!=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'g':
+ t = parse_prefix_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_prefix_expression(first+2, last, "!", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'x':
+ t = parse_noexcept_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'o':
+ switch (t[1])
+ {
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 'o':
+ t = parse_binary_expression(first+2, last, "||", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'r':
+ t = parse_binary_expression(first+2, last, "|", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'R':
+ t = parse_binary_expression(first+2, last, "|=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'p':
+ switch (t[1])
+ {
+ case 'm':
+ t = parse_binary_expression(first+2, last, "->*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "+=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'p':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "++", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")++";
+ first = t1;
+ }
+ }
+ break;
+ case 's':
+ t = parse_prefix_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_arrow_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'q':
+ if (t[1] == 'u')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ const char* t3 = parse_expression(t2, last, db);
+ if (t3 != t2)
+ {
+ if (db.names.size() < 3)
+ return first;
+ auto op3 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+ first = t3;
+ }
+ else
+ {
+ db.names.pop_back();
+ db.names.pop_back();
+ }
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'r':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_reinterpret_cast_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, "%", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'M':
+ t = parse_binary_expression(first+2, last, "%=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, ">>", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, ">>=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 's':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_static_cast_expr(first, last, db);
+ break;
+ case 'p':
+ first = parse_pack_expansion(first, last, db);
+ break;
+ case 'r':
+ return parse_unresolved_name(first, last, db);
+ case 't':
+ first = parse_sizeof_type_expr(first, last, db);
+ break;
+ case 'z':
+ first = parse_sizeof_expr_expr(first, last, db);
+ break;
+ case 'Z':
+ if (last - t >= 3)
+ {
+ switch (t[2])
+ {
+ case 'T':
+ first = parse_sizeof_param_pack_expr(first, last, db);
+ break;
+ case 'f':
+ first = parse_sizeof_function_param_pack_expr(first, last, db);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ first = parse_typeid_expr(first, last, db);
+ break;
+ case 'r':
+ db.names.push_back("throw");
+ first += 2;
+ break;
+ case 'w':
+ first = parse_throw_expr(first, last, db);
+ break;
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parse_unresolved_name(first, last, db);
+ }
+ }
+ return first;
+}
+
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+
+template <class C>
+const char*
+parse_template_arg(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
+ {
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ first = t+1;
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
+ }
+ else
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+
+template <class C>
+const char*
+parse_template_args(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2 && *first == 'I')
+ {
+ if (db.tag_templates)
+ db.template_param.back().clear();
+ const char* t = first+1;
+ typename C::String args("<");
+ while (*t != 'E')
+ {
+ if (db.tag_templates)
+ db.template_param.emplace_back(db.names.get_allocator());
+ size_t k0 = db.names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.names.size();
+ if (db.tag_templates)
+ db.template_param.pop_back();
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.tag_templates)
+ {
+ db.template_param.back().emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.template_param.back().back().push_back(db.names[k]);
+ }
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (args.size() > 1)
+ args += ", ";
+ args += db.names[k].move_full();
+ }
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ t = t1;
+ }
+ first = t + 1;
+ if (args.back() != '>')
+ args += ">";
+ else
+ args += " >";
+ db.names.push_back(std::move(args));
+
+ }
+ return first;
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::= # empty
+// ::= <substitution>
+// ::= <prefix> <data-member-prefix>
+// extension ::= L
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_nested_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'N')
+ {
+ unsigned cv;
+ const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+ if (t0 == last)
+ return first;
+ db.ref = 0;
+ if (*t0 == 'R')
+ {
+ db.ref = 1;
+ ++t0;
+ }
+ else if (*t0 == 'O')
+ {
+ db.ref = 2;
+ ++t0;
+ }
+ db.names.emplace_back();
+ if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+ {
+ t0 += 2;
+ db.names.back().first = "std";
+ }
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ bool pop_subs = false;
+ bool component_ends_with_template_args = false;
+ while (*t0 != 'E')
+ {
+ component_ends_with_template_args = false;
+ const char* t1;
+ switch (*t0)
+ {
+ case 'S':
+ if (t0 + 1 != last && t0[1] == 't')
+ goto do_parse_unqualified_name;
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ {
+ db.names.back().first += "::" + name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ else
+ db.names.back().first = name;
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'T':
+ t1 = parse_template_param(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'D':
+ if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+ goto do_parse_unqualified_name;
+ t1 = parse_decltype(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'I':
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ component_ends_with_template_args = true;
+ }
+ else
+ return first;
+ break;
+ case 'L':
+ if (++t0 == last)
+ return first;
+ break;
+ default:
+ do_parse_unqualified_name:
+ t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ }
+ }
+ first = t0 + 1;
+ db.cv = cv;
+ if (pop_subs && !db.subs.empty())
+ db.subs.pop_back();
+ if (ends_with_template_args)
+ *ends_with_template_args = component_ends_with_template_args;
+ }
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+
+
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+ // parse but ignore discriminator
+ if (first != last)
+ {
+ if (*first == '_')
+ {
+ const char* t1 = first+1;
+ if (t1 != last)
+ {
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
+ {
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
+ }
+ }
+ }
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = parse_encoding(first+1, last, db);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ switch (*t)
+ {
+ case 's':
+ first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::string literal");
+ break;
+ case 'd':
+ if (++t != last)
+ {
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ t = t1 + 1;
+ t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ first = t1;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ default:
+ {
+ const char* t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ }
+ else
+ db.names.pop_back();
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ switch (*t0)
+ {
+ case 'N':
+ {
+ const char* t1 = parse_nested_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ case 'Z':
+ {
+ const char* t1 = parse_local_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ default:
+ {
+ const char* t1 = parse_unscoped_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ else // <unscoped-name>
+ first = t1;
+ }
+ else
+ { // try <substitution> <template-args>
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+// # non-virtual base override
+//
+// <v-offset> ::= <offset number> _ <virtual offset number>
+// # virtual base override, with vcall offset
+
+const char*
+parse_call_offset(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'h':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ first = t + 1;
+ }
+ break;
+ case 'v':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_number(++t, last);
+ if (t2 != t && t2 != last && *t2 == '_')
+ first = t2 + 1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+
+template <class C>
+const char*
+parse_special_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'T':
+ switch (first[1])
+ {
+ case 'V':
+ // TV <type> # virtual table
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "vtable for ");
+ first = t;
+ }
+ break;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "VTT for ");
+ first = t;
+ }
+ break;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo for ");
+ first = t;
+ }
+ break;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo name for ");
+ first = t;
+ }
+ break;
+ case 'c':
+ // Tc <call-offset> <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+2, last);
+ if (t0 == first+2)
+ break;
+ const char* t1 = parse_call_offset(t0, last);
+ if (t1 == t0)
+ break;
+ t = parse_encoding(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "covariant return thunk to ");
+ first = t;
+ }
+ }
+ break;
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t0 = parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = parse_type(++t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto left = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first = "construction vtable for " +
+ std::move(left) + "-in-" +
+ db.names.back().move_full();
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ // T <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+1, last);
+ if (t0 == first+1)
+ break;
+ t = parse_encoding(t0, last, db);
+ if (t != t0)
+ {
+ if (db.names.empty())
+ return first;
+ if (first[2] == 'v')
+ {
+ db.names.back().first.insert(0, "virtual thunk to ");
+ first = t;
+ }
+ else
+ {
+ db.names.back().first.insert(0, "non-virtual thunk to ");
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1])
+ {
+ case 'V':
+ // GV <object name> # Guard variable for one-time initialization
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "guard variable for ");
+ first = t;
+ }
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "reference temporary for ");
+ first = t;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+
+template <class C>
+const char*
+parse_encoding(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
+ switch (*first)
+ {
+ case 'G':
+ case 'T':
+ first = parse_special_name(first, last, db);
+ break;
+ default:
+ {
+ bool ends_with_template_args = false;
+ const char* t = parse_name(first, last, db,
+ &ends_with_template_args);
+ unsigned cv = db.cv;
+ unsigned ref = db.ref;
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
+ {
+ save_value<bool> sb2(db.tag_templates);
+ db.tag_templates = false;
+ const char* t2;
+ typename C::String ret2;
+ if (db.names.empty())
+ return first;
+ const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
+ if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
+ {
+ t2 = parse_type(t, last, db);
+ if (t2 == t)
+ return first;
+ if (db.names.size() < 2)
+ return first;
+ auto ret1 = std::move(db.names.back().first);
+ ret2 = std::move(db.names.back().second);
+ if (ret2.empty())
+ ret1 += ' ';
+ db.names.pop_back();
+ db.names.back().first.insert(0, ret1);
+ t = t2;
+ }
+ db.names.back().first += '(';
+ if (t != last && *t == 'v')
+ {
+ ++t;
+ }
+ else
+ {
+ bool first_arg = true;
+ while (true)
+ {
+ size_t k0 = db.names.size();
+ t2 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t2 == t)
+ break;
+ if (k1 > k0)
+ {
+ typename C::String tmp;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (!tmp.empty())
+ tmp += ", ";
+ tmp += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_arg)
+ db.names.back().first += ", ";
+ else
+ first_arg = false;
+ db.names.back().first += tmp;
+ }
+ }
+ t = t2;
+ }
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += ')';
+ if (cv & 1)
+ db.names.back().first.append(" const");
+ if (cv & 2)
+ db.names.back().first.append(" volatile");
+ if (cv & 4)
+ db.names.back().first.append(" restrict");
+ if (ref == 1)
+ db.names.back().first.append(" &");
+ else if (ref == 2)
+ db.names.back().first.append(" &&");
+ db.names.back().first += ret2;
+ first = t;
+ }
+ else
+ first = t;
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+
+template <class C>
+const char*
+parse_block_invoke(const char* first, const char* last, C& db)
+{
+ if (last - first >= 13)
+ {
+ const char test[] = "_block_invoke";
+ const char* t = first;
+ for (int i = 0; i < 13; ++i, ++t)
+ {
+ if (*t != test[i])
+ return first;
+ }
+ if (t != last)
+ {
+ if (*t == '_')
+ {
+ // must have at least 1 decimal digit
+ if (++t == last || !std::isdigit(*t))
+ return first;
+ ++t;
+ }
+ // parse zero or more digits
+ while (t != last && isdigit(*t))
+ ++t;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "invocation function for block in ");
+ first = t;
+ }
+ return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+template <class C>
+const char*
+parse_dot_suffix(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == '.')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " (" + typename C::String(first, last) + ")";
+ first = last;
+ }
+ return first;
+}
+
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
+// <mangled-name> ::= _Z<encoding>
+// ::= <type>
+
+template <class C>
+void
+demangle(const char* first, const char* last, C& db, int& status)
+{
+ if (first >= last)
+ {
+ status = invalid_mangled_name;
+ return;
+ }
+ if (*first == '_')
+ {
+ if (last - first >= 4)
+ {
+ if (first[1] == 'Z')
+ {
+ const char* t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == '.')
+ t = parse_dot_suffix(t, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ {
+ const char* t = parse_encoding(first+4, last, db);
+ if (t != first+4 && t != last)
+ {
+ const char* t1 = parse_block_invoke(t, last, db);
+ if (t1 != last)
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ {
+ const char* t = parse_type(first, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ if (status == success && db.names.empty())
+ status = invalid_mangled_name;
+}
+
+template <std::size_t N>
+class arena
+{
+ static const std::size_t alignment = 16;
+ alignas(alignment) char buf_[N];
+ char* ptr_;
+
+#if UPSTREAM_CODE
+ std::size_t
+ align_up(std::size_t n) noexcept
+ {return n + (alignment-1) & ~(alignment-1);}
+#else
+ std::size_t
+ align_up(std::size_t n) noexcept
+ {return (n + (alignment-1)) & ~(alignment-1);}
+#endif
+
+ bool
+ pointer_in_buffer(char* p) noexcept
+ {return buf_ <= p && p <= buf_ + N;}
+
+public:
+ arena() noexcept : ptr_(buf_) {}
+ ~arena() {ptr_ = nullptr;}
+ arena(const arena&) = delete;
+ arena& operator=(const arena&) = delete;
+
+ char* allocate(std::size_t n);
+ void deallocate(char* p, std::size_t n) noexcept;
+
+ static constexpr std::size_t size() {return N;}
+ std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+ void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
+{
+ n = align_up(n);
+ if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+ {
+ char* r = ptr_;
+ ptr_ += n;
+ return r;
+ }
+ return static_cast<char*>(std::malloc(n));
+}
+
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) noexcept
+{
+ if (pointer_in_buffer(p))
+ {
+ n = align_up(n);
+ if (p + n == ptr_)
+ ptr_ = p;
+ }
+ else
+ std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+ arena<N>& a_;
+public:
+ typedef T value_type;
+
+public:
+ template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+ short_alloc(arena<N>& a) noexcept : a_(a) {}
+ template <class U>
+ short_alloc(const short_alloc<U, N>& a) noexcept
+ : a_(a.a_) {}
+ short_alloc(const short_alloc&) = default;
+ short_alloc& operator=(const short_alloc&) = delete;
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t n) noexcept
+ {
+ a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
+ }
+
+ template <class T1, std::size_t N1, class U, std::size_t M>
+ friend
+ bool
+ operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
+
+ template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+ typedef T value_type;
+
+ malloc_alloc() = default;
+ template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t) noexcept
+ {
+ std::free(p);
+ }
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
+{
+ return true;
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
+{
+ return !(x == y);
+}
+
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+
+template <class StrT>
+struct string_pair
+{
+ StrT first;
+ StrT second;
+
+ string_pair() = default;
+ string_pair(StrT f) : first(std::move(f)) {}
+ string_pair(StrT f, StrT s)
+ : first(std::move(f)), second(std::move(s)) {}
+ template <size_t N>
+ string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+ size_t size() const {return first.size() + second.size();}
+ StrT full() const {return first + second;}
+ StrT move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+#if UPSTREAM_CODE
+ typedef std::basic_string<char, std::char_traits<char>,
+ malloc_alloc<char>> String;
+#else
+ typedef std::basic_string<char, std::char_traits<char> > String;
+#endif
+ typedef Vector<string_pair<String>> sub_type;
+ typedef Vector<sub_type> template_param_type;
+ sub_type names;
+ template_param_type subs;
+ Vector<template_param_type> template_param;
+ unsigned cv;
+ unsigned ref;
+ unsigned encoding_depth;
+ bool parsed_ctor_dtor_cv;
+ bool tag_templates;
+ bool fix_forward_references;
+ bool try_to_parse_template_args;
+
+ template <size_t N>
+ Db(arena<N>& ar) :
+ names(ar),
+ subs(0, names, ar),
+ template_param(0, subs, ar)
+ {}
+};
+
+#if UPSTREAM_CODE
+extern "C"
+__attribute__ ((__visibility__("default")))
+char*
+__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
+{
+ if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
+ {
+ if (status)
+ *status = invalid_args;
+ return nullptr;
+ }
+ size_t internal_size = buf != nullptr ? *n : 0;
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ size_t len = std::strlen(mangled_name);
+ demangle(mangled_name, mangled_name + len, db,
+ internal_status);
+ if (internal_status == success && db.fix_forward_references &&
+ !db.template_param.empty() && !db.template_param.front().empty())
+ {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(mangled_name, mangled_name + len, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+ if (internal_status == success)
+ {
+ size_t sz = db.names.back().size() + 1;
+ if (sz > internal_size)
+ {
+ char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+ if (newbuf == nullptr)
+ {
+ internal_status = memory_alloc_failure;
+ buf = nullptr;
+ }
+ else
+ {
+ buf = newbuf;
+ if (n != nullptr)
+ *n = sz;
+ }
+ }
+ if (buf != nullptr)
+ {
+ db.names.back().first += db.names.back().second;
+ std::memcpy(buf, db.names.back().first.data(), sz-1);
+ buf[sz-1] = char(0);
+ }
+ }
+ else
+ buf = nullptr;
+ if (status)
+ *status = internal_status;
+ return buf;
+}
+#endif
+
+} // namespace mcld
diff --git a/include/mcld/Support/Demangle.h b/include/mcld/Support/Demangle.h
new file mode 100644
index 0000000..b6f7412
--- /dev/null
+++ b/include/mcld/Support/Demangle.h
@@ -0,0 +1,22 @@
+//===- Demangle.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SUPPORT_DEMANGLE_H
+#define MCLD_SUPPORT_DEMANGLE_H
+
+#include <string>
+
+namespace mcld {
+
+std::string demangleName(const std::string& mangled_name);
+
+bool isCtorOrDtor(const char* pName, size_t pLength);
+
+} // namespace mcld
+
+#endif
diff --git a/include/mcld/Support/FileOutputBuffer.h b/include/mcld/Support/FileOutputBuffer.h
index 94cf640..6b48e14 100644
--- a/include/mcld/Support/FileOutputBuffer.h
+++ b/include/mcld/Support/FileOutputBuffer.h
@@ -10,11 +10,10 @@
#define MCLD_SUPPORT_FILEOUTPUTBUFFER_H
#include <mcld/Support/MemoryRegion.h>
-#include <llvm/ADT/OwningPtr.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/FileSystem.h>
-#include <llvm/Support/system_error.h>
+#include <system_error>
namespace mcld {
@@ -27,9 +26,9 @@ public:
/// Factory method to create an OutputBuffer object which manages a read/write
/// buffer of the specified size. When committed, the buffer will be written
/// to the file at the specified path.
- static llvm::error_code create(FileHandle& pFileHandle,
- size_t pSize,
- llvm::OwningPtr<FileOutputBuffer>& pResult);
+ static std::error_code create(FileHandle& pFileHandle,
+ size_t pSize,
+ std::unique_ptr<FileOutputBuffer>& pResult);
/// Returns a pointer to the start of the buffer.
uint8_t* getBufferStart() {
@@ -60,7 +59,7 @@ private:
FileOutputBuffer(llvm::sys::fs::mapped_file_region* pRegion,
FileHandle& pFileHandle);
- llvm::OwningPtr<llvm::sys::fs::mapped_file_region> m_pRegion;
+ std::unique_ptr<llvm::sys::fs::mapped_file_region> m_pRegion;
FileHandle& m_FileHandle;
};
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
index 2fef506..570e293 100644
--- a/include/mcld/Support/MemoryArea.h
+++ b/include/mcld/Support/MemoryArea.h
@@ -11,7 +11,6 @@
#include <mcld/ADT/Uncopyable.h>
-#include <llvm/ADT/OwningPtr.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/MemoryBuffer.h>
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
index 15337f6..351111d 100644
--- a/include/mcld/Target/GNULDBackend.h
+++ b/include/mcld/Target/GNULDBackend.h
@@ -19,6 +19,8 @@
#include <llvm/Support/ELF.h>
+#include <cstdint>
+
namespace mcld {
class Module;
@@ -258,8 +260,8 @@ public:
bool pSymHasPLT,
bool isAbsReloc) const;
- /// isSymbolPreemtible - whether the symbol can be preemted by other
- /// link unit
+ /// isSymbolPreemptible - whether the symbol can be preemted by other link
+ /// units
/// @ref Google gold linker, symtab.h:551
bool isSymbolPreemptible(const ResolveInfo& pSym) const;
@@ -309,9 +311,13 @@ public:
/// getStubFactory
StubFactory* getStubFactory() { return m_pStubFactory; }
- /// maxBranchOffset - return the max (forward) branch offset of the backend.
+ /// maxFwdBranchOffset - return the max forward branch offset of the backend.
+ /// Target can override this function if needed.
+ virtual int64_t maxFwdBranchOffset() { return INT64_MAX; }
+
+ /// maxBwdBranchOffset - return the max backward branch offset of the backend.
/// Target can override this function if needed.
- virtual uint64_t maxBranchOffset() { return (uint64_t)-1; }
+ virtual int64_t maxBwdBranchOffset() { return 0; }
/// checkAndSetHasTextRel - check pSection flag to set HasTextRel
void checkAndSetHasTextRel(const LDSection& pSection);
@@ -330,6 +336,10 @@ public:
/// attribute - the attribute section data.
const ELFAttribute& attribute() const { return *m_pAttribute; }
+ /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+ /// function pointer access
+ bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection) const;
+
protected:
/// getRelEntrySize - the size in BYTE of rel type relocation
virtual size_t getRelEntrySize() = 0;
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
index 29fb395..a1a5f1c 100644
--- a/include/mcld/Target/TargetLDBackend.h
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -35,6 +35,7 @@ class ObjectBuilder;
class ObjectReader;
class ObjectWriter;
class Relocator;
+class ResolveInfo;
class SectionData;
class StubFactory;
@@ -62,6 +63,7 @@ public:
virtual bool initRelocator() = 0;
virtual Relocator* getRelocator() = 0;
+ virtual const Relocator* getRelocator() const = 0;
// ----- format dependent ----- //
virtual ArchiveReader* createArchiveReader(Module&) = 0;
@@ -167,6 +169,15 @@ public:
/// entry in the middle
virtual void createAndSizeEhFrameHdr(Module& pModule) = 0;
+ /// isSymbolPreemptible - whether the symbol can be preemted by other link
+ /// units
+ virtual bool isSymbolPreemptible(const ResolveInfo& pSym) const = 0;
+
+ /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+ /// function pointer access
+ virtual bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+ const = 0;
+
protected:
const LinkerConfig& config() const { return m_Config; }
diff --git a/lib/CodeGen/MCLDTargetMachine.cpp b/lib/CodeGen/MCLDTargetMachine.cpp
index e1d9a0e..7749748 100644
--- a/lib/CodeGen/MCLDTargetMachine.cpp
+++ b/lib/CodeGen/MCLDTargetMachine.cpp
@@ -15,7 +15,6 @@
#include <mcld/Support/ToolOutputFile.h>
#include <mcld/Target/TargetLDBackend.h>
-#include <llvm/ADT/OwningPtr.h>
#include <llvm/Analysis/Passes.h>
#include <llvm/CodeGen/AsmPrinter.h>
#include <llvm/CodeGen/MachineFunctionAnalysis.h>
@@ -127,7 +126,7 @@ static void addPassesToHandleExceptions(llvm::TargetMachine *TM,
// FALLTHROUGH
case llvm::ExceptionHandling::DwarfCFI:
case llvm::ExceptionHandling::ARM:
- case llvm::ExceptionHandling::Win64:
+ case llvm::ExceptionHandling::WinEH:
PM.add(createDwarfEHPass(TM));
break;
case llvm::ExceptionHandling::None:
@@ -300,7 +299,7 @@ mcld::MCLDTargetMachine::addCompilerPasses(llvm::legacy::PassManagerBase &pPM,
// now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
- OwningPtr<MCStreamer> AsmStreamer(
+ std::unique_ptr<MCStreamer> AsmStreamer(
m_pLLVMTarget->createAsmStreamer(*Context, pOutput,
getVerboseAsm(getTM()),
getTM().Options.MCOptions.MCUseDwarfDirectory,
@@ -314,7 +313,7 @@ mcld::MCLDTargetMachine::addCompilerPasses(llvm::legacy::PassManagerBase &pPM,
if (funcPass == 0)
return true;
// If successful, createAsmPrinter took ownership of AsmStreamer
- AsmStreamer.take();
+ AsmStreamer.release();
pPM.add(funcPass);
return false;
}
@@ -338,7 +337,7 @@ mcld::MCLDTargetMachine::addAssemblerPasses(llvm::legacy::PassManagerBase &pPM,
return true;
// now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
- OwningPtr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
+ std::unique_ptr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
m_Triple, *Context, *MAB, pOutput, MCE, STI,
getTM().Options.MCOptions.MCRelaxAll, getTM().Options.MCOptions.MCNoExecStack));
@@ -348,7 +347,7 @@ mcld::MCLDTargetMachine::addAssemblerPasses(llvm::legacy::PassManagerBase &pPM,
if (funcPass == 0)
return true;
// If successful, createAsmPrinter took ownership of AsmStreamer
- AsmStreamer.take();
+ AsmStreamer.release();
pPM.add(funcPass);
return false;
}
diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp
index 7f9b81c..f6e86b9 100644
--- a/lib/Core/GeneralOptions.cpp
+++ b/lib/Core/GeneralOptions.cpp
@@ -9,6 +9,7 @@
#include <mcld/GeneralOptions.h>
#include <mcld/MC/Input.h>
#include <mcld/MC/ZOption.h>
+#include <cassert>
using namespace mcld;
@@ -54,7 +55,11 @@ GeneralOptions::GeneralOptions()
m_bNoStdlib(false),
m_bWarnMismatch(true),
m_bGCSections(false),
+ m_bPrintGCSections(false),
m_bGenUnwindInfo(true),
+ m_bPrintICFSections(false),
+ m_ICF(ICF_None),
+ m_ICFIterations(0) ,
m_GPSize(8),
m_StripSymbols(KeepAllSymbols),
m_HashStyle(SystemV) {
@@ -145,3 +150,26 @@ void GeneralOptions::addZOption(const ZOption& pOption)
break;
}
}
+
+bool GeneralOptions::isInExcludeLIBS(const Input& pInput) const
+{
+ assert(pInput.type() == Input::Archive);
+
+ if (m_ExcludeLIBS.empty()) {
+ return false;
+ }
+
+ // Specifying "--exclude-libs ALL" excludes symbols in all archive libraries
+ // from automatic export.
+ if (m_ExcludeLIBS.count("ALL") != 0) {
+ return true;
+ }
+
+ std::string name(pInput.name());
+ name.append(".a");
+ if (m_ExcludeLIBS.count(name) != 0) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp
index 080a122..bc44990 100644
--- a/lib/Core/IRBuilder.cpp
+++ b/lib/Core/IRBuilder.cpp
@@ -62,8 +62,12 @@ LDFileFormat::Kind GetELFSectionKind(uint32_t pType, const char* pName,
case llvm::ELF::SHT_INIT_ARRAY:
case llvm::ELF::SHT_FINI_ARRAY:
case llvm::ELF::SHT_PREINIT_ARRAY:
- case llvm::ELF::SHT_PROGBITS:
- return LDFileFormat::Regular;
+ case llvm::ELF::SHT_PROGBITS: {
+ if ((pFlag & llvm::ELF::SHF_EXECINSTR) != 0)
+ return LDFileFormat::TEXT;
+ else
+ return LDFileFormat::DATA;
+ }
case llvm::ELF::SHT_SYMTAB:
case llvm::ELF::SHT_DYNSYM:
case llvm::ELF::SHT_STRTAB:
@@ -423,6 +427,13 @@ LDSymbol* IRBuilder::AddSymbol(Input& pInput,
name = renameSym.getEntry()->value();
}
+ // Fix up the visibility if object has no export set.
+ if (pInput.noExport() && (pDesc != ResolveInfo::Undefined)) {
+ if ((pVis == ResolveInfo::Default) || (pVis == ResolveInfo::Protected)) {
+ pVis = ResolveInfo::Hidden;
+ }
+ }
+
switch (pInput.type()) {
case Input::Object: {
diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp
index 464f039..c8638a7 100644
--- a/lib/Core/Linker.cpp
+++ b/lib/Core/Linker.cpp
@@ -28,8 +28,6 @@
#include <mcld/Fragment/Relocation.h>
#include <mcld/Fragment/FragmentRef.h>
-#include <llvm/ADT/OwningPtr.h>
-
#include <cassert>
using namespace mcld;
@@ -96,7 +94,12 @@ bool Linker::normalize(Module& pModule, IRBuilder& pBuilder)
if (!Diagnose())
return false;
- // 4. - normalize the input tree
+ // 4.a - add undefined symbols
+ // before reading the inputs, we should add undefined symbols set by -u to
+ // ensure that correspoding objects (e.g. in an archive) will be included
+ m_pObjLinker->addUndefinedSymbols();
+
+ // 4.b - normalize the input tree
// read out sections and symbol/string tables (from the files) and
// set them in Module. When reading out the symbol, resolve their symbols
// immediately and set their ResolveInfo (i.e., Symbol Resolution).
@@ -204,7 +207,6 @@ bool Linker::layout()
assert(NULL != m_pConfig && NULL != m_pObjLinker);
// 10. - add standard symbols, target-dependent symbols and script symbols
- // m_pObjLinker->addUndefSymbols();
if (!m_pObjLinker->addStandardSymbols() ||
!m_pObjLinker->addTargetSymbols() ||
!m_pObjLinker->addScriptSymbols())
@@ -280,7 +282,7 @@ bool Linker::emit(const Module& pModule, const std::string& pPath)
return false;
}
- llvm::OwningPtr<FileOutputBuffer> output;
+ std::unique_ptr<FileOutputBuffer> output;
FileOutputBuffer::create(file,
m_pObjLinker->getWriter()->getOutputSize(pModule),
output);
@@ -295,7 +297,7 @@ bool Linker::emit(const Module& pModule, int pFileDescriptor)
FileHandle file;
file.delegate(pFileDescriptor);
- llvm::OwningPtr<FileOutputBuffer> output;
+ std::unique_ptr<FileOutputBuffer> output;
FileOutputBuffer::create(file,
m_pObjLinker->getWriter()->getOutputSize(pModule),
output);
diff --git a/lib/LD/BranchIslandFactory.cpp b/lib/LD/BranchIslandFactory.cpp
index 116f075..fcaa2eb 100644
--- a/lib/LD/BranchIslandFactory.cpp
+++ b/lib/LD/BranchIslandFactory.cpp
@@ -19,14 +19,16 @@ using namespace mcld;
//===----------------------------------------------------------------------===//
/// ctor
-/// @param pMaxBranchRange - the max branch range of the target backend
-/// @param pMaxIslandSize - a predifned value (1KB here) to decide the max
-/// size of the island
-BranchIslandFactory::BranchIslandFactory(uint64_t pMaxBranchRange,
- uint64_t pMaxIslandSize)
- : GCFactory<BranchIsland, 0>(1u), // magic number
- m_MaxBranchRange(pMaxBranchRange - pMaxIslandSize),
- m_MaxIslandSize(pMaxIslandSize)
+/// @param pMaxFwdBranchRange - the max forward branch range of the target
+/// @param pMaxBwdBranchRange - the max backward branch range of the target
+/// @param pMaxIslandSize - the predefined value for the max size of a island
+BranchIslandFactory::BranchIslandFactory(int64_t pMaxFwdBranchRange,
+ int64_t pMaxBwdBranchRange,
+ size_t pMaxIslandSize)
+ : GCFactory<BranchIsland, 0>(1u), // magic number
+ m_MaxFwdBranchRange(pMaxFwdBranchRange - pMaxIslandSize),
+ m_MaxBwdBranchRange(pMaxBwdBranchRange + pMaxIslandSize),
+ m_MaxIslandSize(pMaxIslandSize)
{
}
@@ -38,11 +40,11 @@ BranchIslandFactory::~BranchIslandFactory()
/// @param pSectionData - the SectionData holds fragments need to be grouped
void BranchIslandFactory::group(Module& pModule)
{
- /* Currently only support relaxing .text section! */
+ /* 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_MaxBranchRange - m_MaxIslandSize;
+ 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();
@@ -51,11 +53,11 @@ void BranchIslandFactory::group(Module& pModule)
}
if (frag != NULL) {
produce(*frag);
- group_end = (*it).getOffset() + m_MaxBranchRange - m_MaxIslandSize;
+ group_end = (*it).getOffset() + m_MaxFwdBranchRange;
}
}
}
- if (find(sd.back()) == NULL)
+ if (getIslands(sd.back()).first == NULL)
produce(sd.back());
}
}
@@ -71,17 +73,29 @@ BranchIsland* BranchIslandFactory::produce(Fragment& pFragment)
return island;
}
-/// find - find a island for the given fragment
-/// @param pFragment - the fragment needs a branch isladn
-BranchIsland* BranchIslandFactory::find(const Fragment& pFragment)
+/// getIsland - find fwd and bwd islands for the fragment
+/// @param pFragment - the fragment needs a branch island
+std::pair<BranchIsland*, BranchIsland*>
+BranchIslandFactory::getIslands(const Fragment& pFragment)
{
- // Currently we always find the island in a forward direction.
- // TODO: If we can search backward, then we may reduce the number of stubs.
- for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ BranchIsland* fwd = NULL;
+ BranchIsland* bwd = NULL;
+ for (iterator it = begin(), ie = end(), prev = ie; it != ie;
+ prev = it, ++it) {
if ((pFragment.getOffset() < (*it).offset()) &&
- ((pFragment.getOffset() + m_MaxBranchRange) >= (*it).offset()))
- return &(*it);
+ ((pFragment.getOffset() + m_MaxFwdBranchRange) >= (*it).offset())) {
+
+ fwd = &*it;
+
+ if (prev != ie) {
+ int64_t bwd_off = (int64_t)pFragment.getOffset() + m_MaxBwdBranchRange;
+ if ((pFragment.getOffset() > (*prev).offset()) &&
+ (bwd_off <= (*prev).offset())) {
+ bwd = &*prev;
+ }
+ }
+ break;
+ }
}
- return NULL;
+ return std::make_pair(fwd, bwd);
}
-
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
index 943b046..aed389a 100644
--- a/lib/LD/DiagnosticInfos.cpp
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -141,18 +141,17 @@ bool DiagnosticInfos::process(DiagnosticEngine& pEngine) const
else
severity = DiagnosticEngine::Ignore;
break;
- case LinkerConfig::Exec:
- if (m_Config.options().isNoUndefined())
- severity = DiagnosticEngine::Error;
- else
- severity = DiagnosticEngine::Ignore;
- break;
default:
severity = DiagnosticEngine::Error;
break;
}
break;
}
+ case diag::debug_print_gc_sections: {
+ if (!m_Config.options().getPrintGCSections())
+ severity = DiagnosticEngine::Ignore;
+ break;
+ }
default:
break;
} // end of switch
diff --git a/lib/LD/ELFBinaryReader.cpp b/lib/LD/ELFBinaryReader.cpp
index ee537c2..c72fa58 100644
--- a/lib/LD/ELFBinaryReader.cpp
+++ b/lib/LD/ELFBinaryReader.cpp
@@ -52,7 +52,7 @@ bool ELFBinaryReader::readBinary(Input& pInput)
LDSection* data_sect =
m_Builder.CreateELFHeader(pInput,
".data",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC,
0x1);
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index ebeba63..94eef58 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -17,7 +17,6 @@
#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/Twine.h>
-#include <llvm/ADT/OwningPtr.h>
#include <llvm/Support/ErrorHandling.h>
#include <string>
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
index 551a60d..318e595 100644
--- a/lib/LD/ELFFileFormat.cpp
+++ b/lib/LD/ELFFileFormat.cpp
@@ -67,7 +67,7 @@ ELFFileFormat::ELFFileFormat()
void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitClass)
{
f_pTextSection = pBuilder.CreateSection(".text",
- LDFileFormat::Regular,
+ LDFileFormat::TEXT,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
0x1);
@@ -76,7 +76,7 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
llvm::ELF::SHT_NULL,
0x0);
f_pReadOnlySection = pBuilder.CreateSection(".rodata",
- LDFileFormat::Regular,
+ LDFileFormat::TEXT,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
0x1);
@@ -92,12 +92,12 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
0x0,
0x1);
f_pDataSection = pBuilder.CreateSection(".data",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pData1 = pBuilder.CreateSection(".data1",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
@@ -107,22 +107,22 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
0x0,
0x1);
f_pInit = pBuilder.CreateSection(".init",
- LDFileFormat::Regular,
+ LDFileFormat::TEXT,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
0x1);
f_pInitArray = pBuilder.CreateSection(".init_array",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_INIT_ARRAY,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pFini = pBuilder.CreateSection(".fini",
- LDFileFormat::Regular,
+ LDFileFormat::TEXT,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
0x1);
f_pFiniArray = pBuilder.CreateSection(".fini_array",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_FINI_ARRAY,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
@@ -132,14 +132,14 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
0x0,
0x1);
f_pPreInitArray = pBuilder.CreateSection(".preinit_array",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PREINIT_ARRAY,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
// the definition of SHF_XXX attributes of rodata in Linux Standard Base
// conflicts with System V standard. We follow System V standard.
f_pROData1 = pBuilder.CreateSection(".rodata1",
- LDFileFormat::Regular,
+ LDFileFormat::TEXT,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
0x1);
@@ -170,7 +170,7 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
llvm::ELF::SHF_TLS,
0x1);
f_pTData = pBuilder.CreateSection(".tdata",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC |
llvm::ELF::SHF_WRITE |
@@ -179,17 +179,17 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
/// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
f_pCtors = pBuilder.CreateSection(".ctors",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pDataRelRo = pBuilder.CreateSection(".data.rel.ro",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pDtors = pBuilder.CreateSection(".dtors",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
@@ -219,7 +219,7 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
llvm::ELF::SHF_ALLOC,
0x1);
f_pJCR = pBuilder.CreateSection(".jcr",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
@@ -241,7 +241,7 @@ void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitCl
/// @ref GCC convention, see http://www.airs.com/blog/archives/189
f_pDataRelRoLocal = pBuilder.CreateSection(".data.rel.ro.local",
- LDFileFormat::Regular,
+ LDFileFormat::DATA,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index a34739a..a0ece0f 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -170,7 +170,10 @@ bool ELFObjectReader::readSections(Input& pInput)
fatal(diag::err_cannot_read_section) << (*section)->name();
}
} else {
- (*section)->setKind(LDFileFormat::Regular);
+ if (((*section)->flag() & llvm::ELF::SHF_EXECINSTR) != 0)
+ (*section)->setKind(LDFileFormat::TEXT);
+ else
+ (*section)->setKind(LDFileFormat::DATA);
SectionData* sd = IRBuilder::CreateSectionData(**section);
if (!m_pELFReader->readRegularSection(pInput, *sd))
fatal(diag::err_cannot_read_section) << (*section)->name();
@@ -199,7 +202,8 @@ bool ELFObjectReader::readSections(Input& pInput)
// FIXME: support GCCExceptTable Kind
case LDFileFormat::GCCExceptTable:
/** Fall through **/
- case LDFileFormat::Regular:
+ case LDFileFormat::TEXT:
+ case LDFileFormat::DATA:
case LDFileFormat::Note:
case LDFileFormat::MetaData: {
SectionData* sd = IRBuilder::CreateSectionData(**section);
diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp
index dca6936..c90efdf 100644
--- a/lib/LD/ELFObjectWriter.cpp
+++ b/lib/LD/ELFObjectWriter.cpp
@@ -29,8 +29,8 @@
#include <mcld/LD/ELFFileFormat.h>
#include <mcld/Target/GNUInfo.h>
+#include <llvm/Support/Errc.h>
#include <llvm/Support/ErrorHandling.h>
-#include <llvm/Support/system_error.h>
#include <llvm/Support/ELF.h>
#include <llvm/Support/Casting.h>
@@ -61,7 +61,8 @@ void ELFObjectWriter::writeSection(Module& pModule,
if (section->getSectionData() == NULL)
return;
// Fall through
- case LDFileFormat::Regular:
+ case LDFileFormat::TEXT:
+ case LDFileFormat::DATA:
case LDFileFormat::Relocation:
case LDFileFormat::Target:
case LDFileFormat::Debug:
@@ -94,7 +95,8 @@ void ELFObjectWriter::writeSection(Module& pModule,
// Write out sections with data
switch(section->kind()) {
case LDFileFormat::GCCExceptTable:
- case LDFileFormat::Regular:
+ case LDFileFormat::TEXT:
+ case LDFileFormat::DATA:
case LDFileFormat::Debug:
case LDFileFormat::Note:
emitSectionData(*section, region);
@@ -116,8 +118,8 @@ void ELFObjectWriter::writeSection(Module& pModule,
}
}
-llvm::error_code ELFObjectWriter::writeObject(Module& pModule,
- FileOutputBuffer& pOutput)
+std::error_code ELFObjectWriter::writeObject(Module& pModule,
+ FileOutputBuffer& pOutput)
{
bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
@@ -180,10 +182,10 @@ llvm::error_code ELFObjectWriter::writeObject(Module& pModule,
emitSectionHeader<64>(pModule, m_Config, pOutput);
}
else
- return make_error_code(errc::not_supported);
+ return llvm::make_error_code(llvm::errc::function_not_supported);
}
- return llvm::make_error_code(llvm::errc::success);
+ return std::error_code();
}
// getOutputSize - count the final output size
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index 3dc95a5..4553bfb 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -401,6 +401,10 @@ size_t GNUArchiveReader::includeMember(const LinkerConfig& pConfig,
if (m_ELFObjectReader.isMyFormat(*member, doContinue)) {
member->setType(Input::Object);
+ // Set this object as no export if the archive is in the exclude libs.
+ if (pArchive.getARFile().noExport()) {
+ member->setNoExport();
+ }
pArchive.addObjectMember(pFileOffset, parent->lastPos);
m_ELFObjectReader.readHeader(*member);
m_ELFObjectReader.readSections(*member);
@@ -468,4 +472,3 @@ bool GNUArchiveReader::includeAllMembers(const LinkerConfig& pConfig,
}
return true;
}
-
diff --git a/lib/LD/GarbageCollection.cpp b/lib/LD/GarbageCollection.cpp
index 4ea40ac..44c9b5a 100644
--- a/lib/LD/GarbageCollection.cpp
+++ b/lib/LD/GarbageCollection.cpp
@@ -18,6 +18,7 @@
#include <mcld/LinkerConfig.h>
#include <mcld/LinkerScript.h>
#include <mcld/Module.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
#include <llvm/Support/Casting.h>
@@ -63,7 +64,8 @@ static bool shouldKeep(const std::string& pName)
/// shouldProcessGC - check if the section kind is handled in GC
static bool mayProcessGC(const LDSection& pSection)
{
- if (pSection.kind() == LDFileFormat::Regular ||
+ if (pSection.kind() == LDFileFormat::TEXT ||
+ pSection.kind() == LDFileFormat::DATA ||
pSection.kind() == LDFileFormat::BSS ||
pSection.kind() == LDFileFormat::GCCExceptTable)
return true;
@@ -270,6 +272,24 @@ void GarbageCollection::getEntrySections(SectionVecTy& pEntry)
pEntry.push_back(sect);
}
}
+
+ // symbols set by -u should not be garbage collected. Set them entries.
+ GeneralOptions::const_undef_sym_iterator usym;
+ GeneralOptions::const_undef_sym_iterator usymEnd =
+ m_Config.options().undef_sym_end();
+ for (usym = m_Config.options().undef_sym_begin(); usym != usymEnd; ++usym) {
+ LDSymbol* sym = m_Module.getNamePool().findSymbol(*usym);
+ assert(sym);
+ ResolveInfo* info = sym->resolveInfo();
+ assert(info);
+ if (!info->isDefine() || !sym->hasFragRef())
+ continue;
+ // only the symbols defined in the concerned sections can be entries
+ const LDSection* sect = &sym->fragRef()->frag()->getParent()->getSection();
+ if (!mayProcessGC(*sect))
+ continue;
+ pEntry.push_back(sect);
+ }
}
void GarbageCollection::findReferencedSections(SectionVecTy& pEntry)
@@ -323,8 +343,11 @@ void GarbageCollection::stripSections()
if (!mayProcessGC(*section))
continue;
- if (m_ReferencedSections.find(section) == m_ReferencedSections.end())
+ if (m_ReferencedSections.find(section) == m_ReferencedSections.end()) {
section->setKind(LDFileFormat::Ignore);
+ debug(diag::debug_print_gc_sections) << section->name()
+ << (*obj)->name();
+ }
}
}
diff --git a/lib/LD/Relocator.cpp b/lib/LD/Relocator.cpp
index bf76573..fa3a94f 100644
--- a/lib/LD/Relocator.cpp
+++ b/lib/LD/Relocator.cpp
@@ -6,7 +6,6 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <mcld/Config/Config.h>
#include <mcld/Fragment/Fragment.h>
#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDSection.h>
@@ -14,40 +13,14 @@
#include <mcld/LD/Relocator.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/SectionData.h>
+#include <mcld/Support/Demangle.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Module.h>
-#ifdef HAVE_CXXABI_H
-#include <cxxabi.h>
-#endif
#include <sstream>
using namespace mcld;
//===----------------------------------------------------------------------===//
-// Helper functions
-//===----------------------------------------------------------------------===//
-std::string demangleSymbol(const std::string& mangled_name) {
-#ifdef HAVE_CXXABI_H
- // __cxa_demangle needs manually handle the memory release, so we wrap
- // it into this helper function.
- size_t output_leng;
- int status;
- char* buffer = abi::__cxa_demangle(mangled_name.c_str(), /*buffer=*/0,
- &output_leng, &status);
- if (status != 0) { // Failed
- return mangled_name;
- }
- std::string demangled_name(buffer);
- free(buffer);
-
- return demangled_name;
-#else
- return mangled_name;
-#endif
-}
-
-
-//===----------------------------------------------------------------------===//
// Relocator
//===----------------------------------------------------------------------===//
Relocator::~Relocator()
@@ -87,8 +60,7 @@ void Relocator::issueUndefRef(Relocation& pReloc,
sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1)); // Drop .rel(a) prefix
std::string reloc_sym(pReloc.symInfo()->name());
- if (reloc_sym.substr(0, 2) == "_Z")
- reloc_sym = demangleSymbol(reloc_sym);
+ reloc_sym = demangleName(reloc_sym);
std::stringstream ss;
ss << "0x" << std::hex << undef_sym_pos;
@@ -119,8 +91,7 @@ void Relocator::issueUndefRef(Relocation& pReloc,
}
}
- if (caller_func_name.substr(0, 2) == "_Z")
- caller_func_name = demangleSymbol(caller_func_name);
+ caller_func_name = demangleName(caller_func_name);
fatal(diag::undefined_reference_text) << reloc_sym
<< pInput.path()
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
index d7daf1d..3dad005 100644
--- a/lib/LD/StaticResolver.cpp
+++ b/lib/LD/StaticResolver.cpp
@@ -8,10 +8,9 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/StaticResolver.h>
#include <mcld/LD/LDSymbol.h>
+#include <mcld/Support/Demangle.h>
#include <mcld/Support/MsgHandling.h>
-#include <cxxabi.h>
-
using namespace mcld;
//==========================
@@ -171,9 +170,6 @@ bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
}
/* Fall through */
case MDEF: { /* multiple definition error. */
- int status;
- char* demangled_name = abi::__cxa_demangle(pNew.name(), NULL, NULL,
- &status);
if (pOld.isDefine() && pNew.isDefine() &&
pOld.isAbsolute() && pNew.isAbsolute() &&
(pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType ||
@@ -183,21 +179,15 @@ bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
old->override(pNew);
break;
} else {
- if (demangled_name != NULL) {
- error(diag::multiple_absolute_definitions) << demangled_name
- << pOld.outSymbol()->value() << pValue;
- } else {
- error(diag::multiple_absolute_definitions) << pNew.name()
- << pOld.outSymbol()->value() << pValue;
- }
+ error(diag::multiple_absolute_definitions)
+ << demangleName(pNew.name())
+ << pOld.outSymbol()->value()
+ << pValue;
break;
}
}
- if (demangled_name != NULL) {
- error(diag::multiple_definitions) << demangled_name;
- } else {
- error(diag::multiple_definitions) << pNew.name();
- }
+
+ error(diag::multiple_definitions) << demangleName(pNew.name());
break;
}
case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp
index 3d7c56a..52c372c 100644
--- a/lib/LD/StubFactory.cpp
+++ b/lib/LD/StubFactory.cpp
@@ -14,7 +14,6 @@
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/Fragment/Relocation.h>
-#include <mcld/Fragment/FragmentRef.h>
#include <string>
@@ -43,67 +42,78 @@ Stub* StubFactory::create(Relocation& pReloc,
BranchIslandFactory& pBRIslandFactory)
{
// find if there is a prototype stub for the input relocation
- Stub* prototype = findPrototype(pReloc,
- pReloc.place(),
- pTargetSymValue);
- if (NULL != prototype) {
- // find the island for the input relocation
- BranchIsland* island = pBRIslandFactory.find(*(pReloc.targetRef().frag()));
- if (NULL == island) {
+ Stub* stub = NULL;
+ Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
+ if (prototype != NULL) {
+ const Fragment* frag = pReloc.targetRef().frag();
+ // find the islands for the input relocation
+ std::pair<BranchIsland*, BranchIsland*> islands =
+ pBRIslandFactory.getIslands(*frag);
+ if (islands.first == NULL) {
+ // early exit if we can not find the forward island.
return NULL;
}
- // find if there is such a stub in the island already
- Stub* stub = island->findStub(prototype, pReloc);
- if (NULL != stub) {
+ // find if there is such a stub in the backward island first.
+ if (islands.second != NULL) {
+ stub = islands.second->findStub(prototype, pReloc);
+ }
+
+ if (stub != NULL) {
// reset the branch target to the stub instead!
pReloc.setSymInfo(stub->symInfo());
- }
- else {
- // create a stub from the prototype
- stub = prototype->clone();
+ } else {
+ // 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 {
+ // create a stub from the prototype
+ stub = prototype->clone();
- // build a name for stub symbol
- std::string name("__");
- name.append(pReloc.symInfo()->name());
- name.append("_");
- name.append(stub->name());
- name.append("@");
- name.append(island->name());
+ // 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::Resolve>(
- name,
- ResolveInfo::Function,
- ResolveInfo::Define,
- ResolveInfo::Local,
- stub->size(), // size
- stub->initSymValue(), // value
- FragmentRef::Create(*stub, stub->initSymValue()),
- ResolveInfo::Default);
- stub->setSymInfo(symbol->resolveInfo());
+ // 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(),
+ // 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(),
+ Relocation* reloc =
+ Relocation::Create((*it)->type(),
*(FragmentRef::Create(*stub, (*it)->offset())),
(*it)->addend());
- reloc->setSymInfo(pReloc.symInfo());
- island->addRelocation(*reloc);
- }
+ reloc->setSymInfo(pReloc.symInfo());
+ islands.first->addRelocation(*reloc);
+ }
- // add stub to the branch island
- island->addStub(prototype, pReloc, *stub);
+ // 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;
+ // reset the branch target of the input reloc to this stub instead!
+ pReloc.setSymInfo(stub->symInfo());
+ }
}
}
- return NULL;
+ return stub;
}
/// findPrototype - find if there is a registered stub prototype for the given
@@ -119,4 +129,3 @@ Stub* StubFactory::findPrototype(const Relocation& pReloc,
}
return NULL;
}
-
diff --git a/lib/MC/Input.cpp b/lib/MC/Input.cpp
index 2d948c2..26234fc 100644
--- a/lib/MC/Input.cpp
+++ b/lib/MC/Input.cpp
@@ -21,6 +21,7 @@ Input::Input(llvm::StringRef pName)
m_Path(),
m_pAttr(NULL),
m_bNeeded(false),
+ m_bNoExport(false),
m_fileOffset(0),
m_pMemArea(NULL),
m_pContext(NULL) {
@@ -32,6 +33,7 @@ Input::Input(llvm::StringRef pName, const AttributeProxy& pProxy)
m_Path(),
m_pAttr(const_cast<Attribute*>(pProxy.attr())),
m_bNeeded(false),
+ m_bNoExport(false),
m_fileOffset(0),
m_pMemArea(NULL),
m_pContext(NULL) {
@@ -46,6 +48,7 @@ Input::Input(llvm::StringRef pName,
m_Path(pPath),
m_pAttr(NULL),
m_bNeeded(false),
+ m_bNoExport(false),
m_fileOffset(pFileOffset),
m_pMemArea(NULL),
m_pContext(NULL) {
@@ -61,6 +64,7 @@ Input::Input(llvm::StringRef pName,
m_Path(pPath),
m_pAttr(const_cast<Attribute*>(pProxy.attr())),
m_bNeeded(false),
+ m_bNoExport(false),
m_fileOffset(pFileOffset),
m_pMemArea(NULL),
m_pContext(NULL) {
diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp
index d4df036..dfc7f37 100644
--- a/lib/Object/ObjectLinker.cpp
+++ b/lib/Object/ObjectLinker.cpp
@@ -22,6 +22,7 @@
#include <mcld/LD/GroupReader.h>
#include <mcld/LD/BinaryReader.h>
#include <mcld/LD/GarbageCollection.h>
+#include <mcld/LD/IdenticalCodeFolding.h>
#include <mcld/LD/ObjectWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/RelocData.h>
@@ -42,6 +43,7 @@
#include <llvm/Support/Casting.h>
#include <llvm/Support/Host.h>
+#include <system_error>
using namespace llvm;
using namespace mcld;
@@ -111,6 +113,37 @@ bool ObjectLinker::initStdSections()
return true;
}
+void ObjectLinker::addUndefinedSymbols()
+{
+ // Add the symbol set by -u as an undefind global symbol into symbol pool
+ GeneralOptions::const_undef_sym_iterator usym;
+ GeneralOptions::const_undef_sym_iterator usymEnd =
+ m_Config.options().undef_sym_end();
+ for (usym = m_Config.options().undef_sym_begin(); usym != usymEnd; ++usym) {
+ Resolver::Result result;
+ m_pModule->getNamePool().insertSymbol(*usym, // name
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Undefined,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ ResolveInfo::Default,
+ NULL,
+ result);
+
+ LDSymbol* output_sym = result.info->outSymbol();
+ bool has_output_sym = (NULL != output_sym);
+
+ // create the output symbol if it dose not have one
+ if (!result.existent || !has_output_sym) {
+ output_sym = LDSymbol::Create(*result.info);
+ result.info->setSymPtr(output_sym);
+ output_sym->setFragmentRef(FragmentRef::Null());
+ }
+ }
+}
+
void ObjectLinker::normalize()
{
// ----- set up inputs ----- //
@@ -165,6 +198,9 @@ void ObjectLinker::normalize()
// is an archive
else if (doContinue && getArchiveReader()->isMyFormat(**input, doContinue)) {
(*input)->setType(Input::Archive);
+ if (m_Config.options().isInExcludeLIBS(**input)) {
+ (*input)->setNoExport();
+ }
Archive archive(**input, m_pBuilder->getInputBuilder());
getArchiveReader()->readArchive(m_Config, archive);
if(archive.numOfObjectMember() > 0) {
@@ -236,6 +272,12 @@ void ObjectLinker::dataStrippingOpt()
GarbageCollection GC(m_Config, m_LDBackend, *m_pModule);
GC.run();
}
+
+ // Identical code folding
+ if (m_Config.options().getICFMode() != GeneralOptions::ICF_None) {
+ IdenticalCodeFolding icf(m_Config, m_LDBackend, *m_pModule);
+ icf.foldIdenticalCode();
+ }
return;
}
@@ -267,6 +309,7 @@ bool ObjectLinker::mergeSections()
for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) {
switch ((*sect)->kind()) {
// Some *INPUT sections should not be merged.
+ case LDFileFormat::Folded:
case LDFileFormat::Ignore:
case LDFileFormat::Null:
case LDFileFormat::NamePool:
@@ -278,7 +321,8 @@ bool ObjectLinker::mergeSections()
if (!(*sect)->hasRelocData())
continue; // skip
- if ((*sect)->getLink()->kind() == LDFileFormat::Ignore)
+ if ((*sect)->getLink()->kind() == LDFileFormat::Ignore ||
+ (*sect)->getLink()->kind() == LDFileFormat::Folded)
(*sect)->setKind(LDFileFormat::Ignore);
break;
}
@@ -741,7 +785,7 @@ bool ObjectLinker::relocation()
/// emitOutput - emit the output file.
bool ObjectLinker::emitOutput(FileOutputBuffer& pOutput)
{
- return llvm::errc::success == getWriter()->writeObject(*m_pModule, pOutput);
+ return std::error_code() == getWriter()->writeObject(*m_pModule, pOutput);
}
diff --git a/lib/Object/SectionMap.cpp b/lib/Object/SectionMap.cpp
index 64c4a87..4453d42 100644
--- a/lib/Object/SectionMap.cpp
+++ b/lib/Object/SectionMap.cpp
@@ -46,7 +46,7 @@ SectionMap::Input::Input(const std::string& pName,
WildcardPattern::create(pName, WildcardPattern::SORT_NONE));
m_Spec.m_pWildcardSections = sections;
- m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+ m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
SectionData* sd = SectionData::Create(*m_pSection);
m_pSection->setSectionData(sd);
new NullFragment(sd);
@@ -59,7 +59,7 @@ SectionMap::Input::Input(const InputSectDesc& pInputDesc)
m_Spec.m_pWildcardFile = pInputDesc.spec().m_pWildcardFile;
m_Spec.m_pExcludeFiles = pInputDesc.spec().m_pExcludeFiles;
m_Spec.m_pWildcardSections = pInputDesc.spec().m_pWildcardSections;
- m_pSection = LDSection::Create("", LDFileFormat::Regular, 0, 0);
+ m_pSection = LDSection::Create("", LDFileFormat::TEXT, 0, 0);
SectionData* sd = SectionData::Create(*m_pSection);
m_pSection->setSectionData(sd);
new NullFragment(sd);
@@ -85,7 +85,7 @@ SectionMap::Output::Output(const std::string& pName)
m_Epilog.m_pPhdrs = NULL;
m_Epilog.m_pFillExp = NULL;
- m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+ m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
SectionData* sd = SectionData::Create(*m_pSection);
m_pSection->setSectionData(sd);
@@ -98,7 +98,7 @@ SectionMap::Output::Output(const OutputSectDesc& pOutputDesc)
m_Epilog(pOutputDesc.epilog()),
m_Order(UINT_MAX)
{
- m_pSection = LDSection::Create(m_Name, LDFileFormat::Regular, 0, 0);
+ m_pSection = LDSection::Create(m_Name, LDFileFormat::TEXT, 0, 0);
SectionData* sd = SectionData::Create(*m_pSection);
m_pSection->setSectionData(sd);
diff --git a/lib/Support/Demangle.cpp b/lib/Support/Demangle.cpp
new file mode 100644
index 0000000..6db5c34
--- /dev/null
+++ b/lib/Support/Demangle.cpp
@@ -0,0 +1,76 @@
+//===- Demangle.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Config/Config.h>
+#include <mcld/Support/CXADemangle.tcc>
+#include <mcld/Support/Demangle.h>
+
+#ifdef HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
+namespace mcld {
+
+std::string demangleName(const std::string& pName) {
+#ifdef HAVE_CXXABI_H
+ // Spoil names of symbols with C linkage, so use an heuristic approach to
+ // check if the name should be demangled.
+ if (pName.substr(0, 2) != "_Z")
+ return pName;
+ // __cxa_demangle needs manually handle the memory release, so we wrap
+ // it into this helper function.
+ size_t output_leng;
+ int status;
+ char* buffer = abi::__cxa_demangle(pName.c_str(), /*buffer=*/0,
+ &output_leng, &status);
+ if (status != 0) { // Failed
+ return pName;
+ }
+ std::string result(buffer);
+ free(buffer);
+
+ return result;
+#else
+ return pName;
+#endif
+}
+
+bool isCtorOrDtor(const char* pName, size_t pLength)
+{
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ demangle(pName, pName + pLength, db, internal_status);
+ if (internal_status == success &&
+ db.fix_forward_references &&
+ !db.template_param.empty() &&
+ !db.template_param.front().empty()) {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(pName, pName + pLength, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+
+ if (internal_status != success) {
+ db.parsed_ctor_dtor_cv = false;
+ }
+ return db.parsed_ctor_dtor_cv;
+}
+
+} // namespace mcld
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
index ed8c898..4887e6b 100644
--- a/lib/Support/FileOutputBuffer.cpp
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -25,25 +25,25 @@ FileOutputBuffer::~FileOutputBuffer()
m_pRegion.reset(0);
}
-llvm::error_code FileOutputBuffer::create(FileHandle& pFileHandle,
- size_t pSize, llvm::OwningPtr<FileOutputBuffer>& pResult)
+std::error_code FileOutputBuffer::create(FileHandle& pFileHandle,
+ size_t pSize, std::unique_ptr<FileOutputBuffer>& pResult)
{
- llvm::error_code EC;
- llvm::OwningPtr<mapped_file_region> mapped_file(new mapped_file_region(
+ std::error_code ec;
+ std::unique_ptr<mapped_file_region> mapped_file(new mapped_file_region(
pFileHandle.handler(),
false,
mapped_file_region::readwrite,
pSize,
0,
- EC));
+ ec));
- if (EC)
- return EC;
+ if (ec)
+ return ec;
pResult.reset(new FileOutputBuffer(mapped_file.get(), pFileHandle));
if (pResult)
- mapped_file.take();
- return llvm::error_code::success();
+ mapped_file.release();
+ return std::error_code();
}
MemoryRegion FileOutputBuffer::request(size_t pOffset, size_t pLength)
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index 0c7f3c1..548ac72 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -8,9 +8,11 @@
//===----------------------------------------------------------------------===//
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
-#include <llvm/Support/system_error.h>
+
+#include <llvm/Support/ErrorOr.h>
#include <cassert>
+#include <system_error>
using namespace mcld;
@@ -19,12 +21,13 @@ using namespace mcld;
//===--------------------------------------------------------------------===//
MemoryArea::MemoryArea(llvm::StringRef pFilename)
{
- llvm::error_code ec =
- llvm::MemoryBuffer::getFile(pFilename, m_pMemoryBuffer, /*FileSize*/ -1,
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer_or_error =
+ llvm::MemoryBuffer::getFile(pFilename, /*FileSize*/ -1,
/*RequiresNullTerminator*/ false);
- if (ec != llvm::errc::success) {
+ if (std::error_code ec = buffer_or_error.getError()) {
fatal(diag::fatal_cannot_read_input) << pFilename.str();
}
+ m_pMemoryBuffer = std::move(buffer_or_error.get());
}
MemoryArea::MemoryArea(const char* pMemBuffer, size_t pSize)
diff --git a/lib/Target/AArch64/AArch64LDBackend.cpp b/lib/Target/AArch64/AArch64LDBackend.cpp
index 09f6766..cf07428 100644
--- a/lib/Target/AArch64/AArch64LDBackend.cpp
+++ b/lib/Target/AArch64/AArch64LDBackend.cpp
@@ -152,6 +152,12 @@ bool AArch64GNULDBackend::initRelocator()
return true;
}
+const Relocator* AArch64GNULDBackend::getRelocator() const
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
Relocator* AArch64GNULDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
diff --git a/lib/Target/AArch64/AArch64LDBackend.h b/lib/Target/AArch64/AArch64LDBackend.h
index c79bfa6..00e14fa 100644
--- a/lib/Target/AArch64/AArch64LDBackend.h
+++ b/lib/Target/AArch64/AArch64LDBackend.h
@@ -27,6 +27,10 @@ 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));
+
+public:
AArch64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo);
~AArch64GNULDBackend();
@@ -41,9 +45,9 @@ public:
bool initRelocator();
/// getRelocator - return relocator.
+ const Relocator* getRelocator() const;
Relocator* getRelocator();
-
/// doPreLayout - Backend can do any needed modification before layout
void doPreLayout(IRBuilder& pBuilder);
@@ -110,9 +114,8 @@ public:
private:
void defineGOTSymbol(IRBuilder& pBuilder);
- /// maxBranchOffset
- /// FIXME:
- uint64_t maxBranchOffset() { return 0x0; }
+ int64_t maxFwdBranchOffset() { return AARCH64_MAX_FWD_BRANCH_OFFSET; }
+ int64_t maxBwdBranchOffset() { return AARCH64_MAX_BWD_BRANCH_OFFSET; }
/// mayRelax - Backends should override this function if they need relaxation
bool mayRelax() { return true; }
diff --git a/lib/Target/ARM/ARMELFAttributeData.cpp b/lib/Target/ARM/ARMELFAttributeData.cpp
index afab867..8656b7e 100644
--- a/lib/Target/ARM/ARMELFAttributeData.cpp
+++ b/lib/Target/ARM/ARMELFAttributeData.cpp
@@ -1073,3 +1073,21 @@ size_t ARMELFAttributeData::emit(char *pBuf) const {
return (buffer - pBuf);
}
+
+bool ARMELFAttributeData::usingThumb() const
+{
+ int arch = m_Attrs[Tag_CPU_arch].getIntValue();
+ if ((arch == CPU_Arch_ARM_V6_M) || (arch == CPU_Arch_ARM_V6S_M))
+ return true;
+ if ((arch != CPU_Arch_ARM_V7) && (arch != CPU_Arch_ARM_V7E_M))
+ return false;
+
+ arch = m_Attrs[Tag_CPU_arch_profile].getIntValue();
+ return arch == Arch_Profile_Microcontroller;
+}
+
+bool ARMELFAttributeData::usingThumb2() const
+{
+ int arch = m_Attrs[Tag_CPU_arch].getIntValue();
+ return (arch == CPU_Arch_ARM_V6T2) || (arch == CPU_Arch_ARM_V7);
+}
diff --git a/lib/Target/ARM/ARMELFAttributeData.h b/lib/Target/ARM/ARMELFAttributeData.h
index c4128fa..1183b3d 100644
--- a/lib/Target/ARM/ARMELFAttributeData.h
+++ b/lib/Target/ARM/ARMELFAttributeData.h
@@ -180,6 +180,10 @@ public:
virtual size_t emit(char *pBuf) const;
+ virtual bool usingThumb() const;
+
+ virtual bool usingThumb2() const;
+
private:
/// GetAttributeValueType - obtain the value type of the indicated tag.
static unsigned int GetAttributeValueType(TagType pTag);
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index e0ca782..2b30df8 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -17,13 +17,6 @@
#include "THMToTHMStub.h"
#include "THMToARMStub.h"
-#include <cstring>
-
-#include <llvm/ADT/Triple.h>
-#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/Casting.h>
-
#include <mcld/IRBuilder.h>
#include <mcld/LinkerConfig.h>
#include <mcld/Fragment/FillFragment.h>
@@ -45,6 +38,14 @@
#include <mcld/Target/GNUInfo.h>
#include <mcld/Object/ObjectBuilder.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Casting.h>
+
+#include <cstring>
+
using namespace mcld;
//===----------------------------------------------------------------------===//
@@ -205,6 +206,12 @@ bool ARMGNULDBackend::initRelocator()
return true;
}
+const Relocator* ARMGNULDBackend::getRelocator() const
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
Relocator* ARMGNULDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
@@ -471,7 +478,8 @@ void ARMGNULDBackend::setUpReachedSectionsForGC(const Module& pModule,
// the reference
const LDSection* target_sect =
&sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
- if (target_sect->kind() != LDFileFormat::Regular &&
+ if (target_sect->kind() != LDFileFormat::TEXT &&
+ target_sect->kind() != LDFileFormat::DATA &&
target_sect->kind() != LDFileFormat::BSS)
continue;
@@ -716,13 +724,35 @@ bool ARMGNULDBackend::initTargetStubs()
if (NULL != getStubFactory()) {
getStubFactory()->addPrototype(new ARMToARMStub(config().isCodeIndep()));
getStubFactory()->addPrototype(new ARMToTHMStub(config().isCodeIndep()));
- getStubFactory()->addPrototype(new THMToTHMStub(config().isCodeIndep()));
- getStubFactory()->addPrototype(new THMToARMStub(config().isCodeIndep()));
+ getStubFactory()->addPrototype(
+ new THMToTHMStub(config().isCodeIndep(), m_pAttrData->usingThumb2()));
+ getStubFactory()->addPrototype(
+ new THMToARMStub(config().isCodeIndep(), m_pAttrData->usingThumb2()));
return true;
}
return false;
}
+/// maxFwdBranchOffset
+int64_t ARMGNULDBackend::maxFwdBranchOffset()
+{
+ if (m_pAttrData->usingThumb2()) {
+ return THM2_MAX_FWD_BRANCH_OFFSET;
+ } else {
+ return THM_MAX_FWD_BRANCH_OFFSET;
+ }
+}
+
+/// maxBwdBranchOffset
+int64_t ARMGNULDBackend::maxBwdBranchOffset()
+{
+ if (m_pAttrData->usingThumb2()) {
+ return THM2_MAX_BWD_BRANCH_OFFSET;
+ } else {
+ return THM_MAX_BWD_BRANCH_OFFSET;
+ }
+}
+
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule)
@@ -735,6 +765,19 @@ void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule)
}
}
+/// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+/// function pointer access
+bool
+ARMGNULDBackend::mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+ const
+{
+ llvm::StringRef name(pSection.name());
+ return !name.startswith(".ARM.exidx") &&
+ !name.startswith(".ARM.extab") &&
+ GNULDBackend::mayHaveUnsafeFunctionPointerAccess(pSection);
+}
+
+
namespace mcld {
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index cae589d..14d3fde 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -55,9 +55,9 @@ public:
bool initRelocator();
/// getRelocator - return relocator.
+ const Relocator* getRelocator() const;
Relocator* getRelocator();
-
/// doPreLayout - Backend can do any needed modification before layout
void doPreLayout(IRBuilder& pBuilder);
@@ -126,12 +126,17 @@ public:
/// readSection - read target dependent sections
bool readSection(Input& pInput, SectionData& pSD);
+ /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+ /// function pointer access
+ bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection) const;
+
private:
void defineGOTSymbol(IRBuilder& pBuilder);
- /// maxBranchOffset
- /// FIXME: if we can handle arm attributes, we may refine this!
- uint64_t maxBranchOffset() { return THM_MAX_FWD_BRANCH_OFFSET; }
+ /// maxFwdBranchOffset
+ int64_t maxFwdBranchOffset();
+ /// maxBwdBranchOffset
+ int64_t maxBwdBranchOffset();
/// mayRelax - Backends should override this function if they need relaxation
bool mayRelax() { return true; }
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
index 790ed1f..58f00ce 100644
--- a/lib/Target/ARM/ARMRelocationFunctions.h
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -32,6 +32,7 @@ DECL_ARM_APPLY_RELOC_FUNC(thm_movt_prel) \
DECL_ARM_APPLY_RELOC_FUNC(prel31) \
DECL_ARM_APPLY_RELOC_FUNC(got_prel) \
DECL_ARM_APPLY_RELOC_FUNC(tls) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_jump8) \
DECL_ARM_APPLY_RELOC_FUNC(thm_jump11) \
DECL_ARM_APPLY_RELOC_FUNC(thm_jump19) \
DECL_ARM_APPLY_RELOC_FUNC(unsupport)
@@ -141,7 +142,7 @@ DECL_ARM_APPLY_RELOC_FUNC(unsupport)
{ &unsupport, 100, "R_ARM_GNU_VTENTRY" }, \
{ &unsupport, 101, "R_ARM_GNU_VTINERIT" }, \
{ &thm_jump11, 102, "R_ARM_THM_JUMP11" }, \
- { &unsupport, 103, "R_ARM_THM_JUMP8" }, \
+ { &thm_jump8, 103, "R_ARM_THM_JUMP8" }, \
{ &tls, 104, "R_ARM_TLS_GD32" }, \
{ &unsupport, 105, "R_ARM_TLS_LDM32" }, \
{ &unsupport, 106, "R_ARM_TLS_LDO32" }, \
diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp
index 088b219..248c528 100644
--- a/lib/Target/ARM/ARMRelocator.cpp
+++ b/lib/Target/ARM/ARMRelocator.cpp
@@ -460,6 +460,29 @@ void ARMRelocator::checkValidReloc(Relocation& pReloc) const
}
}
+bool ARMRelocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+ switch (pReloc.type()) {
+ case llvm::ELF::R_ARM_PC24:
+ case llvm::ELF::R_ARM_THM_CALL:
+ case llvm::ELF::R_ARM_PLT32:
+ case llvm::ELF::R_ARM_CALL:
+ case llvm::ELF::R_ARM_JUMP24:
+ case llvm::ELF::R_ARM_THM_JUMP24:
+ case llvm::ELF::R_ARM_SBREL31:
+ case llvm::ELF::R_ARM_PREL31:
+ case llvm::ELF::R_ARM_THM_JUMP19:
+ case llvm::ELF::R_ARM_THM_JUMP6:
+ case llvm::ELF::R_ARM_THM_JUMP11:
+ case llvm::ELF::R_ARM_THM_JUMP8: {
+ return false;
+ }
+ default: {
+ return true;
+ }
+ }
+}
+
void
ARMRelocator::scanLocalReloc(Relocation& pReloc, const LDSection& pSection)
{
@@ -936,6 +959,25 @@ ARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent)
return Relocator::OK;
}
+// R_ARM_THM_JUMP8: S + A - P
+ARMRelocator::Result thm_jump8(Relocation& pReloc, ARMRelocator& pParent)
+{
+ Relocator::DWord P = pReloc.place();
+ Relocator::DWord A = helper_sign_extend((pReloc.target() & 0x00ff) << 1, 8) +
+ pReloc.addend();
+ // S depends on PLT exists or not
+ Relocator::Address S = pReloc.symValue();
+ if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)
+ S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
+
+ Relocator::DWord X = S + A - P;
+ if (helper_check_signed_overflow(X, 9))
+ return Relocator::Overflow;
+ // Make sure the Imm is 0. Result Mask.
+ pReloc.target() = (pReloc.target() & 0xFFFFFF00u) | ((X & 0x01FEu) >> 1);
+ return Relocator::OK;
+}
+
// R_ARM_THM_JUMP11: S + A - P
ARMRelocator::Result thm_jump11(Relocation& pReloc, ARMRelocator& pParent)
{
@@ -948,7 +990,7 @@ ARMRelocator::Result thm_jump11(Relocation& pReloc, ARMRelocator& pParent)
S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
Relocator::DWord X = S + A - P;
- if (helper_check_signed_overflow(X, 11))
+ if (helper_check_signed_overflow(X, 12))
return Relocator::Overflow;
// Make sure the Imm is 0. Result Mask.
pReloc.target() = (pReloc.target() & 0xFFFFF800u) | ((X & 0x0FFEu) >> 1);
diff --git a/lib/Target/ARM/ARMRelocator.h b/lib/Target/ARM/ARMRelocator.h
index da4e96b..9c3156b 100644
--- a/lib/Target/ARM/ARMRelocator.h
+++ b/lib/Target/ARM/ARMRelocator.h
@@ -98,6 +98,11 @@ public:
LDSection& pSection,
Input& pInput);
+
+ /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+ /// access a function pointer.
+ virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
private:
void scanLocalReloc(Relocation& pReloc, const LDSection& pSection);
diff --git a/lib/Target/ARM/ARMToARMStub.cpp b/lib/Target/ARM/ARMToARMStub.cpp
index 3f5e6f6..ba3acf4 100644
--- a/lib/Target/ARM/ARMToARMStub.cpp
+++ b/lib/Target/ARM/ARMToARMStub.cpp
@@ -32,7 +32,7 @@ const uint32_t ARMToARMStub::TEMPLATE[] = {
};
ARMToARMStub::ARMToARMStub(bool pIsOutputPIC)
- : Stub(), m_Name("A2A_prototype"), m_pData(NULL), m_Size(0x0)
+ : m_pData(NULL), m_Name("A2A_prototype"), m_Size(0x0)
{
if (pIsOutputPIC) {
m_pData = PIC_TEMPLATE;
@@ -51,7 +51,7 @@ ARMToARMStub::ARMToARMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
const_fixup_iterator pEnd)
- : Stub(), m_Name("A2A_veneer"), m_pData(pData), m_Size(pSize)
+ : m_pData(pData), m_Name("A2A_veneer"), m_Size(pSize)
{
for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
addFixup(**it);
@@ -113,4 +113,3 @@ Stub* ARMToARMStub::doClone()
{
return new ARMToARMStub(m_pData, m_Size, fixup_begin(), fixup_end());
}
-
diff --git a/lib/Target/ARM/ARMToARMStub.h b/lib/Target/ARM/ARMToARMStub.h
index a38dd90..afb26a8 100644
--- a/lib/Target/ARM/ARMToARMStub.h
+++ b/lib/Target/ARM/ARMToARMStub.h
@@ -61,10 +61,10 @@ private:
Stub* doClone();
private:
- std::string m_Name;
static const uint32_t PIC_TEMPLATE[];
static const uint32_t TEMPLATE[];
const uint32_t* m_pData;
+ std::string m_Name;
size_t m_Size;
};
diff --git a/lib/Target/ARM/ARMToTHMStub.cpp b/lib/Target/ARM/ARMToTHMStub.cpp
index 702df38..a46a0c8 100644
--- a/lib/Target/ARM/ARMToTHMStub.cpp
+++ b/lib/Target/ARM/ARMToTHMStub.cpp
@@ -34,7 +34,7 @@ const uint32_t ARMToTHMStub::TEMPLATE[] = {
};
ARMToTHMStub::ARMToTHMStub(bool pIsOutputPIC)
- : Stub(), m_Name("A2T_prototype"), m_pData(NULL), m_Size(0x0)
+ : m_pData(NULL), m_Name("A2T_prototype"), m_Size(0x0)
{
if (pIsOutputPIC) {
m_pData = PIC_TEMPLATE;
@@ -53,7 +53,7 @@ ARMToTHMStub::ARMToTHMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
const_fixup_iterator pEnd)
- : Stub(), m_Name("A2T_veneer"), m_pData(pData), m_Size(pSize)
+ : m_pData(pData), m_Name("A2T_veneer"), m_Size(pSize)
{
for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
addFixup(**it);
@@ -121,4 +121,3 @@ Stub* ARMToTHMStub::doClone()
{
return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
}
-
diff --git a/lib/Target/ARM/ARMToTHMStub.h b/lib/Target/ARM/ARMToTHMStub.h
index f39db84..e7a44bf 100644
--- a/lib/Target/ARM/ARMToTHMStub.h
+++ b/lib/Target/ARM/ARMToTHMStub.h
@@ -61,10 +61,10 @@ private:
Stub* doClone();
private:
- std::string m_Name;
static const uint32_t PIC_TEMPLATE[];
static const uint32_t TEMPLATE[];
const uint32_t* m_pData;
+ std::string m_Name;
size_t m_Size;
};
diff --git a/lib/Target/ARM/THMToARMStub.cpp b/lib/Target/ARM/THMToARMStub.cpp
index e32222e..34e0cbf 100644
--- a/lib/Target/ARM/THMToARMStub.cpp
+++ b/lib/Target/ARM/THMToARMStub.cpp
@@ -33,15 +33,17 @@ const uint32_t THMToARMStub::TEMPLATE[] = {
0x0 // dcd R_ARM_ABS32(X)
};
-THMToARMStub::THMToARMStub(bool pIsOutputPIC)
- : Stub(), m_Name("T2A_prototype"), m_pData(NULL), m_Size(0x0)
+THMToARMStub::THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2)
+ : m_pData(NULL),
+ m_Name("T2A_prototype"),
+ m_Size(0x0),
+ m_bUsingThumb2(pUsingThumb2)
{
if (pIsOutputPIC) {
m_pData = PIC_TEMPLATE;
m_Size = sizeof(PIC_TEMPLATE);
addFixup(12u, -4, llvm::ELF::R_ARM_REL32);
- }
- else {
+ } else {
m_pData = TEMPLATE;
m_Size = sizeof(TEMPLATE);
addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
@@ -52,8 +54,12 @@ THMToARMStub::THMToARMStub(bool pIsOutputPIC)
THMToARMStub::THMToARMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
- const_fixup_iterator pEnd)
- : Stub(), m_Name("T2A_veneer"), m_pData(pData), m_Size(pSize)
+ const_fixup_iterator pEnd,
+ bool pUsingThumb2)
+ : m_pData(pData),
+ m_Name("T2A_veneer"),
+ m_Size(pSize),
+ m_bUsingThumb2(pUsingThumb2)
{
for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
addFixup(**it);
@@ -76,9 +82,19 @@ bool THMToARMStub::isMyDuty(const class Relocation& pReloc,
// then, we do not need a stub unless the branch target is too far.
uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
- if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
- (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET))
- result = true;
+ if (m_bUsingThumb2) {
+ if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
+ (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
+ result = true;
+ break;
+ }
+ } else {
+ if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
+ (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
+ result = true;
+ break;
+ }
+ }
break;
}
case llvm::ELF::R_ARM_THM_JUMP24: {
@@ -121,6 +137,9 @@ uint64_t THMToARMStub::initSymValue() const
Stub* THMToARMStub::doClone()
{
- return new THMToARMStub(m_pData, m_Size, fixup_begin(), fixup_end());
+ return new THMToARMStub(m_pData,
+ m_Size,
+ fixup_begin(),
+ fixup_end(),
+ m_bUsingThumb2);
}
-
diff --git a/lib/Target/ARM/THMToARMStub.h b/lib/Target/ARM/THMToARMStub.h
index a7b6cad..af5a926 100644
--- a/lib/Target/ARM/THMToARMStub.h
+++ b/lib/Target/ARM/THMToARMStub.h
@@ -13,7 +13,6 @@
#include <llvm/Support/DataTypes.h>
#include <mcld/Fragment/Stub.h>
#include <string>
-#include <vector>
namespace mcld
{
@@ -28,7 +27,7 @@ class ResolveInfo;
class THMToARMStub : public Stub
{
public:
- THMToARMStub(bool pIsOutputPIC);
+ THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2);
~THMToARMStub();
@@ -58,17 +57,19 @@ private:
THMToARMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
- const_fixup_iterator pEnd);
+ const_fixup_iterator pEnd,
+ bool pUsingThumb2);
/// doClone
Stub* doClone();
private:
- std::string m_Name;
static const uint32_t PIC_TEMPLATE[];
static const uint32_t TEMPLATE[];
const uint32_t* m_pData;
+ std::string m_Name;
size_t m_Size;
+ bool m_bUsingThumb2;
};
} // namespace of mcld
diff --git a/lib/Target/ARM/THMToTHMStub.cpp b/lib/Target/ARM/THMToTHMStub.cpp
index b58de77..f167f28 100644
--- a/lib/Target/ARM/THMToTHMStub.cpp
+++ b/lib/Target/ARM/THMToTHMStub.cpp
@@ -35,15 +35,17 @@ const uint32_t THMToTHMStub::TEMPLATE[] = {
0x0 // dcd R_ARM_ABS32(X)
};
-THMToTHMStub::THMToTHMStub(bool pIsOutputPIC)
- : Stub(), m_Name("T2T_prototype"), m_pData(NULL), m_Size(0x0)
+THMToTHMStub::THMToTHMStub(bool pIsOutputPIC, bool pUsingThumb2)
+ : m_pData(NULL),
+ m_Name("T2T_prototype"),
+ m_Size(0x0),
+ m_bUsingThumb2(pUsingThumb2)
{
if (pIsOutputPIC) {
m_pData = PIC_TEMPLATE;
m_Size = sizeof(PIC_TEMPLATE);
addFixup(16u, 0x0, llvm::ELF::R_ARM_REL32);
- }
- else {
+ } else {
m_pData = TEMPLATE;
m_Size = sizeof(TEMPLATE);
addFixup(12u, 0x0, llvm::ELF::R_ARM_ABS32);
@@ -54,8 +56,12 @@ THMToTHMStub::THMToTHMStub(bool pIsOutputPIC)
THMToTHMStub::THMToTHMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
- const_fixup_iterator pEnd)
- : Stub(), m_Name("T2T_veneer"), m_pData(pData), m_Size(pSize)
+ const_fixup_iterator pEnd,
+ bool pUsingThumb2)
+ : m_pData(pData),
+ m_Name("T2T_veneer"),
+ m_Size(pSize),
+ m_bUsingThumb2(pUsingThumb2)
{
for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
addFixup(**it);
@@ -78,9 +84,19 @@ bool THMToTHMStub::isMyDuty(const class Relocation& pReloc,
// Check if the branch target is too far
uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
- if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
- (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET))
- result = true;
+ if (m_bUsingThumb2) {
+ if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
+ (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
+ result = true;
+ break;
+ }
+ } else {
+ if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
+ (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
+ result = true;
+ break;
+ }
+ }
break;
}
default:
@@ -117,6 +133,9 @@ uint64_t THMToTHMStub::initSymValue() const
Stub* THMToTHMStub::doClone()
{
- return new THMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
+ return new THMToTHMStub(m_pData,
+ m_Size,
+ fixup_begin(),
+ fixup_end(),
+ m_bUsingThumb2);
}
-
diff --git a/lib/Target/ARM/THMToTHMStub.h b/lib/Target/ARM/THMToTHMStub.h
index f6d155e..4f3f363 100644
--- a/lib/Target/ARM/THMToTHMStub.h
+++ b/lib/Target/ARM/THMToTHMStub.h
@@ -13,7 +13,6 @@
#include <llvm/Support/DataTypes.h>
#include <mcld/Fragment/Stub.h>
#include <string>
-#include <vector>
namespace mcld
{
@@ -28,7 +27,7 @@ class ResolveInfo;
class THMToTHMStub : public Stub
{
public:
- THMToTHMStub(bool pIsOutputPIC);
+ THMToTHMStub(bool pIsOutputPIC, bool pUsingThumb2);
~THMToTHMStub();
@@ -58,17 +57,19 @@ private:
THMToTHMStub(const uint32_t* pData,
size_t pSize,
const_fixup_iterator pBegin,
- const_fixup_iterator pEnd);
+ const_fixup_iterator pEnd,
+ bool pUsingThumb2);
/// doClone
Stub* doClone();
private:
- std::string m_Name;
static const uint32_t PIC_TEMPLATE[];
static const uint32_t TEMPLATE[];
const uint32_t* m_pData;
+ std::string m_Name;
size_t m_Size;
+ bool m_bUsingThumb2;
};
} // namespace of mcld
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index e888bc9..7021c5f 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -8,13 +8,6 @@
//===----------------------------------------------------------------------===//
#include <mcld/Target/GNULDBackend.h>
-#include <string>
-#include <cstring>
-#include <cassert>
-#include <vector>
-#include <algorithm>
-#include <map>
-
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
#include <mcld/LinkerScript.h>
@@ -49,8 +42,16 @@
#include <mcld/Fragment/FillFragment.h>
#include <mcld/MC/Attribute.h>
+#include <llvm/ADT/StringRef.h>
#include <llvm/Support/Host.h>
+#include <algorithm>
+#include <cstring>
+#include <cassert>
+#include <map>
+#include <string>
+#include <vector>
+
namespace {
//===--------------------------------------------------------------------===//
@@ -1380,7 +1381,8 @@ unsigned int GNULDBackend::getSectionOrder(const LDSection& pSectHdr) const
bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
// TODO: need to take care other possible output sections
switch (pSectHdr.kind()) {
- case LDFileFormat::Regular:
+ case LDFileFormat::TEXT:
+ case LDFileFormat::DATA:
if (is_exec) {
if (&pSectHdr == &file_format->getInit())
return SHO_INIT;
@@ -2415,7 +2417,8 @@ void GNULDBackend::placeOutputSections(Module& pModule)
config().codeGenType() == LinkerConfig::Object))
wanted = true;
break;
- case LDFileFormat::Regular:
+ case LDFileFormat::TEXT:
+ case LDFileFormat::DATA:
case LDFileFormat::Target:
case LDFileFormat::MetaData:
case LDFileFormat::BSS:
@@ -2580,6 +2583,19 @@ void GNULDBackend::createAndSizeEhFrameHdr(Module& pModule)
}
}
+/// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+/// function pointer access
+bool GNULDBackend::mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+ const
+{
+ llvm::StringRef name(pSection.name());
+ return !name.startswith(".rodata._ZTV") &&
+ !name.startswith(".data.rel.ro._ZTV") &&
+ !name.startswith(".rodata._ZTC") &&
+ !name.startswith(".data.rel.ro._ZTC") &&
+ !name.startswith(".eh_frame");
+}
+
/// preLayout - Backend can do any needed modification before layout
void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder)
{
@@ -3014,7 +3030,8 @@ void GNULDBackend::sortRelocation(LDSection& pSection)
bool GNULDBackend::initBRIslandFactory()
{
if (NULL == m_pBRIslandFactory) {
- m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset());
+ m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(),
+ maxBwdBranchOffset());
}
return true;
}
diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp
index 9d16804..eb3458b 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.cpp
+++ b/lib/Target/Hexagon/HexagonLDBackend.cpp
@@ -72,6 +72,12 @@ bool HexagonLDBackend::initRelocator()
return true;
}
+const Relocator* HexagonLDBackend::getRelocator() const
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
Relocator* HexagonLDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
@@ -553,7 +559,9 @@ bool HexagonLDBackend::initTargetStubs()
bool HexagonLDBackend::initBRIslandFactory()
{
if (NULL == m_pBRIslandFactory) {
- m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset(), 0);
+ m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(),
+ maxBwdBranchOffset(),
+ 0);
}
return true;
}
diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h
index 21d2e38..0fc909c 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.h
+++ b/lib/Target/Hexagon/HexagonLDBackend.h
@@ -83,6 +83,7 @@ public:
bool initRelocator();
/// getRelocator - return relocator.
+ const Relocator* getRelocator() const;
Relocator* getRelocator();
ResolveInfo::Desc getSymDesc(uint16_t shndx) const
@@ -162,7 +163,8 @@ private:
/// target-dependent segments
void doCreateProgramHdrs(Module& pModule);
- uint64_t maxBranchOffset() { return ~(~0 << 6); }
+ /// maxFwdBranchOffset
+ int64_t maxFwdBranchOffset() { return ~(~0 << 6); }
virtual void setGOTSectionSize(IRBuilder& pBuilder);
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index 46c580d..9714e91 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -143,6 +143,21 @@ void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
+ pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>(
+ "_gp",
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ FragmentRef::Null(), // FragRef
+ ResolveInfo::Default);
+}
+
+const Relocator* MipsGNULDBackend::getRelocator() const
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
}
Relocator* MipsGNULDBackend::getRelocator()
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index 78c5c58..991b3c4 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -47,6 +47,7 @@ public:
void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
/// getRelocator - return relocator.
+ const Relocator* getRelocator() const;
Relocator* getRelocator();
/// preLayout - Backend can do any needed modification before layout
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index f105dd3..eb4c6c6 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -72,6 +72,12 @@ X86GNULDBackend::~X86GNULDBackend()
delete m_pDynamic;
}
+const Relocator* X86GNULDBackend::getRelocator() const
+{
+ assert(NULL != m_pRelocator);
+ return m_pRelocator;
+}
+
Relocator* X86GNULDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index 779c2d1..503fca9 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -76,6 +76,7 @@ public:
virtual bool initRelocator() = 0;
/// getRelocator - return relocator.
+ const Relocator* getRelocator() const;
Relocator* getRelocator();
virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) = 0;
diff --git a/lib/Target/X86/X86Relocator.cpp b/lib/Target/X86/X86Relocator.cpp
index 8cc916e..794296b 100644
--- a/lib/Target/X86/X86Relocator.cpp
+++ b/lib/Target/X86/X86Relocator.cpp
@@ -323,6 +323,23 @@ Relocator::Size X86_32Relocator::getSize(Relocation::Type pType) const
return X86_32ApplyFunctions[pType].size;;
}
+bool
+X86_32Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+ switch (pReloc.type()) {
+ case llvm::ELF::R_386_32:
+ case llvm::ELF::R_386_16:
+ case llvm::ELF::R_386_8:
+ case llvm::ELF::R_386_GOTOFF:
+ case llvm::ELF::R_386_GOT32: {
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
void X86_32Relocator::scanLocalReloc(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
@@ -1297,6 +1314,40 @@ Relocator::Size X86_64Relocator::getSize(Relocation::Type pType) const
return X86_64ApplyFunctions[pType].size;
}
+bool
+X86_64Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+ bool possible_funcptr_reloc = false;
+ switch (pReloc.type()) {
+ case llvm::ELF::R_X86_64_64:
+ case llvm::ELF::R_X86_64_32:
+ case llvm::ELF::R_X86_64_32S:
+ case llvm::ELF::R_X86_64_16:
+ case llvm::ELF::R_X86_64_8:
+ case llvm::ELF::R_X86_64_GOT64:
+ case llvm::ELF::R_X86_64_GOT32:
+ case llvm::ELF::R_X86_64_GOTPCREL64:
+ case llvm::ELF::R_X86_64_GOTPCREL:
+ case llvm::ELF::R_X86_64_GOTPLT64: {
+ possible_funcptr_reloc = true;
+ break;
+ }
+ default: {
+ possible_funcptr_reloc = false;
+ break;
+ }
+ }
+
+ if (pReloc.symInfo()->isGlobal()) {
+ return (config().codeGenType() == LinkerConfig::DynObj) &&
+ ((pReloc.symInfo()->visibility() != ResolveInfo::Default) ||
+ possible_funcptr_reloc);
+ } else {
+ return (config().codeGenType() == LinkerConfig::DynObj) ||
+ possible_funcptr_reloc;
+ }
+}
+
void X86_64Relocator::scanLocalReloc(Relocation& pReloc,
IRBuilder& pBuilder,
Module& pModule,
diff --git a/lib/Target/X86/X86Relocator.h b/lib/Target/X86/X86Relocator.h
index caf259f..84170fe 100644
--- a/lib/Target/X86/X86Relocator.h
+++ b/lib/Target/X86/X86Relocator.h
@@ -151,6 +151,10 @@ public:
X86_32GOTEntry& getTLSModuleID();
+ /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+ /// access a function pointer.
+ virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
private:
void scanLocalReloc(Relocation& pReloc,
IRBuilder& pBuilder,
@@ -207,6 +211,10 @@ public:
const RelRelMap& getRelRelMap() const { return m_RelRelMap; }
RelRelMap& getRelRelMap() { return m_RelRelMap; }
+ /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+ /// access a function pointer.
+ virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
private:
void scanLocalReloc(Relocation& pReloc,
IRBuilder& pBuilder,
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
deleted file mode 100644
index e984501..0000000
--- a/tools/llvm-mcld/llvm-mcld.cpp
+++ /dev/null
@@ -1,1552 +0,0 @@
-//===- llvm-mcld.cpp ------------------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Module.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LinkerScript.h>
-#include <mcld/Target/TargetMachine.h>
-#include <mcld/Support/TargetSelect.h>
-#include <mcld/Support/TargetRegistry.h>
-#include <mcld/Support/CommandLine.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/RealPath.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/FileSystem.h>
-#include <mcld/Support/raw_ostream.h>
-#include <mcld/Support/SystemUtils.h>
-#include <mcld/Support/ToolOutputFile.h>
-#include <mcld/LD/DiagnosticLineInfo.h>
-#include <mcld/LD/TextDiagnosticPrinter.h>
-
-#include <llvm/PassManager.h>
-#include <llvm/Pass.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/DataLayout.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/ADT/Triple.h>
-#include <llvm/ADT/StringSwitch.h>
-#include <llvm/MC/SubtargetFeature.h>
-#include <llvm/Support/CommandLine.h>
-#include <llvm/Support/Debug.h>
-#include <llvm/Support/FormattedStream.h>
-#include <llvm/Support/Host.h>
-#include <llvm/Support/IRReader.h>
-#include <llvm/Support/ManagedStatic.h>
-#include <llvm/Support/Signals.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/TargetSelect.h>
-#include <llvm/Support/Process.h>
-#include <llvm/Target/TargetMachine.h>
-
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-#include <io.h>
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif
-#endif
-
-using namespace llvm;
-
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-
-static cl::opt<bool>
-UnitTest("unittest", cl::desc("do unit test") );
-
-int unit_test( int argc, char* argv[] )
-{
- testing::InitGoogleTest( &argc, argv );
- return RUN_ALL_TESTS();
-}
-
-#endif
-
-// General options for llc. Other pass-specific options are specified
-// within the corresponding llc passes, and target-specific options
-// and back-end code generation options are specified with the target machine.
-//
-// Determine optimization level.
-static cl::opt<char>
-OptLevel("O",
- cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
- "(default = '-O2')"),
- cl::Prefix,
- cl::ZeroOrMore,
- cl::init(' '));
-
-static cl::opt<std::string>
-TargetTriple("mtriple", cl::desc("Override target triple for module"));
-
-static cl::opt<std::string>
-MArch("march", cl::desc("Architecture to generate code for (see --version)"));
-
-static cl::opt<std::string>
-MCPU("mcpu",
- cl::desc("Target a specific cpu type (-mcpu=help for details)"),
- cl::value_desc("cpu-name"),
- cl::init(""));
-
-static cl::list<std::string>
-MAttrs("mattr",
- cl::CommaSeparated,
- cl::desc("Target specific attributes (-mattr=help for details)"),
- cl::value_desc("a1,+a2,-a3,..."));
-
-static cl::opt<llvm::CodeModel::Model>
-CMModel("code-model",
- cl::desc("Choose code model"),
- cl::init(CodeModel::Default),
- cl::values(clEnumValN(CodeModel::Default, "default",
- "Target default code model"),
- clEnumValN(CodeModel::Small, "small",
- "Small code model"),
- clEnumValN(CodeModel::Kernel, "kernel",
- "Kernel code model"),
- clEnumValN(CodeModel::Medium, "medium",
- "Medium code model"),
- clEnumValN(CodeModel::Large, "large",
- "Large code model"),
- clEnumValEnd));
-
-cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
- cl::desc("Do not verify input module"));
-
-static cl::opt<bool>
-EnableFPMAD("enable-fp-mad",
- cl::desc("Enable less precise MAD instructions to be generated"),
- cl::init(false));
-
-static cl::opt<bool>
-DisableFPElim("disable-fp-elim",
- cl::desc("Disable frame pointer elimination optimization"),
- cl::init(false));
-
-static cl::opt<bool>
-DisableFPElimNonLeaf("disable-non-leaf-fp-elim",
- cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"),
- cl::init(false));
-
-static cl::opt<llvm::FPOpFusion::FPOpFusionMode>
-FuseFPOps("fuse-fp-ops",
- cl::desc("Enable aggresive formation of fused FP ops"),
- cl::init(FPOpFusion::Standard),
- cl::values(
- clEnumValN(FPOpFusion::Fast, "fast",
- "Fuse FP ops whenever profitable"),
- clEnumValN(FPOpFusion::Standard, "standard",
- "Only fuse 'blessed' FP ops."),
- clEnumValN(FPOpFusion::Strict, "strict",
- "Only fuse FP ops when the result won't be effected."),
- clEnumValEnd));
-
-static cl::opt<bool>
-EnableUnsafeFPMath("enable-unsafe-fp-math",
- cl::desc("Enable optimizations that may decrease FP precision"),
- cl::init(false));
-
-static cl::opt<bool>
-EnableNoInfsFPMath("enable-no-infs-fp-math",
- cl::desc("Enable FP math optimizations that assume no +-Infs"),
- cl::init(false));
-
-static cl::opt<bool>
-EnableNoNaNsFPMath("enable-no-nans-fp-math",
- cl::desc("Enable FP math optimizations that assume no NaNs"),
- cl::init(false));
-
-static cl::opt<bool>
-EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
- cl::Hidden,
- cl::desc("Force codegen to assume rounding mode can change dynamically"),
- cl::init(false));
-
-static cl::opt<bool>
-GenerateSoftFloatCalls("soft-float",
- cl::desc("Generate software floating point library calls"),
- cl::init(false));
-
-static cl::opt<llvm::FloatABI::ABIType>
-FloatABIForCalls("float-abi",
- cl::desc("Choose float ABI type"),
- cl::init(FloatABI::Default),
- cl::values(
- clEnumValN(FloatABI::Default, "default",
- "Target default float ABI type"),
- clEnumValN(FloatABI::Soft, "soft",
- "Soft float ABI (implied by -soft-float)"),
- clEnumValN(FloatABI::Hard, "hard",
- "Hard float ABI (uses FP registers)"),
- clEnumValEnd));
-
-static cl::opt<bool>
-DontPlaceZerosInBSS("nozero-initialized-in-bss",
- cl::desc("Don't place zero-initialized symbols into bss section"),
- cl::init(false));
-
-static cl::opt<bool>
-EnableJITExceptionHandling("jit-enable-eh",
- cl::desc("Emit exception handling information"),
- cl::init(false));
-
-// In debug builds, make this default to true.
-#ifdef NDEBUG
-#define EMIT_DEBUG false
-#else
-#define EMIT_DEBUG true
-#endif
-static cl::opt<bool>
-EmitJitDebugInfo("jit-emit-debug",
- cl::desc("Emit debug information to debugger"),
- cl::init(EMIT_DEBUG));
-#undef EMIT_DEBUG
-
-static cl::opt<bool>
-EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
- cl::Hidden,
- cl::desc("Emit debug info objfiles to disk"),
- cl::init(false));
-
-static cl::opt<bool>
-EnableGuaranteedTailCallOpt("tailcallopt",
- cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
- cl::init(false));
-
-static cl::opt<unsigned>
-OverrideStackAlignment("stack-alignment",
- cl::desc("Override default stack alignment"),
- cl::init(0));
-
-static cl::opt<bool>
-EnableRealignStack("realign-stack",
- cl::desc("Realign stack if needed"),
- cl::init(true));
-
-static cl::opt<std::string>
-TrapFuncName("trap-func", cl::Hidden,
- cl::desc("Emit a call to trap function rather than a trap instruction"),
- cl::init(""));
-
-static cl::opt<bool>
-SegmentedStacks("segmented-stacks",
- cl::desc("Use segmented stacks if possible."),
- cl::init(false));
-
-//===----------------------------------------------------------------------===//
-// Command Line Options
-// There are four kinds of command line options:
-// 1. Bitcode option. Used to represent a bitcode.
-// 2. Attribute options. Attributes describes the input file after them. For
-// example, --as-needed affects the input file after this option. Attribute
-// options are not attributes. Attribute options are the options that is
-// used to define a legal attribute.
-// 3. Scripting options, Used to represent a subset of link scripting
-// language, such as --defsym.
-// 4. General options. (the rest of options)
-//===----------------------------------------------------------------------===//
-// Bitcode Options
-//===----------------------------------------------------------------------===//
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgBitcodeFilename("dB",
- cl::desc("set default bitcode"),
- cl::value_desc("bitcode"));
-
-//===----------------------------------------------------------------------===//
-// General Options
-//===----------------------------------------------------------------------===//
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgOutputFilename("o",
- cl::desc("Output filename"),
- cl::value_desc("filename"));
-
-static cl::alias
-AliasOutputFilename("output",
- cl::desc("alias for -o"),
- cl::aliasopt(ArgOutputFilename));
-
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgSysRoot("sysroot",
- cl::desc("Use directory as the location of the sysroot, overriding the configure-time default."),
- cl::value_desc("directory"),
- cl::ValueRequired);
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgSearchDirList("L",
- cl::ZeroOrMore,
- cl::desc("Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts."),
- cl::value_desc("searchdir"),
- cl::Prefix);
-
-static cl::alias
-ArgSearchDirListAlias("library-path",
- cl::desc("alias for -L"),
- cl::aliasopt(ArgSearchDirList));
-
-static cl::opt<bool>
-ArgTrace("t",
- cl::desc("Print the names of the input files as ld processes them."));
-
-static cl::alias
-ArgTraceAlias("trace",
- cl::desc("alias for -t"),
- cl::aliasopt(ArgTrace));
-
-static cl::opt<int>
-ArgVerbose("verbose",
- cl::init(-1),
- cl::desc("Display the version number for ld and list the linker emulations supported."));
-
-static cl::opt<bool>
-ArgVersion("V",
- cl::init(false),
- cl::desc("Display the version number for MCLinker."));
-
-static cl::opt<int>
-ArgMaxErrorNum("error-limit",
- cl::init(-1),
- cl::desc("limits the maximum number of erros."));
-
-static cl::opt<int>
-ArgMaxWarnNum("warning-limit",
- cl::init(-1),
- cl::desc("limits the maximum number of warnings."));
-
-static cl::opt<std::string>
-ArgEntry("e",
- cl::desc("Use entry as the explicit symbol for beginning execution of your program."),
- cl::value_desc("entry"),
- cl::ValueRequired);
-
-static cl::alias
-ArgEntryAlias("entry",
- cl::desc("alias for -e"),
- cl::aliasopt(ArgEntry));
-
-static cl::opt<bool>
-ArgBsymbolic("Bsymbolic",
- cl::desc("Bind references within the shared library."),
- cl::init(false));
-
-static cl::opt<bool>
-ArgBgroup("Bgroup",
- cl::desc("Info the dynamic linker to perform lookups only inside the group."),
- cl::init(false));
-
-static cl::opt<std::string>
-ArgSOName("soname",
- cl::desc("Set internal name of shared library"),
- cl::value_desc("name"));
-
-static cl::opt<bool>
-ArgNoUndefined("no-undefined",
- cl::desc("Do not allow unresolved references"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgAllowMulDefs("allow-multiple-definition",
- cl::desc("Allow multiple definition"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgEhFrameHdr("eh-frame-hdr",
- cl::desc("Request creation of \".eh_frame_hdr\" section and ELF \"PT_GNU_EH_FRAME\" segment header."),
- cl::init(false));
-
-static cl::list<mcld::ZOption, bool, llvm::cl::parser<mcld::ZOption> >
-ArgZOptionList("z",
- cl::ZeroOrMore,
- cl::desc("The -z options for GNU ld compatibility."),
- cl::value_desc("keyword"),
- cl::Prefix);
-
-cl::opt<mcld::CodeGenFileType>
-ArgFileType("filetype", cl::init(mcld::CGFT_EXEFile),
- cl::desc("Choose a file type (not all types are supported by all targets):"),
- cl::values(
- clEnumValN(mcld::CGFT_ASMFile, "asm",
- "Emit an assembly ('.s') file"),
- clEnumValN(mcld::CGFT_OBJFile, "obj",
- "Emit a relocatable object ('.o') file"),
- clEnumValN(mcld::CGFT_DSOFile, "dso",
- "Emit an dynamic shared object ('.so') file"),
- clEnumValN(mcld::CGFT_EXEFile, "exe",
- "Emit a executable ('.exe') file"),
- clEnumValN(mcld::CGFT_NULLFile, "null",
- "Emit nothing, for performance testing"),
- clEnumValEnd));
-
-static cl::opt<bool>
-ArgShared("shared",
- cl::desc("Create a shared library."),
- cl::init(false));
-
-static cl::alias
-ArgSharedAlias("Bshareable",
- cl::desc("alias for -shared"),
- cl::aliasopt(ArgShared));
-
-static cl::opt<bool>
-ArgPIE("pie",
- cl::desc("Emit a position-independent executable file"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgRelocatable("relocatable",
- cl::desc("Generate relocatable output"),
- cl::init(false));
-
-static cl::alias
-ArgRelocatableAlias("r",
- cl::desc("alias for --relocatable"),
- cl::aliasopt(ArgRelocatable));
-
-static cl::opt<Reloc::Model>
-ArgRelocModel("relocation-model",
- cl::desc("Choose relocation model"),
- cl::init(Reloc::Default),
- cl::values(
- clEnumValN(Reloc::Default, "default",
- "Target default relocation model"),
- clEnumValN(Reloc::Static, "static",
- "Non-relocatable code"),
- clEnumValN(Reloc::PIC_, "pic",
- "Fully relocatable, position independent code"),
- clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
- "Relocatable external references, non-relocatable code"),
- clEnumValEnd));
-
-static cl::opt<bool>
-ArgFPIC("fPIC",
- cl::desc("Set relocation model to pic. The same as -relocation-model=pic."),
- cl::init(false));
-
-static cl::opt<std::string>
-ArgDyld("dynamic-linker",
- cl::ZeroOrMore,
- cl::desc("Set the name of the dynamic linker."),
- cl::value_desc("Program"));
-
-namespace color {
-enum Color {
- Never,
- Always,
- Auto
-};
-} // namespace of color
-
-static cl::opt<color::Color>
-ArgColor("color",
- cl::value_desc("WHEN"),
- cl::desc("Surround the result strings with the marker"),
- cl::init(color::Auto),
- cl::values(
- clEnumValN(color::Never, "never",
- "do not surround result strings"),
- clEnumValN(color::Always, "always",
- "always surround result strings, even the output is a plain file"),
- clEnumValN(color::Auto, "auto",
- "surround result strings only if the output is a tty"),
- clEnumValEnd));
-
-static cl::opt<bool>
-ArgDiscardLocals("discard-locals",
- cl::desc("Delete all temporary local symbols."),
- cl::init(false));
-
-static cl::alias
-ArgDiscardLocalsAlias("X",
- cl::desc("alias for --discard-locals"),
- cl::aliasopt(ArgDiscardLocals));
-
-static cl::opt<bool>
-ArgDiscardAll("discard-all",
- cl::desc("Delete all local symbols."),
- cl::init(false));
-
-static cl::alias
-ArgDiscardAllAlias("x",
- cl::desc("alias for --discard-all"),
- cl::aliasopt(ArgDiscardAll));
-
-static cl::opt<bool>
-ArgStripDebug("strip-debug",
- cl::desc("Omit debugger symbol information from the output file."),
- cl::init(false));
-
-static cl::alias
-ArgStripDebugAlias("S",
- cl::desc("alias for --strip-debug"),
- cl::aliasopt(ArgStripDebug));
-
-static cl::opt<bool>
-ArgStripAll("strip-all",
- cl::desc("Omit all symbol information from the output file."),
- cl::init(false));
-
-static cl::alias
-ArgStripAllAlias("s",
- cl::desc("alias for --strip-all"),
- cl::aliasopt(ArgStripAll));
-
-static cl::opt<bool>
-ArgNMagic("nmagic",
- cl::desc("Do not page align data"),
- cl::init(false));
-
-static cl::alias
-ArgNMagicAlias("n",
- cl::desc("alias for --nmagic"),
- cl::aliasopt(ArgNMagic));
-
-static cl::opt<bool>
-ArgOMagic("omagic",
- cl::desc("Do not page align data, do not make text readonly"),
- cl::init(false));
-
-static cl::alias
-ArgOMagicAlias("N",
- cl::desc("alias for --omagic"),
- cl::aliasopt(ArgOMagic));
-
-
-static cl::opt<int>
-ArgGPSize("G",
- cl::desc("Set the maximum size of objects to be optimized using GP"),
- cl::init(8));
-
-/// @{
-/// @name FIXME: begin of unsupported options
-/// @}
-static cl::opt<bool>
-ArgGCSections("gc-sections",
- cl::desc("Enable garbage collection of unused input sections."),
- cl::init(false));
-
-static cl::opt<bool>
-ArgNoGCSections("no-gc-sections",
- cl::desc("disable garbage collection of unused input sections."),
- cl::init(false));
-
-namespace icf {
-enum Mode {
- None,
- All,
- Safe
-};
-} // namespace of icf
-
-static cl::opt<icf::Mode>
-ArgICF("icf",
- cl::ZeroOrMore,
- cl::desc("Identical Code Folding"),
- cl::init(icf::None),
- cl::values(
- clEnumValN(icf::None, "none",
- "do not perform cold folding"),
- clEnumValN(icf::All, "all",
- "always preform cold folding"),
- clEnumValN(icf::Safe, "safe",
- "Folds ctors, dtors and functions whose pointers are definitely not taken."),
- clEnumValEnd));
-
-// FIXME: add this to target options?
-static cl::opt<bool>
-ArgFIXCA8("fix-cortex-a8",
- cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgExportDynamic("export-dynamic",
- cl::desc("Export all dynamic symbols"),
- cl::init(false));
-
-static cl::alias
-ArgExportDynamicAlias("E",
- cl::desc("alias for --export-dynamic"),
- cl::aliasopt(ArgExportDynamic));
-
-static cl::opt<std::string>
-ArgEmulation("m",
- cl::ZeroOrMore,
- cl::desc("Set GNU linker emulation"),
- cl::value_desc("emulation"));
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgRuntimePathLink("rpath-link",
- cl::ZeroOrMore,
- cl::desc("Add a directory to the link time library search path"),
- cl::value_desc("dir"));
-
-static cl::list<std::string>
-ArgExcludeLIBS("exclude-libs",
- cl::CommaSeparated,
- cl::desc("Exclude libraries from automatic export"),
- cl::value_desc("lib1,lib2,..."));
-
-static cl::opt<std::string>
-ArgBuildID("build-id",
- cl::desc("Request creation of \".note.gnu.build-id\" ELF note section."),
- cl::value_desc("style"),
- cl::ValueOptional);
-
-static cl::opt<std::string>
-ArgForceUndefined("u",
- cl::desc("Force symbol to be undefined in the output file"),
- cl::value_desc("symbol"));
-
-static cl::alias
-ArgForceUndefinedAlias("undefined",
- cl::desc("alias for -u"),
- cl::aliasopt(ArgForceUndefined));
-
-static cl::opt<std::string>
-ArgVersionScript("version-script",
- cl::desc("Version script."),
- cl::value_desc("Version script"));
-
-static cl::opt<bool>
-ArgWarnCommon("warn-common",
- cl::desc("warn common symbol"),
- cl::init(false));
-
-static cl::opt<mcld::GeneralOptions::HashStyle>
-ArgHashStyle("hash-style", cl::init(mcld::GeneralOptions::SystemV),
- cl::desc("Set the type of linker's hash table(s)."),
- cl::values(
- clEnumValN(mcld::GeneralOptions::SystemV, "sysv",
- "classic ELF .hash section"),
- clEnumValN(mcld::GeneralOptions::GNU, "gnu",
- "new style GNU .gnu.hash section"),
- clEnumValN(mcld::GeneralOptions::Both, "both",
- "both the classic ELF and new style GNU hash tables"),
- clEnumValEnd));
-
-static cl::opt<std::string>
-ArgFilter("F",
- cl::desc("Filter for shared object symbol table"),
- cl::value_desc("name"));
-
-static cl::alias
-ArgFilterAlias("filter",
- cl::desc("alias for -F"),
- cl::aliasopt(ArgFilterAlias));
-
-static cl::list<std::string>
-ArgAuxiliary("f",
- cl::ZeroOrMore,
- cl::desc("Auxiliary filter for shared object symbol table"),
- cl::value_desc("name"));
-
-static cl::alias
-ArgAuxiliaryAlias("auxiliary",
- cl::desc("alias for -f"),
- cl::aliasopt(ArgAuxiliary));
-
-static cl::opt<bool>
-ArgUseGold("use-gold",
- cl::desc("GCC/collect2 compatibility: uses ld.gold. Ignored"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgUseMCLD("use-mcld",
- cl::desc("GCC/collect2 compatibility: uses ld.mcld. Ignored"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgUseLD("use-ld",
- cl::desc("GCC/collect2 compatibility: uses ld.bfd. Ignored"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgEB("EB",
- cl::desc("Link big-endian objects. This affects the default output format."),
- cl::init(false));
-
-static cl::opt<bool>
-ArgEL("EL",
- cl::desc("Link little-endian objects. This affects the default output format."),
- cl::init(false));
-
-static cl::list<std::string>
-ArgPlugin("plugin",
- cl::desc("Load a plugin library."),
- cl::value_desc("plugin"));
-
-static cl::list<std::string>
-ArgPluginOpt("plugin-opt",
- cl::desc(" Pass an option to the plugin."),
- cl::value_desc("option"));
-
-static cl::opt<bool>
-ArgSVR4Compatibility("Qy",
- cl::desc("This option is ignored for SVR4 compatibility"),
- cl::init(false));
-
-static cl::list<std::string>
-ArgY("Y",
- cl::desc("Add path to the default library search path"),
- cl::value_desc("default-search-path"));
-
-/// @{
-/// @name FIXME: end of unsupported options
-/// @}
-
-static cl::opt<bool>
-ArgNoStdlib("nostdlib",
- cl::desc("Only search lib dirs explicitly specified on cmdline"),
- cl::init(false));
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgRuntimePath("rpath",
- cl::ZeroOrMore,
- cl::desc("Add a directory to the runtime library search path"),
- cl::value_desc("dir"));
-
-static cl::alias
-ArgRuntimePathAlias("R",
- cl::desc("alias for --rpath"),
- cl::aliasopt(ArgRuntimePath), cl::Prefix);
-
-static cl::opt<bool>
-ArgEnableNewDTags("enable-new-dtags",
- cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"),
- cl::init(false));
-
-static cl::opt<bool>
-ArgPrintMap("M",
- cl::desc("Print a link map to the standard output."),
- cl::init(false));
-
-static cl::alias
-ArgPrintMapAlias("print-map",
- cl::desc("alias for -M"),
- cl::aliasopt(ArgPrintMap));
-
-static bool ArgFatalWarnings;
-
-static cl::opt<bool, true, cl::FalseParser>
-ArgNoFatalWarnings("no-fatal-warnings",
- cl::location(ArgFatalWarnings),
- cl::desc("do not turn warnings into errors"),
- cl::init(false),
- cl::ValueDisallowed);
-
-static cl::opt<bool, true>
-ArgFatalWarningsFlag("fatal-warnings",
- cl::location(ArgFatalWarnings),
- cl::desc("turn all warnings into errors"),
- cl::init(false),
- cl::ValueDisallowed);
-
-static cl::opt<bool>
-ArgWarnSharedTextrel("warn-shared-textrel",
- cl::desc("Warn if adding DT_TEXTREL in a shared object."),
- cl::init(false));
-
-namespace format {
-enum Format {
- Binary,
- Unknown // decided by triple
-};
-} // namespace of format
-
-static cl::opt<format::Format>
-ArgFormat("b",
- cl::value_desc("Format"),
- cl::desc("set input format"),
- cl::init(format::Unknown),
- cl::values(
- clEnumValN(format::Binary, "binary",
- "read in binary machine code."),
- clEnumValEnd));
-
-static cl::alias
-ArgFormatAlias("format",
- cl::desc("alias for -b"),
- cl::aliasopt(ArgFormat));
-
-static cl::opt<format::Format>
-ArgOFormat("oformat",
- cl::value_desc("Format"),
- cl::desc("set output format"),
- cl::init(format::Unknown),
- cl::values(
- clEnumValN(format::Binary, "binary",
- "generate binary machine code."),
- clEnumValEnd));
-
-static cl::opt<bool>
-ArgDefineCommon("d",
- cl::ZeroOrMore,
- cl::desc("Define common symbol"),
- cl::init(false));
-
-static cl::alias
-ArgDefineCommonAlias1("dc",
- cl::ZeroOrMore,
- cl::desc("alias for -d"),
- cl::aliasopt(ArgDefineCommon));
-
-static cl::alias
-ArgDefineCommonAlias2("dp",
- cl::ZeroOrMore,
- cl::desc("alias for -d"),
- cl::aliasopt(ArgDefineCommon));
-
-//===----------------------------------------------------------------------===//
-// Scripting Options
-//===----------------------------------------------------------------------===//
-static cl::list<std::string>
-ArgWrapList("wrap",
- cl::ZeroOrMore,
- cl::desc("Use a wrap function fo symbol."),
- cl::value_desc("symbol"));
-
-static cl::list<std::string>
-ArgPortList("portable",
- cl::ZeroOrMore,
- cl::desc("Use a portable function fo symbol."),
- cl::value_desc("symbol"));
-
-static cl::list<std::string>
-ArgAddressMapList("section-start",
- cl::ZeroOrMore,
- cl::desc("Locate a output section at the given absolute address"),
- cl::value_desc("Set address of section"),
- cl::Prefix);
-
-static cl::list<std::string>
-ArgDefSymList("defsym",
- cl::ZeroOrMore,
- cl::desc("Define a symbol"),
- cl::value_desc("symbol=expression"));
-
-static cl::opt<unsigned long long>
-ArgBssSegAddr("Tbss",
- cl::desc("Set the address of the bss segment"),
- cl::init(-1U));
-
-static cl::opt<unsigned long long>
-ArgDataSegAddr("Tdata",
- cl::desc("Set the address of the data segment"),
- cl::init(-1U));
-
-static cl::opt<unsigned long long>
-ArgTextSegAddr("Ttext",
- cl::desc("Set the address of the text segment"),
- cl::init(-1U));
-
-//===----------------------------------------------------------------------===//
-// non-member functions
-//===----------------------------------------------------------------------===//
-/// GetOutputStream - get the output stream.
-static mcld::ToolOutputFile *GetOutputStream(const char* pTargetName,
- Triple::OSType pOSType,
- mcld::CodeGenFileType pFileType,
- const mcld::sys::fs::Path& pInputFilename,
- mcld::sys::fs::Path& pOutputFilename)
-{
- if (pOutputFilename.empty()) {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("-");
- else {
- switch(pFileType) {
- case mcld::CGFT_ASMFile: {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("_out");
- else
- pOutputFilename.assign(pInputFilename.stem().native());
-
- if (0 == strcmp(pTargetName, "c"))
- pOutputFilename.native() += ".cbe.c";
- else if (0 == strcmp(pTargetName, "cpp"))
- pOutputFilename.native() += ".cpp";
- else
- pOutputFilename.native() += ".s";
- }
- break;
-
- case mcld::CGFT_OBJFile: {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("_out");
- else
- pOutputFilename.assign(pInputFilename.stem().native());
-
- if (pOSType == Triple::Win32)
- pOutputFilename.native() += ".obj";
- else
- pOutputFilename.native() += ".o";
- }
- break;
-
- case mcld::CGFT_PARTIAL: {
- if (Triple::Win32 == pOSType) {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("_out");
- else
- pOutputFilename.assign(pInputFilename.stem().native());
- pOutputFilename.native() += ".obj";
- }
- else
- pOutputFilename.assign("a.out");
- }
- break;
-
- case mcld::CGFT_DSOFile: {
- if (Triple::Win32 == pOSType) {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("_out");
- else
- pOutputFilename.assign(pInputFilename.stem().native());
- pOutputFilename.native() += ".dll";
- }
- else
- pOutputFilename.assign("a.out");
- }
- break;
-
- case mcld::CGFT_EXEFile: {
- if (Triple::Win32 == pOSType) {
- if (0 == pInputFilename.native().compare("-"))
- pOutputFilename.assign("_out");
- else
- pOutputFilename.assign(pInputFilename.stem().native());
- pOutputFilename.native() += ".exe";
- }
- else
- pOutputFilename.assign("a.out");
- }
- break;
-
- case mcld::CGFT_NULLFile:
- break;
- default:
- llvm::report_fatal_error("Unknown output file type.\n");
- } // end of switch
- } // end of ! pInputFilename == "-"
- } // end of if empty pOutputFilename
-
- mcld::FileHandle::Permission permission;
- switch (pFileType) {
- default: assert(0 && "Unknown file type");
- case mcld::CGFT_ASMFile:
- case mcld::CGFT_OBJFile:
- case mcld::CGFT_PARTIAL:
- permission = mcld::FileHandle::Permission(0x644);
- break;
- case mcld::CGFT_DSOFile:
- case mcld::CGFT_EXEFile:
- case mcld::CGFT_BINARY:
- case mcld::CGFT_NULLFile:
- permission = mcld::FileHandle::Permission(0x755);
- break;
- }
-
- // Open the file.
- mcld::ToolOutputFile* result_output =
- new mcld::ToolOutputFile(pOutputFilename,
- mcld::FileHandle::ReadWrite |
- mcld::FileHandle::Create |
- mcld::FileHandle::Truncate,
- permission);
-
- return result_output;
-}
-
-/// ParseProgName - Parse program name
-/// This function simplifies cross-compiling by reading triple from the program
-/// name. For example, if the program name is `arm-linux-eabi-ld.mcld', we can
-/// get the triple is arm-linux-eabi by the program name.
-static std::string ParseProgName(const char *progname)
-{
- static const char *suffixes[] = {
- "ld",
- "ld.mcld",
- };
-
- std::string ProgName(mcld::sys::fs::Path(progname).stem().native());
-
- for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
- if (ProgName == suffixes[i])
- return std::string();
- }
-
- StringRef ProgNameRef(ProgName);
- StringRef Prefix;
-
- for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
- if (!ProgNameRef.endswith(suffixes[i]))
- continue;
-
- StringRef::size_type LastComponent = ProgNameRef.rfind('-',
- ProgNameRef.size() - strlen(suffixes[i]));
- if (LastComponent == StringRef::npos)
- continue;
- StringRef Prefix = ProgNameRef.slice(0, LastComponent);
- std::string IgnoredError;
- if (!llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError))
- continue;
- return Prefix.str();
- }
- return std::string();
-}
-
-static Triple ParseEmulation(const std::string& pEmulation)
-{
- Triple result = StringSwitch<Triple>(pEmulation)
- .Case("armelf_linux_eabi", Triple("arm", "", "linux", "gnueabi"))
- .Case("elf_i386", Triple("i386", "", "", "gnu"))
- .Case("elf_x86_64", Triple("x86_64", "", "", "gnu"))
- .Case("elf32_x86_64", Triple("x86_64", "", "", "gnux32"))
- .Case("elf_i386_fbsd", Triple("i386", "", "freebsd", "gnu"))
- .Case("elf_x86_64_fbsd", Triple("x86_64", "", "freebsd", "gnu"))
- .Case("elf32ltsmip", Triple("mipsel", "", "", "gnu"))
- .Default(Triple());
-
- if (result.getArch() == Triple::UnknownArch &&
- result.getOS() == Triple::UnknownOS &&
- result.getEnvironment() == Triple::UnknownEnvironment)
- mcld::error(mcld::diag::err_invalid_emulation) << pEmulation << "\n";
-
- return result;
-}
-
-static bool ShouldColorize()
-{
- const char* term = getenv("TERM");
- return term && (0 != strcmp(term, "dumb"));
-}
-
-static bool ProcessLinkerOptionsFromCommand(mcld::LinkerScript& pScript,
- mcld::LinkerConfig& pConfig)
-{
- // ----- Set up General Options ----- //
- // set up colorize
- switch (ArgColor) {
- case color::Never:
- pConfig.options().setColor(false);
- break;
- case color::Always:
- pConfig.options().setColor(true);
- break;
- case color::Auto:
- bool color_option = ShouldColorize() &&
- llvm::sys::Process::FileDescriptorIsDisplayed(STDOUT_FILENO);
- pConfig.options().setColor(color_option);
- break;
- }
-
- mcld::outs().setColor(pConfig.options().color());
- mcld::errs().setColor(pConfig.options().color());
-
- // set up soname
- pConfig.options().setSOName(ArgSOName);
-
- // add all rpath entries
- cl::list<std::string>::iterator rp;
- cl::list<std::string>::iterator rpEnd = ArgRuntimePath.end();
- for (rp = ArgRuntimePath.begin(); rp != rpEnd; ++rp) {
- pConfig.options().getRpathList().push_back(*rp);
- }
-
- // --fatal-warnings
- // pConfig.options().setFatalWarnings(ArgFatalWarnings);
-
- // -shared or -pie
- if (true == ArgShared || true == ArgPIE) {
- ArgFileType = mcld::CGFT_DSOFile;
- }
- else if (true == ArgRelocatable) {
- ArgFileType = mcld::CGFT_PARTIAL;
- }
- else if (format::Binary == ArgOFormat) {
- ArgFileType = mcld::CGFT_BINARY;
- }
-
- // -b [input-format], --format=[input-format]
- if (format::Binary == ArgFormat)
- pConfig.options().setBinaryInput();
-
- // -V
- if (ArgVersion) {
- mcld::outs() << "MCLinker - "
- << mcld::LinkerConfig::version()
- << "\n";
- }
-
- // set up sysroot
- if (!ArgSysRoot.empty()) {
- if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
- pScript.setSysroot(ArgSysRoot);
- }
-
- // add all search directories
- cl::list<std::string>::iterator sd;
- cl::list<std::string>::iterator sdEnd = ArgSearchDirList.end();
- for (sd=ArgSearchDirList.begin(); sd!=sdEnd; ++sd) {
- if (!pScript.directories().insert(*sd)) {
- // FIXME: need a warning function
- errs() << "WARNING: can not open search directory `-L"
- << *sd
- << "'.\n";
- }
- }
-
- pConfig.options().setPIE(ArgPIE);
- pConfig.options().setTrace(ArgTrace);
- pConfig.options().setVerbose(ArgVerbose);
- pConfig.options().setMaxErrorNum(ArgMaxErrorNum);
- pConfig.options().setMaxWarnNum(ArgMaxWarnNum);
- pConfig.options().setEntry(ArgEntry);
- pConfig.options().setBsymbolic(ArgBsymbolic);
- pConfig.options().setBgroup(ArgBgroup);
- pConfig.options().setDyld(ArgDyld);
- pConfig.options().setNoUndefined(ArgNoUndefined);
- pConfig.options().setMulDefs(ArgAllowMulDefs);
- pConfig.options().setEhFrameHdr(ArgEhFrameHdr);
- pConfig.options().setNMagic(ArgNMagic);
- pConfig.options().setOMagic(ArgOMagic);
- pConfig.options().setStripDebug(ArgStripDebug || ArgStripAll);
- pConfig.options().setExportDynamic(ArgExportDynamic);
- pConfig.options().setWarnSharedTextrel(ArgWarnSharedTextrel);
- pConfig.options().setDefineCommon(ArgDefineCommon);
- pConfig.options().setNewDTags(ArgEnableNewDTags);
- pConfig.options().setHashStyle(ArgHashStyle);
- pConfig.options().setNoStdlib(ArgNoStdlib);
- pConfig.options().setPrintMap(ArgPrintMap);
- pConfig.options().setGPSize(ArgGPSize);
-
- if (ArgStripAll)
- pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
- else if (ArgDiscardAll)
- pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
- else if (ArgDiscardLocals)
- pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
- else
- pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);
-
- // set up rename map, for --wrap
- cl::list<std::string>::iterator wname;
- cl::list<std::string>::iterator wnameEnd = ArgWrapList.end();
- for (wname = ArgWrapList.begin(); wname != wnameEnd; ++wname) {
- bool exist = false;
-
- // add wname -> __wrap_wname
- mcld::StringEntry<llvm::StringRef>* to_wrap =
- pScript.renameMap().insert(*wname, exist);
-
- std::string to_wrap_str = "__wrap_" + *wname;
- to_wrap->setValue(to_wrap_str);
-
- if (exist)
- mcld::warning(mcld::diag::rewrap) << *wname << to_wrap_str;
-
- // add __real_wname -> wname
- std::string from_real_str = "__real_" + *wname;
- mcld::StringEntry<llvm::StringRef>* from_real =
- pScript.renameMap().insert(from_real_str, exist);
- from_real->setValue(*wname);
- if (exist)
- mcld::warning(mcld::diag::rewrap) << *wname << from_real_str;
- } // end of for
-
- // set up rename map, for --portable
- cl::list<std::string>::iterator pname;
- cl::list<std::string>::iterator pnameEnd = ArgPortList.end();
- for (pname = ArgPortList.begin(); pname != pnameEnd; ++pname) {
- bool exist = false;
-
- // add pname -> pname_portable
- mcld::StringEntry<llvm::StringRef>* to_port =
- pScript.renameMap().insert(*pname, exist);
-
- std::string to_port_str = *pname + "_portable";
- to_port->setValue(to_port_str);
-
- if (exist)
- mcld::warning(mcld::diag::rewrap) << *pname << to_port_str;
-
- // add __real_pname -> pname
- std::string from_real_str = "__real_" + *pname;
- mcld::StringEntry<llvm::StringRef>* from_real =
- pScript.renameMap().insert(from_real_str, exist);
-
- from_real->setValue(*pname);
- if (exist)
- mcld::warning(mcld::diag::rewrap) << *pname << from_real_str;
- } // end of for
-
- // add -z options
- cl::list<mcld::ZOption>::iterator zOpt;
- cl::list<mcld::ZOption>::iterator zOptEnd = ArgZOptionList.end();
- for (zOpt = ArgZOptionList.begin(); zOpt != zOptEnd; ++zOpt) {
- pConfig.options().addZOption(*zOpt);
- }
-
- if (ArgGCSections) {
- mcld::warning(mcld::diag::warn_unsupported_option) << ArgGCSections.ArgStr;
- }
-
- // set up icf mode
- switch (ArgICF) {
- case icf::None:
- break;
- case icf::All:
- case icf::Safe:
- default:
- mcld::warning(mcld::diag::warn_unsupported_option) << ArgICF.ArgStr;
- break;
- }
-
- if (ArgFIXCA8) {
- mcld::warning(mcld::diag::warn_unsupported_option) << ArgFIXCA8.ArgStr;
- }
-
- // add address mappings
- // -Ttext
- if (-1U != ArgTextSegAddr) {
- bool exist = false;
- mcld::StringEntry<uint64_t>* text_mapping =
- pScript.addressMap().insert(".text", exist);
- text_mapping->setValue(ArgTextSegAddr);
- }
- // -Tdata
- if (-1U != ArgDataSegAddr) {
- bool exist = false;
- mcld::StringEntry<uint64_t>* data_mapping =
- pScript.addressMap().insert(".data", exist);
- data_mapping->setValue(ArgDataSegAddr);
- }
- // -Tbss
- if (-1U != ArgBssSegAddr) {
- bool exist = false;
- mcld::StringEntry<uint64_t>* bss_mapping =
- pScript.addressMap().insert(".bss", exist);
- bss_mapping->setValue(ArgBssSegAddr);
- }
- // --section-start SECTION=ADDRESS
- for (cl::list<std::string>::iterator
- it = ArgAddressMapList.begin(), ie = ArgAddressMapList.end();
- it != ie; ++it) {
- // FIXME: Add a cl::parser
- size_t pos = (*it).find_last_of('=');
- llvm::StringRef script(*it);
- uint64_t address = 0x0;
- script.substr(pos + 1).getAsInteger(0, address);
- bool exist = false;
- mcld::StringEntry<uint64_t>* addr_mapping =
- pScript.addressMap().insert(script.substr(0, pos), exist);
- addr_mapping->setValue(address);
- }
-
- // --defsym symbols
- for (cl::list<std::string>::iterator
- it = ArgDefSymList.begin(), ie = ArgDefSymList.end();
- it != ie ; ++it) {
- llvm::StringRef expression(*it);
- size_t pos = expression.find_last_of('=');
- if (pos == expression.size() - 1) {
- errs() << "defsym option: expression must not end with '='\n";
- return false;
- }
- if (llvm::StringRef::npos == pos) {
- errs() << "syntax : --defsym symbol=expression\n";
- return false;
- }
- bool exist = false;
- // FIXME: This will not work with multiple destinations such as
- // --defsym abc=pqr=expression
-
- mcld::StringEntry<llvm::StringRef> *defsyms =
- pScript.defSymMap().insert(expression.substr(0,pos),exist);
- defsyms->setValue(expression.substr(pos + 1));
- }
-
- // set up filter/aux filter for shared object
- pConfig.options().setFilter(ArgFilter);
-
- cl::list<std::string>::iterator aux;
- cl::list<std::string>::iterator auxEnd = ArgAuxiliary.end();
- for (aux = ArgAuxiliary.begin(); aux != auxEnd; ++aux)
- pConfig.options().getAuxiliaryList().push_back(*aux);
-
- return true;
-}
-
-int main(int argc, char* argv[])
-{
- sys::PrintStackTraceOnErrorSignal();
-
- LLVMContext &Context = getGlobalContext();
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
- // Initialize targets first, so that --version shows registered targets.
- InitializeAllTargets();
- InitializeAllAsmPrinters();
- InitializeAllAsmParsers();
- InitializeAllTargetMCs();
- mcld::InitializeAllTargets();
- mcld::InitializeAllLinkers();
- mcld::InitializeAllEmulations();
- mcld::InitializeAllDiagnostics();
-
- cl::ParseCommandLineOptions(argc, argv, "MCLinker\n");
-
-#ifdef ENABLE_UNITTEST
- if (UnitTest) {
- return unit_test( argc, argv );
- }
-#endif
-
- // Load the module to be compiled...
- std::auto_ptr<llvm::Module> M;
-
- // Load the module to be linked...
- mcld::LinkerScript LDScript;
- mcld::Module LDIRModule(LDScript);
- mcld::LinkerConfig LDConfig;
-
- // Process the linker input from the command line
- if (!ProcessLinkerOptionsFromCommand(LDScript, LDConfig)) {
- errs() << argv[0] << ": failed to process linker options from command line!\n";
- return 1;
- }
-
- if (ArgBitcodeFilename.empty() &&
- (mcld::CGFT_DSOFile != ArgFileType &&
- mcld::CGFT_EXEFile != ArgFileType &&
- mcld::CGFT_PARTIAL != ArgFileType &&
- mcld::CGFT_BINARY != ArgFileType)) {
- // If the file is not given, forcefully read from stdin
- if (ArgVerbose >= 0) {
- errs() << "** The bitcode/llvm asm file is not given. Read from stdin.\n"
- << "** Specify input bitcode/llvm asm file by\n\n"
- << " llvm-mcld -dB [the bitcode/llvm asm]\n\n";
- }
-
- ArgBitcodeFilename.assign("-");
- }
-
- if (!ArgBitcodeFilename.empty()) {
- SMDiagnostic Err;
- M.reset(ParseIRFile(ArgBitcodeFilename.native(), Err, Context));
-
- if (M.get() == 0) {
- Err.print(argv[0], errs());
- errs() << "** Failed to to the given bitcode/llvm asm file '"
- << ArgBitcodeFilename.native() << "'. **\n";
- return 1;
- }
- }
- else {
- // If here, output must be dynamic shared object (mcld::CGFT_DSOFile) and
- // executable file (mcld::CGFT_EXEFile).
- M.reset(new Module("Empty Module", Context));
- }
- Module &mod = *M.get();
-
- // If we are supposed to override the target triple, do so now.
- Triple TheTriple;
- if (!TargetTriple.empty()) {
- // 1. Use the triple from command.
- TheTriple.setTriple(TargetTriple);
- mod.setTargetTriple(TargetTriple);
- } else if (!mod.getTargetTriple().empty()) {
- // 2. Use the triple in the input Module.
- TheTriple.setTriple(mod.getTargetTriple());
- } else {
- std::string ProgNameTriple = ParseProgName(argv[0]);
- if (!ProgNameTriple.empty()) {
- // 3. Use the triple from the program name prefix.
- TheTriple.setTriple(ProgNameTriple);
- mod.setTargetTriple(ProgNameTriple);
- } else {
- // 4. Use the default target triple.
- TheTriple.setTriple(mcld::sys::getDefaultTargetTriple());
- if (!ArgEmulation.empty()) {
- // Process target emulation.
- Triple EmulationTriple = ParseEmulation(ArgEmulation);
- if (EmulationTriple.getArch() != Triple::UnknownArch)
- TheTriple.setArch(EmulationTriple.getArch());
- if (EmulationTriple.getOS() != Triple::UnknownOS)
- TheTriple.setOS(EmulationTriple.getOS());
- if (EmulationTriple.getEnvironment() != Triple::UnknownEnvironment)
- TheTriple.setEnvironment(EmulationTriple.getEnvironment());
- }
- }
- }
-
- // Allocate target machine. First, check whether the user has explicitly
- // specified an architecture to compile for. If so we have to look it up by
- // name, because it might be a backend that has no mapping to a target triple.
- const mcld::Target *TheTarget = 0;
- if (!MArch.empty()) {
- for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
- ie = mcld::TargetRegistry::end(); it != ie; ++it) {
- if (MArch == (*it)->get()->getName()) {
- TheTarget = *it;
- break;
- }
- }
-
- if (!TheTarget) {
- errs() << argv[0] << ": error: invalid target '" << MArch << "'.\n";
- return 1;
- }
-
- // Adjust the triple to match (if known), otherwise stick with the
- // module/host triple.
- Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
- if (Type != Triple::UnknownArch)
- TheTriple.setArch(Type);
- }
- else {
- std::string Err;
- TheTarget = mcld::TargetRegistry::lookupTarget(TheTriple.getTriple(), Err);
- if (TheTarget == 0) {
- errs() << "error: auto-selecting target `" << TheTriple.getTriple()
- << "'\n"
- << "Please use the -march option to explicitly select a target.\n"
- << "Example:\n"
- << " $ " << argv[0] << " -march=arm\n";
- return 1;
- }
- }
- // Set up mcld::LinkerConfig
- LDConfig.targets().setTriple(TheTriple);
-
- // Package up features to be passed to target/subtarget
- std::string FeaturesStr;
- if (MAttrs.size()) {
- SubtargetFeatures Features;
- for (unsigned i = 0; i != MAttrs.size(); ++i)
- Features.AddFeature(MAttrs[i]);
- FeaturesStr = Features.getString();
- }
-
- CodeGenOpt::Level OLvl = CodeGenOpt::Default;
- switch (OptLevel) {
- default:
- errs() << argv[0] << ": invalid optimization level.\n";
- return 1;
- case ' ': break;
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
- }
-
- // set -fPIC
- if (ArgFPIC)
- ArgRelocModel = Reloc::PIC_;
-
- TargetOptions Options;
- Options.LessPreciseFPMADOption = EnableFPMAD;
- Options.NoFramePointerElim = DisableFPElim;
- Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
- Options.AllowFPOpFusion = FuseFPOps;
- Options.UnsafeFPMath = EnableUnsafeFPMath;
- Options.NoInfsFPMath = EnableNoInfsFPMath;
- Options.NoNaNsFPMath = EnableNoNaNsFPMath;
- Options.HonorSignDependentRoundingFPMathOption =
- EnableHonorSignDependentRoundingFPMath;
- Options.UseSoftFloat = GenerateSoftFloatCalls;
- if (FloatABIForCalls != FloatABI::Default)
- Options.FloatABIType = FloatABIForCalls;
- Options.NoZerosInBSS = DontPlaceZerosInBSS;
- Options.JITExceptionHandling = EnableJITExceptionHandling;
- Options.JITEmitDebugInfo = EmitJitDebugInfo;
- Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
- Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
- Options.StackAlignmentOverride = OverrideStackAlignment;
- Options.RealignStack = EnableRealignStack;
- Options.TrapFuncName = TrapFuncName;
- Options.EnableSegmentedStacks = SegmentedStacks;
-
- std::auto_ptr<mcld::MCLDTargetMachine> target_machine(
- TheTarget->createTargetMachine(TheTriple.getTriple(),
- MCPU, FeaturesStr, Options,
- ArgRelocModel, CMModel, OLvl));
- assert(target_machine.get() && "Could not allocate target machine!");
- mcld::MCLDTargetMachine &TheTargetMachine = *target_machine.get();
-
- LDConfig.targets().setTargetCPU(MCPU);
- LDConfig.targets().setTargetFeatureString(FeaturesStr);
-
- TheTargetMachine.getTM().setMCUseLoc(false);
- TheTargetMachine.getTM().setMCUseCFI(false);
-
- // FIXME: Move the initialization of LineInfo to mcld::Linker when we
- // finish LineInfo's implementation.
- OwningPtr<mcld::DiagnosticLineInfo>
- diag_line_info(TheTarget->createDiagnosticLineInfo(*TheTarget,
- TheTriple.getTriple()));
-
- mcld::getDiagnosticEngine().setLineInfo(*diag_line_info.take());
-
- // Figure out where we are going to send the output...
- OwningPtr<mcld::ToolOutputFile>
- Out(GetOutputStream(TheTarget->get()->getName(),
- TheTriple.getOS(),
- ArgFileType,
- ArgBitcodeFilename,
- ArgOutputFilename));
- if (!Out) {
- // FIXME: show some error message pls.
- return 1;
- }
-
- // Build up all of the passes that we want to do to the module.
- PassManager PM;
-
- // Add the data layout from the target machine, if it exists, or the module.
- if (const DataLayout *DL = TheTargetMachine.getTM().getDataLayout())
- PM.add(new DataLayout(*DL));
- else
- PM.add(new DataLayout(&mod));
-
- // Override default to generate verbose assembly.
- TheTargetMachine.getTM().setAsmVerbosityDefault(true);
-
- {
- // Ask the target to add backend passes as necessary.
- if( TheTargetMachine.addPassesToEmitFile(PM,
- *Out,
- ArgFileType,
- OLvl,
- LDIRModule,
- LDConfig,
- NoVerify)) {
- errs() << argv[0] << ": target does not support generation of this"
- << " file type!\n";
- return 1;
- }
-
- // Before executing passes, print the final values of the LLVM options.
- cl::PrintOptionValues();
-
- PM.run(mod);
- }
-
- if (mcld::getDiagnosticEngine().getPrinter()->getNumErrors())
- return 1;
-
- // Declare success.
- Out->keep();
- return 0;
-}
diff --git a/tools/mcld/include/mcld/OptimizationOptions.h b/tools/mcld/include/mcld/OptimizationOptions.h
index 485e732..5385f91 100644
--- a/tools/mcld/include/mcld/OptimizationOptions.h
+++ b/tools/mcld/include/mcld/OptimizationOptions.h
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#ifndef MCLD_LDLITE_OPTIMIZATION_OPTIONS_H
#define MCLD_LDLITE_OPTIMIZATION_OPTIONS_H
+#include <mcld/GeneralOptions.h>
#include <llvm/Support/CommandLine.h>
#include <string>
@@ -18,21 +19,17 @@ class LinkerConfig;
class OptimizationOptions
{
public:
- enum ICF {
- ICF_None,
- ICF_All,
- ICF_Safe
- };
-
-public:
OptimizationOptions();
bool parse(LinkerConfig& pConfig);
private:
bool& m_GCSections;
+ bool& m_PrintGCSections;
bool& m_GenUnwindInfo;
- llvm::cl::opt<ICF>& m_ICF;
+ llvm::cl::opt<mcld::GeneralOptions::ICF>& m_ICF;
+ llvm::cl::opt<unsigned>& m_ICFIterations;
+ llvm::cl::opt<bool>& m_PrintICFSections;
llvm::cl::opt<char>& m_OptLevel;
llvm::cl::list<std::string>& m_Plugin;
llvm::cl::list<std::string>& m_PluginOpt;
diff --git a/tools/mcld/include/mcld/SymbolOptions.h b/tools/mcld/include/mcld/SymbolOptions.h
index b7c16f7..60f5e06 100644
--- a/tools/mcld/include/mcld/SymbolOptions.h
+++ b/tools/mcld/include/mcld/SymbolOptions.h
@@ -24,7 +24,7 @@ public:
private:
// not supported yet
- llvm::cl::opt<std::string>& m_ForceUndefined;
+ llvm::cl::list<std::string>& m_ForceUndefined;
llvm::cl::opt<std::string>& m_VersionScript;
llvm::cl::opt<bool>& m_WarnCommon;
llvm::cl::opt<bool>& m_DefineCommon;
diff --git a/tools/mcld/lib/DynamicSectionOptions.cpp b/tools/mcld/lib/DynamicSectionOptions.cpp
index 415bdc8..5ceeaef 100644
--- a/tools/mcld/lib/DynamicSectionOptions.cpp
+++ b/tools/mcld/lib/DynamicSectionOptions.cpp
@@ -75,7 +75,7 @@ llvm::cl::opt<std::string> ArgFilter("F",
llvm::cl::alias ArgFilterAlias("filter",
llvm::cl::desc("alias for -F"),
- llvm::cl::aliasopt(ArgFilterAlias));
+ llvm::cl::aliasopt(ArgFilter));
// } Not supported yet
diff --git a/tools/mcld/lib/OptimizationOptions.cpp b/tools/mcld/lib/OptimizationOptions.cpp
index 7eca773..9de70f4 100644
--- a/tools/mcld/lib/OptimizationOptions.cpp
+++ b/tools/mcld/lib/OptimizationOptions.cpp
@@ -13,7 +13,6 @@
namespace {
-// Not supported yet
bool ArgGCSections;
llvm::cl::opt<bool, true> ArgGCSectionsFlag("gc-sections",
@@ -28,6 +27,20 @@ llvm::cl::opt<bool, true, llvm::cl::FalseParser> ArgNoGCSectionsFlag("no-gc-sect
llvm::cl::desc("disable garbage collection of unused input sections."),
llvm::cl::init(false));
+bool ArgPrintGCSections;
+
+llvm::cl::opt<bool, true> ArgPrintGCSectionsFlag("print-gc-sections",
+ llvm::cl::ZeroOrMore,
+ llvm::cl::location(ArgPrintGCSections),
+ llvm::cl::desc("List all sections removed by garbage collection."),
+ llvm::cl::init(false));
+
+llvm::cl::opt<bool, true, llvm::cl::FalseParser> ArgNoPrintGCSectionsFlag("no-print-gc-sections",
+ llvm::cl::ZeroOrMore,
+ llvm::cl::location(ArgPrintGCSections),
+ llvm::cl::desc("disable --print-gc-sections"),
+ llvm::cl::init(false));
+
bool ArgGenUnwindInfo;
llvm::cl::opt<bool, true, llvm::cl::FalseParser>
@@ -47,19 +60,27 @@ ArgGenUnwindInfoFlag("ld-generated-unwind-info",
llvm::cl::init(true),
llvm::cl::ValueDisallowed);
-llvm::cl::opt<mcld::OptimizationOptions::ICF> ArgICF("icf",
+llvm::cl::opt<mcld::GeneralOptions::ICF> ArgICF("icf",
llvm::cl::ZeroOrMore,
llvm::cl::desc("Identical Code Folding"),
- llvm::cl::init(mcld::OptimizationOptions::ICF_None),
+ llvm::cl::init(mcld::GeneralOptions::ICF_None),
llvm::cl::values(
- clEnumValN(mcld::OptimizationOptions::ICF_None, "none",
+ clEnumValN(mcld::GeneralOptions::ICF_None, "none",
"do not perform cold folding"),
- clEnumValN(mcld::OptimizationOptions::ICF_All, "all",
+ clEnumValN(mcld::GeneralOptions::ICF_All, "all",
"always preform cold folding"),
- clEnumValN(mcld::OptimizationOptions::ICF_Safe, "safe",
+ clEnumValN(mcld::GeneralOptions::ICF_Safe, "safe",
"Folds those whose pointers are definitely not taken."),
clEnumValEnd));
+llvm::cl::opt<unsigned> ArgICFIterations("icf-iterations",
+ llvm::cl::desc("Number of iterations to do ICF."),
+ llvm::cl::init(2));
+
+llvm::cl::opt<bool> ArgPrintICFSections("print-icf-sections",
+ llvm::cl::desc("Print the folded identical sections."),
+ llvm::cl::init(false));
+
llvm::cl::opt<char> ArgOptLevel("O",
llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
"(default = '-O2')"),
@@ -84,8 +105,11 @@ using namespace mcld;
//===----------------------------------------------------------------------===//
OptimizationOptions::OptimizationOptions()
: m_GCSections(ArgGCSections),
+ m_PrintGCSections(ArgPrintGCSections),
m_GenUnwindInfo(ArgGenUnwindInfo),
m_ICF(ArgICF),
+ m_ICFIterations(ArgICFIterations),
+ m_PrintICFSections(ArgPrintICFSections),
m_OptLevel(ArgOptLevel),
m_Plugin(ArgPlugin),
m_PluginOpt(ArgPluginOpt) {
@@ -97,19 +121,17 @@ bool OptimizationOptions::parse(LinkerConfig& pConfig)
if (m_GCSections)
pConfig.options().setGCSections();
+ // set --print-gc-sections
+ if (m_PrintGCSections)
+ pConfig.options().setPrintGCSections();
+
// set --ld-generated-unwind-info (or not)
pConfig.options().setGenUnwindInfo(m_GenUnwindInfo);
// set --icf [mode]
- switch (m_ICF) {
- case ICF_None:
- break;
- case ICF_All:
- case ICF_Safe:
- default:
- warning(mcld::diag::warn_unsupported_option) << m_ICF.ArgStr;
- break;
- }
+ pConfig.options().setICFMode(m_ICF);
+ pConfig.options().setICFIterations(m_ICFIterations);
+ pConfig.options().setPrintICFSections(m_PrintICFSections);
return true;
}
diff --git a/tools/mcld/lib/OutputFormatOptions.cpp b/tools/mcld/lib/OutputFormatOptions.cpp
index 5a148ee..87a3638 100644
--- a/tools/mcld/lib/OutputFormatOptions.cpp
+++ b/tools/mcld/lib/OutputFormatOptions.cpp
@@ -228,6 +228,14 @@ bool OutputFormatOptions::parse(mcld::Module& pModule, LinkerConfig& pConfig)
pConfig.options().setOMagic(m_OMagic);
pConfig.options().setHashStyle(m_HashStyle);
pConfig.options().setExportDynamic(m_ExportDynamic);
+
+ // --exclude-libs
+ llvm::cl::list<std::string>::iterator exclude,
+ excludeEnd = m_ExcludeLIBS.end();
+ for (exclude = m_ExcludeLIBS.begin(); exclude != excludeEnd; ++exclude) {
+ pConfig.options().excludeLIBS().insert(*exclude);
+ }
+
if (m_NoWarnMismatch)
pConfig.options().setWarnMismatch(false);
else
@@ -299,5 +307,3 @@ bool OutputFormatOptions::parseOutput(Module& pModule, LinkerConfig& pConfig)
pModule.setName(output_filename);
return true;
}
-
-
diff --git a/tools/mcld/lib/PreferenceOptions.cpp b/tools/mcld/lib/PreferenceOptions.cpp
index 4fc6445..e5fa3df 100644
--- a/tools/mcld/lib/PreferenceOptions.cpp
+++ b/tools/mcld/lib/PreferenceOptions.cpp
@@ -91,17 +91,13 @@ llvm::cl::opt<bool, true> ArgFatalWarningsFlag("fatal-warnings",
llvm::cl::init(false),
llvm::cl::ValueDisallowed);
-llvm::cl::opt<bool> ArgUseGold("use-gold",
- llvm::cl::desc("GCC/collect2 compatibility: uses ld.gold. Ignored"),
- llvm::cl::init(false));
-
-llvm::cl::opt<bool> ArgUseMCLD("use-mcld",
- llvm::cl::desc("GCC/collect2 compatibility: uses ld.mcld. Ignored"),
- llvm::cl::init(false));
+llvm::cl::opt<std::string> ArgUseLD("fuse-ld",
+ llvm::cl::desc("Ignored for GCC/collect2 linker compatibility."),
+ llvm::cl::init("mcld"));
-llvm::cl::opt<bool> ArgUseLD("use-ld",
- llvm::cl::desc("GCC/collect2 compatibility: uses ld.bfd. Ignored"),
- llvm::cl::init(false));
+llvm::cl::opt<std::string> ArgUseMCLD("use-mcld",
+ llvm::cl::desc("Ignored for GCC/collect2 linker compatibility."),
+ llvm::cl::init("mcld"));
//===----------------------------------------------------------------------===//
// Non-member functions
diff --git a/tools/mcld/lib/SymbolOptions.cpp b/tools/mcld/lib/SymbolOptions.cpp
index 66b52f6..4de764a 100644
--- a/tools/mcld/lib/SymbolOptions.cpp
+++ b/tools/mcld/lib/SymbolOptions.cpp
@@ -12,11 +12,13 @@
namespace {
// Not supprted yet {
-llvm::cl::opt<std::string> ArgForceUndefined("u",
+llvm::cl::list<std::string> ArgForceUndefined("u",
+ llvm::cl::ZeroOrMore,
llvm::cl::desc("Force symbol to be undefined in the output file"),
llvm::cl::value_desc("symbol"));
llvm::cl::alias ArgForceUndefinedAlias("undefined",
+ llvm::cl::ZeroOrMore,
llvm::cl::desc("alias for -u"),
llvm::cl::aliasopt(ArgForceUndefined));
@@ -64,6 +66,11 @@ bool SymbolOptions::parse(LinkerConfig& pConfig)
// set -d
pConfig.options().setDefineCommon(m_DefineCommon);
+ // set -u/--undefined symbols
+ llvm::cl::list<std::string>::iterator usym, usymEnd = m_ForceUndefined.end();
+ for (usym = m_ForceUndefined.begin(); usym != usymEnd; ++usym)
+ pConfig.options().getUndefSymList().push_back(*usym);
+
return true;
}