Index: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h +++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h @@ -151,9 +151,10 @@ void setIsStaticExecutable(bool v) { _isStaticExecutable = v; } void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; } void setUseShlibUndefines(bool use) { _useShlibUndefines = use; } - void setOutputELFType(uint32_t type) { _outputELFType = type; } + void createInternalFiles(std::vector> &) const override; + /// \brief Set the dynamic linker path void setInterpreter(StringRef dynamicLinker) { _dynamicLinkerArg = true; @@ -181,6 +182,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 +231,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); @@ -272,6 +282,7 @@ StringRefVector _rpathList; StringRefVector _rpathLinkList; std::map _undefinedAtomsFromFile; + std::map _absoluteSymbols; }; } // end namespace lld Index: lld/trunk/lib/Core/LinkingContext.cpp =================================================================== --- lld/trunk/lib/Core/LinkingContext.cpp +++ lld/trunk/lib/Core/LinkingContext.cpp @@ -44,7 +44,7 @@ } std::unique_ptr LinkingContext::createEntrySymbolFile() const { - return createEntrySymbolFile("command line option -e"); + return createEntrySymbolFile(""); } std::unique_ptr @@ -58,7 +58,7 @@ } std::unique_ptr LinkingContext::createUndefinedSymbolFile() const { - return createUndefinedSymbolFile("command line option -u"); + return createUndefinedSymbolFile(""); } std::unique_ptr Index: lld/trunk/lib/Driver/GnuLdDriver.cpp =================================================================== --- lld/trunk/lib/Driver/GnuLdDriver.cpp +++ lld/trunk/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; @@ -363,6 +376,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: lld/trunk/lib/Driver/GnuLdOptions.td =================================================================== --- lld/trunk/lib/Driver/GnuLdOptions.td +++ lld/trunk/lib/Driver/GnuLdOptions.td @@ -190,6 +190,9 @@ def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, HelpText<"Allow multiple definitions">, Group; +def defsym : Joined<["--"], "defsym=">, + HelpText<"Create a defined symbol">, + Group; //===----------------------------------------------------------------------===// /// Custom Options @@ -243,4 +246,3 @@ //===----------------------------------------------------------------------===// def help : Flag<["--"], "help">, HelpText<"Display this help message">; - Index: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lld/trunk/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,6 +195,19 @@ return libName; } +void ELFLinkingContext::createInternalFiles( + std::vector> &files) const { + std::unique_ptr file( + new SimpleFile("")); + for (auto i : getAbsoluteSymbols()) { + StringRef sym = i.first; + uint64_t val = i.second; + file->addAtom(*(new (_allocator) CommandLineAbsoluteAtom(*file, sym, val))); + } + files.push_back(std::move(file)); + LinkingContext::createInternalFiles(files); +} + std::unique_ptr ELFLinkingContext::createUndefinedSymbolFile() const { if (_initialUndefinedSymbols.empty()) return nullptr; @@ -186,7 +215,7 @@ new SimpleFile("command line option -u")); for (auto undefSymStr : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom( - *undefinedSymFile, undefSymStr))); + *undefinedSymFile, undefSymStr))); return std::move(undefinedSymFile); } Index: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -93,11 +93,12 @@ } 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"); + return LinkingContext::createUndefinedSymbolFile( + ""); } bool PECOFFLinkingContext::createImplicitFiles( Index: lld/trunk/test/elf/defsym.objtxt =================================================================== --- lld/trunk/test/elf/defsym.objtxt +++ lld/trunk/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: lld/trunk/test/pecoff/include.test =================================================================== --- lld/trunk/test/pecoff/include.test +++ lld/trunk/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: lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp =================================================================== --- lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp +++ lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp @@ -27,8 +27,47 @@ }; } +// 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)); +}