mirror of
https://github.com/intel/llvm.git
synced 2026-01-29 04:16:38 +08:00
[ELF] Support --defsym option to define an absolute symbol.
This patch is to support --defsym option for ELF file format/GNU-compatible driver. Currently it takes a symbol name followed by '=' and a number. If such option is given, the driver sets up an absolute symbol with the specified address. You can specify multiple --defsym options to define multiple symbols. GNU LD's --defsym provides many more features. For example, it allows users to specify another symbol name instead of a number to define a symbol alias, or it even allows a symbol plus an offset (e.g. --defsym=foo+3) to define symbol- relative alias. This patch does not support that, but will be supported in subsequent patches. Differential Revision: http://llvm-reviews.chandlerc.com/D3208 llvm-svn: 205029
This commit is contained in:
@@ -151,9 +151,10 @@ public:
|
||||
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;
|
||||
@@ -181,6 +182,11 @@ public:
|
||||
/// 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 {
|
||||
@@ -225,6 +231,10 @@ public:
|
||||
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);
|
||||
@@ -272,6 +282,7 @@ protected:
|
||||
StringRefVector _rpathList;
|
||||
StringRefVector _rpathLinkList;
|
||||
std::map<const SharedLibraryFile *, bool> _undefinedAtomsFromFile;
|
||||
std::map<std::string, uint64_t> _absoluteSymbols;
|
||||
};
|
||||
} // end namespace lld
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ bool LinkingContext::createImplicitFiles(
|
||||
}
|
||||
|
||||
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
|
||||
return createEntrySymbolFile("command line option -e");
|
||||
return createEntrySymbolFile("<command line option -e>");
|
||||
}
|
||||
|
||||
std::unique_ptr<File>
|
||||
@@ -58,7 +58,7 @@ LinkingContext::createEntrySymbolFile(StringRef filename) const {
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
@@ -88,6 +88,19 @@ static error_code getFileMagic(ELFLinkingContext &ctx, StringRef path,
|
||||
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;
|
||||
@@ -363,6 +376,17 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
||||
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());
|
||||
|
||||
@@ -190,6 +190,9 @@ def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
|
||||
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
|
||||
@@ -243,4 +246,3 @@ def alias_output_filetype: Joined<["--"], "output-filetype=">,
|
||||
//===----------------------------------------------------------------------===//
|
||||
def help : Flag<["--"], "help">,
|
||||
HelpText<"Display this help message">;
|
||||
|
||||
|
||||
@@ -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 @@ ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
|
||||
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;
|
||||
@@ -186,7 +215,7 @@ std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
|
||||
new SimpleFile("command line option -u"));
|
||||
for (auto undefSymStr : _initialUndefinedSymbols)
|
||||
undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
|
||||
*undefinedSymFile, undefSymStr)));
|
||||
*undefinedSymFile, undefSymStr)));
|
||||
return std::move(undefinedSymFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,11 +93,12 @@ bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
||||
}
|
||||
|
||||
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(
|
||||
|
||||
9
lld/test/elf/defsym.objtxt
Normal file
9
lld/test/elf/defsym.objtxt
Normal file
@@ -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
|
||||
@@ -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: <command line option /include>: sym1
|
||||
CHECK: Undefined symbol: <command line option /include>: sym2
|
||||
|
||||
@@ -27,8 +27,47 @@ protected:
|
||||
};
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user