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<std::unique_ptr<File>> &) const override;
+
/// \brief Set the dynamic linker path
void setInterpreter(StringRef dynamicLinker) {
_dynamicLinkerArg = true;
/// 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<const StringRef *> initFunctions() const {
return true;
}
+ const std::map<std::string, uint64_t> &getAbsoluteSymbols() const {
+ return _absoluteSymbols;
+ }
+
/// \brief Helper function to allocate strings.
StringRef allocateString(StringRef ref) const {
char *x = _allocator.Allocate<char>(ref.size() + 1);
StringRefVector _rpathList;
StringRefVector _rpathLinkList;
std::map<const SharedLibraryFile *, bool> _undefinedAtomsFromFile;
+ std::map<std::string, uint64_t> _absoluteSymbols;
};
} // end namespace lld
}
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
- return createEntrySymbolFile("command line option -e");
+ return createEntrySymbolFile("<command line option -e>");
}
std::unique_ptr<File>
}
std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
- return createUndefinedSymbolFile("command line option -u");
+ return createUndefinedSymbolFile("<command line option -u or --defsym>");
}
std::unique_ptr<File>
return make_error_code(ReaderError::unknown_file_format);
}
+// Parses an argument of --defsym. A given string must be in the form
+// of <symbol>=<number>. 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<StringRef> ELFFileNode::getPath(const LinkingContext &) const {
if (!_isDashlPrefix)
return _path;
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<InputElement> controlStart(new ELFGroup(*ctx, index++));
controlNodeStack.push(controlStart.get());
def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
HelpText<"Allow multiple definitions">,
Group<grp_resolveropt>;
+def defsym : Joined<["--"], "defsym=">,
+ HelpText<"Create a defined symbol">,
+ Group<grp_resolveropt>;
//===----------------------------------------------------------------------===//
/// Custom Options
//===----------------------------------------------------------------------===//
def help : Flag<["--"], "help">,
HelpText<"Display this help message">;
-
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)
return libName;
}
+void ELFLinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File>> &files) const {
+ std::unique_ptr<SimpleFile> file(
+ new SimpleFile("<internal file for --defsym>"));
+ 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<File> ELFLinkingContext::createUndefinedSymbolFile() const {
if (_initialUndefinedSymbols.empty())
return nullptr;
new SimpleFile("command line option -u"));
for (auto undefSymStr : _initialUndefinedSymbols)
undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
- *undefinedSymFile, undefSymStr)));
+ *undefinedSymFile, undefSymStr)));
return std::move(undefinedSymFile);
}
}
std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const {
- return LinkingContext::createEntrySymbolFile("command line option /entry");
+ return LinkingContext::createEntrySymbolFile("<command line option /entry>");
}
std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const {
- return LinkingContext::createUndefinedSymbolFile("command line option /include");
+ return LinkingContext::createUndefinedSymbolFile(
+ "<command line option /include>");
}
bool PECOFFLinkingContext::createImplicitFiles(
--- /dev/null
+# 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
# 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: <command line option /include>: sym1
+CHECK: Undefined symbol: <command line option /include>: sym2
};
}
+// 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));
+}