Update mclinker to 96e60abf286338c8e231b7c990c30c7c4651be0e.
Change-Id: I29a840d11cecc1ed133768b79222f8bae5f4db2d
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
index 8daf65f..e984501 100644
--- a/tools/llvm-mcld/llvm-mcld.cpp
+++ b/tools/llvm-mcld/llvm-mcld.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#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>
@@ -18,6 +19,7 @@
#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>
@@ -28,6 +30,7 @@
#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>
@@ -45,7 +48,7 @@
# include <unistd.h>
#endif
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
@@ -58,7 +61,6 @@
#endif
#endif
-
using namespace llvm;
#ifdef ENABLE_UNITTEST
@@ -521,6 +523,12 @@
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
/// @}
@@ -574,6 +582,7 @@
static cl::opt<std::string>
ArgEmulation("m",
+ cl::ZeroOrMore,
cl::desc("Set GNU linker emulation"),
cl::value_desc("emulation"));
@@ -592,7 +601,8 @@
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::value_desc("style"),
+ cl::ValueOptional);
static cl::opt<std::string>
ArgForceUndefined("u",
@@ -648,6 +658,21 @@
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));
@@ -657,6 +682,26 @@
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
/// @}
@@ -682,22 +727,19 @@
cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"),
cl::init(false));
-class FalseParser : public cl::parser<bool> {
- const char *ArgStr;
-public:
+static cl::opt<bool>
+ArgPrintMap("M",
+ cl::desc("Print a link map to the standard output."),
+ cl::init(false));
- // parse - Return true on error.
- bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, bool &Val) {
- if (cl::parser<bool>::parse(O, ArgName, Arg, Val))
- return false;
- Val = false;
- return false;
- }
-};
+static cl::alias
+ArgPrintMapAlias("print-map",
+ cl::desc("alias for -M"),
+ cl::aliasopt(ArgPrintMap));
static bool ArgFatalWarnings;
-static cl::opt<bool, true, FalseParser>
+static cl::opt<bool, true, cl::FalseParser>
ArgNoFatalWarnings("no-fatal-warnings",
cl::location(ArgFatalWarnings),
cl::desc("do not turn warnings into errors"),
@@ -705,7 +747,7 @@
cl::ValueDisallowed);
static cl::opt<bool, true>
-ArgFatalWarnings_("fatal-warnings",
+ArgFatalWarningsFlag("fatal-warnings",
cl::location(ArgFatalWarnings),
cl::desc("turn all warnings into errors"),
cl::init(false),
@@ -756,11 +798,13 @@
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));
@@ -786,6 +830,12 @@
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"),
@@ -897,13 +947,13 @@
case mcld::CGFT_ASMFile:
case mcld::CGFT_OBJFile:
case mcld::CGFT_PARTIAL:
- permission = 0644;
+ permission = mcld::FileHandle::Permission(0x644);
break;
case mcld::CGFT_DSOFile:
case mcld::CGFT_EXEFile:
case mcld::CGFT_BINARY:
case mcld::CGFT_NULLFile:
- permission = 0755;
+ permission = mcld::FileHandle::Permission(0x755);
break;
}
@@ -922,7 +972,7 @@
/// 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 void ParseProgName(const char *progname)
+static std::string ParseProgName(const char *progname)
{
static const char *suffixes[] = {
"ld",
@@ -933,7 +983,7 @@
for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
if (ProgName == suffixes[i])
- return;
+ return std::string();
}
StringRef ProgNameRef(ProgName);
@@ -951,9 +1001,29 @@
std::string IgnoredError;
if (!llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError))
continue;
- TargetTriple = Prefix.str();
- return;
+ 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()
@@ -962,7 +1032,9 @@
return term && (0 != strcmp(term, "dumb"));
}
-static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) {
+static bool ProcessLinkerOptionsFromCommand(mcld::LinkerScript& pScript,
+ mcld::LinkerConfig& pConfig)
+{
// ----- Set up General Options ----- //
// set up colorize
switch (ArgColor) {
@@ -1020,14 +1092,14 @@
// set up sysroot
if (!ArgSysRoot.empty()) {
if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
- pConfig.options().setSysroot(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 (!pConfig.options().directories().insert(*sd)) {
+ if (!pScript.directories().insert(*sd)) {
// FIXME: need a warning function
errs() << "WARNING: can not open search directory `-L"
<< *sd
@@ -1056,6 +1128,8 @@
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);
@@ -1074,7 +1148,7 @@
// add wname -> __wrap_wname
mcld::StringEntry<llvm::StringRef>* to_wrap =
- pConfig.scripts().renameMap().insert(*wname, exist);
+ pScript.renameMap().insert(*wname, exist);
std::string to_wrap_str = "__wrap_" + *wname;
to_wrap->setValue(to_wrap_str);
@@ -1085,7 +1159,7 @@
// add __real_wname -> wname
std::string from_real_str = "__real_" + *wname;
mcld::StringEntry<llvm::StringRef>* from_real =
- pConfig.scripts().renameMap().insert(from_real_str, exist);
+ pScript.renameMap().insert(from_real_str, exist);
from_real->setValue(*wname);
if (exist)
mcld::warning(mcld::diag::rewrap) << *wname << from_real_str;
@@ -1099,7 +1173,7 @@
// add pname -> pname_portable
mcld::StringEntry<llvm::StringRef>* to_port =
- pConfig.scripts().renameMap().insert(*pname, exist);
+ pScript.renameMap().insert(*pname, exist);
std::string to_port_str = *pname + "_portable";
to_port->setValue(to_port_str);
@@ -1110,7 +1184,7 @@
// add __real_pname -> pname
std::string from_real_str = "__real_" + *pname;
mcld::StringEntry<llvm::StringRef>* from_real =
- pConfig.scripts().renameMap().insert(from_real_str, exist);
+ pScript.renameMap().insert(from_real_str, exist);
from_real->setValue(*pname);
if (exist)
@@ -1148,21 +1222,21 @@
if (-1U != ArgTextSegAddr) {
bool exist = false;
mcld::StringEntry<uint64_t>* text_mapping =
- pConfig.scripts().addressMap().insert(".text", exist);
+ pScript.addressMap().insert(".text", exist);
text_mapping->setValue(ArgTextSegAddr);
}
// -Tdata
if (-1U != ArgDataSegAddr) {
bool exist = false;
mcld::StringEntry<uint64_t>* data_mapping =
- pConfig.scripts().addressMap().insert(".data", exist);
+ pScript.addressMap().insert(".data", exist);
data_mapping->setValue(ArgDataSegAddr);
}
// -Tbss
if (-1U != ArgBssSegAddr) {
bool exist = false;
mcld::StringEntry<uint64_t>* bss_mapping =
- pConfig.scripts().addressMap().insert(".bss", exist);
+ pScript.addressMap().insert(".bss", exist);
bss_mapping->setValue(ArgBssSegAddr);
}
// --section-start SECTION=ADDRESS
@@ -1176,10 +1250,33 @@
script.substr(pos + 1).getAsInteger(0, address);
bool exist = false;
mcld::StringEntry<uint64_t>* addr_mapping =
- pConfig.scripts().addressMap().insert(script.substr(0, pos), exist);
+ 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);
@@ -1193,6 +1290,8 @@
int main(int argc, char* argv[])
{
+ sys::PrintStackTraceOnErrorSignal();
+
LLVMContext &Context = getGlobalContext();
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
@@ -1206,7 +1305,6 @@
mcld::InitializeAllEmulations();
mcld::InitializeAllDiagnostics();
- ParseProgName(argv[0]);
cl::ParseCommandLineOptions(argc, argv, "MCLinker\n");
#ifdef ENABLE_UNITTEST
@@ -1219,12 +1317,12 @@
std::auto_ptr<llvm::Module> M;
// Load the module to be linked...
- mcld::Module LDIRModule;
-
+ mcld::LinkerScript LDScript;
+ mcld::Module LDIRModule(LDScript);
mcld::LinkerConfig LDConfig;
// Process the linker input from the command line
- if (!ProcessLinkerOptionsFromCommand(LDConfig)) {
+ if (!ProcessLinkerOptionsFromCommand(LDScript, LDConfig)) {
errs() << argv[0] << ": failed to process linker options from command line!\n";
return 1;
}
@@ -1265,19 +1363,32 @@
// 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);
- }
-
- // User doesn't specify the triple from command.
- if (TheTriple.getTriple().empty()) {
- // Try to get one from the input Module.
- const std::string &TripleStr = mod.getTargetTriple();
-
- if (TripleStr.empty())
- TheTriple.setTriple(sys::getDefaultTargetTriple());
- else
- TheTriple.setTriple(TripleStr);
+ } 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
@@ -1374,6 +1485,9 @@
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);
@@ -1436,4 +1550,3 @@
Out->keep();
return 0;
}
-