Index: include/lld/Core/LinkingContext.h =================================================================== --- include/lld/Core/LinkingContext.h +++ include/lld/Core/LinkingContext.h @@ -326,8 +326,8 @@ std::unique_ptr createEntrySymbolFile(StringRef filename) const; /// Method to create a internal file for an undefined symbol - virtual std::unique_ptr createUndefinedSymbolFile() const; - std::unique_ptr createUndefinedSymbolFile(StringRef filename) const; + virtual std::unique_ptr createCommandLineFile() const; + std::unique_ptr createCommandLineFile(StringRef filename) const; StringRef _outputPath; StringRef _entrySymbolName; Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -181,6 +181,11 @@ /// add to the list of finalizer functions void addFiniFunction(StringRef name) { _finiFunctions.push_back(name); } + /// Add an absolute symbol. Used for --defsym. + void addInitialAbsoluteSymbol(StringRef name, uint64_t addr) { + _absoluteSymbols[name] = addr; + } + /// Return the list of initializer symbols that are specified in the /// linker command line, using the -init option. range initFunctions() const { @@ -225,6 +230,10 @@ return true; } + const std::map &getAbsoluteSymbols() const { + return _absoluteSymbols; + } + /// \brief Helper function to allocate strings. StringRef allocateString(StringRef ref) const { char *x = _allocator.Allocate(ref.size() + 1); @@ -248,7 +257,7 @@ Writer &writer() const override; /// Method to create a internal file for an undefined symbol - std::unique_ptr createUndefinedSymbolFile() const override; + std::unique_ptr createCommandLineFile() const override; uint16_t _outputELFType; // e.g ET_EXEC llvm::Triple _triple; @@ -272,6 +281,7 @@ StringRefVector _rpathList; StringRefVector _rpathLinkList; std::map _undefinedAtomsFromFile; + std::map _absoluteSymbols; }; } // end namespace lld Index: include/lld/ReaderWriter/PECOFFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/PECOFFLinkingContext.h +++ include/lld/ReaderWriter/PECOFFLinkingContext.h @@ -272,7 +272,7 @@ std::unique_ptr createEntrySymbolFile() const override; /// Method to create a internal file for an undefined symbol - std::unique_ptr createUndefinedSymbolFile() const override; + std::unique_ptr createCommandLineFile() const override; private: enum : uint64_t { Index: lib/Core/LinkingContext.cpp =================================================================== --- lib/Core/LinkingContext.cpp +++ lib/Core/LinkingContext.cpp @@ -43,7 +43,7 @@ } std::unique_ptr LinkingContext::createEntrySymbolFile() const { - return createEntrySymbolFile("command line option -e"); + return createEntrySymbolFile(""); } std::unique_ptr @@ -56,12 +56,12 @@ return std::move(entryFile); } -std::unique_ptr LinkingContext::createUndefinedSymbolFile() const { - return createUndefinedSymbolFile("command line option -u"); +std::unique_ptr LinkingContext::createCommandLineFile() const { + return createCommandLineFile(""); } std::unique_ptr -LinkingContext::createUndefinedSymbolFile(StringRef filename) const { +LinkingContext::createCommandLineFile(StringRef filename) const { if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr undefinedSymFile(new SimpleFile(filename)); @@ -77,7 +77,7 @@ internalFile = createEntrySymbolFile(); if (internalFile) result.push_back(std::move(internalFile)); - internalFile = createUndefinedSymbolFile(); + internalFile = createCommandLineFile(); if (internalFile) result.push_back(std::move(internalFile)); } Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -88,6 +88,19 @@ return make_error_code(ReaderError::unknown_file_format); } +// Parses an argument of --defsym. A given string must be in the form +// of =. Note that we don't support symbol-relative +// aliases yet. +static bool parseDefsymOption(StringRef opt, StringRef &sym, uint64_t &addr) { + size_t equalPos = opt.find('='); + if (equalPos == StringRef::npos) + return false; + sym = opt.substr(0, equalPos); + if (opt.substr(equalPos + 1).getAsInteger(0, addr)) + return false; + return true; +} + llvm::ErrorOr ELFFileNode::getPath(const LinkingContext &) const { if (!_isDashlPrefix) return _path; @@ -369,6 +382,17 @@ asNeeded = false; break; + case OPT_defsym: { + StringRef sym; + uint64_t addr; + if (!parseDefsymOption(inputArg->getValue(), sym, addr)) { + diagnostics << "invalid --defsym: " << inputArg->getValue() << "\n"; + return false; + } + ctx->addInitialAbsoluteSymbol(sym, addr); + break; + } + case OPT_start_group: { std::unique_ptr controlStart(new ELFGroup(*ctx, index++)); controlNodeStack.push(controlStart.get()); Index: lib/Driver/GnuLdOptions.td =================================================================== --- lib/Driver/GnuLdOptions.td +++ lib/Driver/GnuLdOptions.td @@ -187,6 +187,9 @@ def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">, HelpText<"Resolve undefined symbols from dynamic libraries">, Group; +def defsym : Joined<["--"], "defsym=">, + HelpText<"Create a defined symbol">, + Group; //===----------------------------------------------------------------------===// /// Custom Options @@ -240,4 +243,3 @@ //===----------------------------------------------------------------------===// def help : Flag<["--"], "help">, HelpText<"Display this help message">; - Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -25,6 +25,22 @@ namespace lld { +class CommandLineAbsoluteAtom : public AbsoluteAtom { +public: + CommandLineAbsoluteAtom(const File &file, StringRef name, uint64_t value) + : _file(file), _name(name), _value(value) {} + + const File& file() const override { return _file; } + StringRef name() const override { return _name; } + uint64_t value() const override { return _value; } + Scope scope() const override { return scopeGlobal; } + +private: + const File &_file; + StringRef _name; + uint64_t _value; +}; + class CommandLineUndefinedAtom : public SimpleUndefinedAtom { public: CommandLineUndefinedAtom(const File &f, StringRef name) @@ -179,15 +195,19 @@ return libName; } -std::unique_ptr ELFLinkingContext::createUndefinedSymbolFile() const { - if (_initialUndefinedSymbols.empty()) +std::unique_ptr ELFLinkingContext::createCommandLineFile() const { + if (_initialUndefinedSymbols.empty() && getAbsoluteSymbols().empty()) return nullptr; - std::unique_ptr undefinedSymFile( - new SimpleFile("command line option -u")); - for (auto undefSymStr : _initialUndefinedSymbols) - undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom( - *undefinedSymFile, undefSymStr))); - return std::move(undefinedSymFile); + std::unique_ptr file(new SimpleFile( + "")); + for (StringRef sym : _initialUndefinedSymbols) + file->addAtom(*(new (_allocator) CommandLineUndefinedAtom(*file, sym))); + for (auto i : getAbsoluteSymbols()) { + StringRef sym = i.first; + uint64_t val = i.second; + file->addAtom(*(new (_allocator) CommandLineAbsoluteAtom(*file, sym, val))); + } + return std::move(file); } } // end namespace lld Index: lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -93,11 +93,11 @@ } std::unique_ptr PECOFFLinkingContext::createEntrySymbolFile() const { - return LinkingContext::createEntrySymbolFile("command line option /entry"); + return LinkingContext::createEntrySymbolFile(""); } -std::unique_ptr PECOFFLinkingContext::createUndefinedSymbolFile() const { - return LinkingContext::createUndefinedSymbolFile("command line option /include"); +std::unique_ptr PECOFFLinkingContext::createCommandLineFile() const { + return LinkingContext::createCommandLineFile(""); } bool PECOFFLinkingContext::createImplicitFiles( Index: test/elf/defsym.objtxt =================================================================== --- /dev/null +++ test/elf/defsym.objtxt @@ -0,0 +1,9 @@ +# RUN: lld -flavor gnu -target x86_64 --defsym=foo=0x1234 -r %s \ +# RUN: --output-filetype=yaml | FileCheck %s + +absolute-atoms: + +# CHECK: absolute-atoms: +# CHECK: - name: foo +# CHECK: scope: global +# CHECK: value: 0x0000000000001234 Index: test/pecoff/include.test =================================================================== --- test/pecoff/include.test +++ test/pecoff/include.test @@ -4,5 +4,5 @@ # RUN: /subsystem:console -- %t.obj 2> %t.log # RUN: FileCheck %s < %t.log -CHECK: Undefined symbol: command line option /include: sym1 -CHECK: Undefined symbol: command line option /include: sym2 +CHECK: Undefined symbol: : sym1 +CHECK: Undefined symbol: : sym2 Index: unittests/DriverTests/GnuLdDriverTest.cpp =================================================================== --- unittests/DriverTests/GnuLdDriverTest.cpp +++ unittests/DriverTests/GnuLdDriverTest.cpp @@ -27,8 +27,43 @@ }; } +// All calls of parse() in this file has empty "--start-group" and "--end-group" +// options. This is a workaround for the current GNU-compatible driver. The +// driver complains if no input file is given, but if we give a file, it tries +// to read it to get magic bytes. It's not suitable for unit tests. +// +// TODO: Modify the driver to make it more test friendly. + TEST_F(GnuLdParserTest, Empty) { EXPECT_FALSE(parse("ld", nullptr)); EXPECT_EQ(linkingContext(), nullptr); EXPECT_EQ("No input files\n", errorMessage()); } + +// Tests for --defsym + +TEST_F(GnuLdParserTest, DefsymDecimal) { + EXPECT_TRUE(parse("ld", "--start-group", "--end-group", "--defsym=sym=1000", nullptr)); + assert(_context.get()); + auto map = _context->getAbsoluteSymbols(); + EXPECT_EQ((size_t)1, map.size()); + EXPECT_EQ((uint64_t)1000, map["sym"]); +} + +TEST_F(GnuLdParserTest, DefsymHexadecimal) { + EXPECT_TRUE(parse("ld", "--start-group", "--end-group", "--defsym=sym=0x1000", nullptr)); + auto map = _context->getAbsoluteSymbols(); + EXPECT_EQ((size_t)1, map.size()); + EXPECT_EQ((uint64_t)0x1000, map["sym"]); +} + +TEST_F(GnuLdParserTest, DefsymOctal) { + EXPECT_TRUE(parse("ld", "--start-group", "--end-group", "--defsym=sym=0777", nullptr)); + auto map = _context->getAbsoluteSymbols(); + EXPECT_EQ((size_t)1, map.size()); + EXPECT_EQ((uint64_t)0777, map["sym"]); +} + +TEST_F(GnuLdParserTest, DefsymFail) { + EXPECT_FALSE(parse("ld", "--start-group", "--end-group", "--defsym=sym=abc", nullptr)); +}