[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