diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 622324c13e2d..763111c6ac38 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -139,6 +139,7 @@ struct Configuration { bool ExecuteOnly; bool ExportDynamic; bool FixCortexA53Errata843419; + bool FormatBinary = false; bool GcSections; bool GdbIndex; bool GnuHash = false; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 796b84fdead7..814c7fe84915 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -183,7 +183,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { return; MemoryBufferRef MBRef = *Buffer; - if (InBinary) { + if (Config->FormatBinary) { Files.push_back(make(MBRef)); return; } @@ -999,7 +999,7 @@ static void setConfigs(opt::InputArgList &Args) { } // Returns a value of "-format" option. -static bool getBinaryOption(StringRef S) { +static bool isFormatBinary(StringRef S) { if (S == "binary") return true; if (S == "elf" || S == "default") @@ -1041,7 +1041,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { Config->AsNeeded = true; break; case OPT_format: - InBinary = getBinaryOption(Arg->getValue()); + Config->FormatBinary = isFormatBinary(Arg->getValue()); break; case OPT_no_as_needed: Config->AsNeeded = false; diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 99e194d9b66c..81d7f608e588 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -42,9 +42,6 @@ private: // True if we are in --start-lib and --end-lib. bool InLib = false; - // True if we are in -format=binary and -format=elf. - bool InBinary = false; - std::vector Files; }; diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index ddb4a49a3e5e..ffc69b265f72 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -72,6 +72,7 @@ private: void readRegionAlias(); void readSearchDir(); void readSections(); + void readTarget(); void readVersion(); void readVersionScriptCommand(); @@ -255,6 +256,8 @@ void ScriptParser::readLinkerScript() { readSearchDir(); } else if (Tok == "SECTIONS") { readSections(); + } else if (Tok == "TARGET") { + readTarget(); } else if (Tok == "VERSION") { readVersion(); } else if (SymbolAssignment *Cmd = readAssignment(Tok)) { @@ -522,6 +525,23 @@ void ScriptParser::readSections() { V.end()); } +void ScriptParser::readTarget() { + // TARGET(foo) is an alias for "--format foo". Unlike GNU linkers, + // we accept only a limited set of BFD names (i.e. "elf" or "binary") + // for --format. We recognize only /^elf/ and "binary" in the linker + // script as well. + expect("("); + StringRef Tok = next(); + expect(")"); + + if (Tok.startswith("elf")) + Config->FormatBinary = false; + else if (Tok == "binary") + Config->FormatBinary = true; + else + setError("unknown target: " + Tok); +} + static int precedence(StringRef Op) { return StringSwitch(Op) .Cases("*", "/", "%", 8) diff --git a/lld/test/ELF/linkerscript/target.s b/lld/test/ELF/linkerscript/target.s new file mode 100644 index 000000000000..32db5b7866c2 --- /dev/null +++ b/lld/test/ELF/linkerscript/target.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "TARGET(binary) INPUT(\"%t.o\") TARGET(elf64-x86-64) INPUT(\"%t.o\")" > %t.script +# RUN: ld.lld --script %t.script -o %t.exe +# RUN: llvm-readelf -symbols %t.exe | FileCheck %s + +# CHECK: _binary_ +# CHECK: foobar + +# RUN: echo "TARGET(foo)" > %t2.script +# RUN: not ld.lld --script %t2.script -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s + +# ERR: unknown target: foo + +.global foobar +foobar: + nop