[lld] r206417 - [ELF] Support --defsym=<symbol>=<symbol>.
Rui Ueyama
ruiu at google.com
Wed Apr 16 13:58:57 PDT 2014
Author: ruiu
Date: Wed Apr 16 15:58:57 2014
New Revision: 206417
URL: http://llvm.org/viewvc/llvm-project?rev=206417&view=rev
Log:
[ELF] Support --defsym=<symbol>=<symbol>.
Currently LLD supports --defsym only in the form of
--defsym=<symbol>=<integer>, where the integer is interpreted as the
absolute address of the symbol. This patch extends it to allow other
symbol name to be given as an RHS value. If a RHS value is a symbol
name, the LHS symbol will be defined as an alias for the RHS symbol.
Internally, a LHS symbol is represented as a zero-size defined atom
who has an LayoutAfter reference to an undefined atom, whose name is
the RHS value. Everything else is already implemented -- Resolver
will resolve the undefined symbol, and the layout pass will layout
the two atoms at the same location. Looks like it's working fine.
Note that GNU LD supports --defsym=<symbol>=<symbol>+<addend>. That
feature is out of scope of this patch.
Differential Revision: http://reviews.llvm.org/D3332
Added:
lld/trunk/test/elf/X86_64/Inputs/fn.o
lld/trunk/test/elf/X86_64/defsym.test
Modified:
lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
lld/trunk/lib/Driver/GnuLdDriver.cpp
lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
lld/trunk/test/elf/defsym.objtxt
lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=206417&r1=206416&r2=206417&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Wed Apr 16 15:58:57 2014
@@ -187,6 +187,10 @@ public:
_absoluteSymbols[name] = addr;
}
+ void addAlias(StringRef sym, StringRef target) {
+ _aliasSymbols[sym] = target;
+ }
+
/// Return the list of initializer symbols that are specified in the
/// linker command line, using the -init option.
range<const StringRef *> initFunctions() const {
@@ -228,6 +232,10 @@ public:
return _absoluteSymbols;
}
+ const std::map<std::string, std::string> getAliases() const {
+ return _aliasSymbols;
+ }
+
/// \brief Helper function to allocate strings.
StringRef allocateString(StringRef ref) const {
char *x = _allocator.Allocate<char>(ref.size() + 1);
@@ -275,6 +283,7 @@ protected:
StringRefVector _rpathList;
StringRefVector _rpathLinkList;
std::map<std::string, uint64_t> _absoluteSymbols;
+ std::map<std::string, std::string> _aliasSymbols;
};
} // end namespace lld
Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=206417&r1=206416&r2=206417&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Wed Apr 16 15:58:57 2014
@@ -129,10 +129,9 @@ static error_code getFileMagic(ELFLinkin
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) {
+// Parses an argument of --defsym=<sym>=<number>
+static bool parseDefsymAsAbsolute(StringRef opt, StringRef &sym,
+ uint64_t &addr) {
size_t equalPos = opt.find('=');
if (equalPos == 0 || equalPos == StringRef::npos)
return false;
@@ -142,6 +141,17 @@ static bool parseDefsymOption(StringRef
return true;
}
+// Parses an argument of --defsym=<sym>=<sym>
+static bool parseDefsymAsAlias(StringRef opt, StringRef &sym,
+ StringRef &target) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ sym = opt.substr(0, equalPos);
+ target = opt.substr(equalPos + 1);
+ return !target.empty();
+}
+
llvm::ErrorOr<StringRef> ELFFileNode::getPath(const LinkingContext &) const {
if (!_attributes._isDashlPrefix)
return _path;
@@ -416,13 +426,16 @@ bool GnuLdDriver::parse(int argc, const
break;
case OPT_defsym: {
- StringRef sym;
+ StringRef sym, target;
uint64_t addr;
- if (!parseDefsymOption(inputArg->getValue(), sym, addr)) {
+ if (parseDefsymAsAbsolute(inputArg->getValue(), sym, addr)) {
+ ctx->addInitialAbsoluteSymbol(sym, addr);
+ } else if (parseDefsymAsAlias(inputArg->getValue(), sym, target)) {
+ ctx->addAlias(sym, target);
+ } else {
diagnostics << "invalid --defsym: " << inputArg->getValue() << "\n";
return false;
}
- ctx->addInitialAbsoluteSymbol(sym, addr);
break;
}
Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=206417&r1=206416&r2=206417&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Wed Apr 16 15:58:57 2014
@@ -41,6 +41,70 @@ private:
uint64_t _value;
};
+// An AliasAtom is a zero-size atom representing an alias for other atom. It has
+// a LayoutAfter reference to the target atom, so that this atom and the target
+// atom will be layed out at the same location in the final result. Initially
+// the target atom is an undefined atom. Resolver will replace it with a defined
+// one.
+//
+// It does not have attributes itself. Most member function calls are forwarded
+// to the target atom.
+class AliasAtom : public SimpleDefinedAtom {
+public:
+ AliasAtom(const File &file, StringRef name)
+ : SimpleDefinedAtom(file), _target(nullptr), _name(name) {}
+
+ StringRef name() const override { return _name; }
+ uint64_t size() const override { return 0; }
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ Scope scope() const override {
+ getTarget();
+ return _target ? _target->scope() : scopeLinkageUnit;
+ }
+
+ Merge merge() const override {
+ getTarget();
+ return _target ? _target->merge() : mergeNo;
+ }
+
+ ContentType contentType() const override {
+ getTarget();
+ return _target ? _target->contentType() : typeUnknown;
+ }
+
+ Interposable interposable() const override {
+ getTarget();
+ return _target ? _target->interposable() : interposeNo;
+ }
+
+ SectionChoice sectionChoice() const override {
+ getTarget();
+ return _target ? _target->sectionChoice() : sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override {
+ getTarget();
+ return _target ? _target->customSectionName() : StringRef("");
+ }
+
+private:
+ void getTarget() const {
+ if (_target)
+ return;
+ for (const Reference *r : *this) {
+ if (r->kindNamespace() == lld::Reference::KindNamespace::all &&
+ r->kindValue() == lld::Reference::kindLayoutAfter) {
+ _target = dyn_cast<DefinedAtom>(r->target());
+ return;
+ }
+ }
+ }
+
+ mutable const DefinedAtom *_target;
+ StringRef _name;
+};
+
class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
public:
CommandLineUndefinedAtom(const File &f, StringRef name)
@@ -204,6 +268,17 @@ void ELFLinkingContext::createInternalFi
uint64_t val = i.second;
file->addAtom(*(new (_allocator) CommandLineAbsoluteAtom(*file, sym, val)));
}
+ for (auto &i : getAliases()) {
+ StringRef from = i.first;
+ StringRef to = i.second;
+ SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from);
+ UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to);
+ fromAtom->addReference(Reference::KindNamespace::all,
+ Reference::KindArch::all, Reference::kindLayoutAfter,
+ 0, toAtom, 0);
+ file->addAtom(*fromAtom);
+ file->addAtom(*toAtom);
+ }
files.push_back(std::move(file));
LinkingContext::createInternalFiles(files);
}
Added: lld/trunk/test/elf/X86_64/Inputs/fn.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/fn.o?rev=206417&view=auto
==============================================================================
Binary files lld/trunk/test/elf/X86_64/Inputs/fn.o (added) and lld/trunk/test/elf/X86_64/Inputs/fn.o Wed Apr 16 15:58:57 2014 differ
Added: lld/trunk/test/elf/X86_64/defsym.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/defsym.test?rev=206417&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/defsym.test (added)
+++ lld/trunk/test/elf/X86_64/defsym.test Wed Apr 16 15:58:57 2014
@@ -0,0 +1,21 @@
+RUN: lld -flavor gnu -target x86_64 --defsym=_start=fn %p/Inputs/fn.o -o %t
+RUN: llvm-readobj -symbols %t | FileCheck %s
+
+CHECK: Symbol {
+CHECK: Name: _start (1)
+CHECK: Value: 0x4001E0
+CHECK: Size: 0
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
+CHECK: Symbol {
+CHECK: Name: fn (8)
+CHECK: Value: 0x4001E0
+CHECK: Size: 6
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
Modified: lld/trunk/test/elf/defsym.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/defsym.objtxt?rev=206417&r1=206416&r2=206417&view=diff
==============================================================================
--- lld/trunk/test/elf/defsym.objtxt (original)
+++ lld/trunk/test/elf/defsym.objtxt Wed Apr 16 15:58:57 2014
@@ -1,9 +1,28 @@
# RUN: lld -flavor gnu -target x86_64 --defsym=foo=0x1234 -r %s \
-# RUN: --output-filetype=yaml | FileCheck %s
+# RUN: --output-filetype=yaml | FileCheck -check-prefix=ABS %s
-absolute-atoms:
+# RUN: lld -flavor gnu -target x86_64 --defsym=foo=main -r %s \
+# RUN: --output-filetype=yaml | FileCheck -check-prefix=ALIAS %s
-# CHECK: absolute-atoms:
-# CHECK: - name: foo
-# CHECK: scope: global
-# CHECK: value: 0x0000000000001234
+defined-atoms:
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00, 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+
+# ABS: absolute-atoms:
+# ABS: - name: foo
+# ABS: scope: global
+# ABS: value: 0x0000000000001234
+
+# ALIAS: defined-atoms:
+# ALIAS: - name: foo
+# ALIAS: scope: global
+# ALIAS: section-choice: custom-required
+# ALIAS: section-name: .text
+# ALIAS: references:
+# ALIAS: - kind: layout-after
+# ALIAS: offset: 0
+# ALIAS: target: main
Modified: lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp?rev=206417&r1=206416&r2=206417&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp Wed Apr 16 15:58:57 2014
@@ -149,6 +149,14 @@ TEST_F(GnuLdParserTest, DefsymHexadecima
EXPECT_EQ((uint64_t)0x1000, map["sym"]);
}
+TEST_F(GnuLdParserTest, DefsymAlias) {
+ EXPECT_TRUE(
+ parse("ld", "--start-group", "--end-group", "--defsym=sym=abc", nullptr));
+ auto map = _context->getAliases();
+ EXPECT_EQ((size_t)1, map.size());
+ EXPECT_EQ("abc", map["sym"]);
+}
+
TEST_F(GnuLdParserTest, DefsymOctal) {
EXPECT_TRUE(parse("ld", "--start-group", "--end-group", "--defsym=sym=0777",
nullptr));
@@ -157,11 +165,6 @@ TEST_F(GnuLdParserTest, DefsymOctal) {
EXPECT_EQ((uint64_t)0777, map["sym"]);
}
-TEST_F(GnuLdParserTest, DefsymFail) {
- EXPECT_FALSE(
- parse("ld", "--start-group", "--end-group", "--defsym=sym=abc", nullptr));
-}
-
TEST_F(GnuLdParserTest, DefsymMisssingSymbol) {
EXPECT_FALSE(
parse("ld", "--start-group", "--end-group", "--defsym==0", nullptr));
More information about the llvm-commits
mailing list