[lld] r228906 - [ELF] Support --wrap option

Shankar Easwaran shankare at codeaurora.org
Wed Feb 11 21:02:46 PST 2015


Author: shankare
Date: Wed Feb 11 23:02:46 2015
New Revision: 228906

URL: http://llvm.org/viewvc/llvm-project?rev=228906&view=rev
Log:
[ELF] Support --wrap option

Use a wrapper function for symbol. Any undefined reference to symbol will be
resolved to "__wrap_symbol". Any undefined reference to "__real_symbol" will be
resolved to symbol.

This can be used to provide a wrapper for a system function. The wrapper
function should be called "__wrap_symbol". If it wishes to call the system
function, it should call "__real_symbol".

Here is a trivial example:

void * __wrap_malloc (size_t c)
{
  printf ("malloc called with %zu\n", c);
  return __real_malloc (c);
}

If you link other code with this file using --wrap malloc, then all calls
to "malloc" will call the function "__wrap_malloc" instead. The call to
"__real_malloc" in "__wrap_malloc" will call the real "malloc" function.

Added:
    lld/trunk/test/elf/wrap.test
Modified:
    lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
    lld/trunk/lib/Driver/GnuLdDriver.cpp
    lld/trunk/lib/Driver/GnuLdOptions.td
    lld/trunk/lib/ReaderWriter/ELF/ELFFile.h
    lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp

Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=228906&r1=228905&r2=228906&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Wed Feb 11 23:02:46 2015
@@ -302,6 +302,11 @@ public:
     _scripts.push_back(std::move(script));
   }
 
+  // --wrap option.
+  void addWrapForSymbol(StringRef);
+
+  StringRefVector wrapCalls() const;
+
 private:
   ELFLinkingContext() LLVM_DELETED_FUNCTION;
 
@@ -341,6 +346,7 @@ protected:
   StringRef _soname;
   StringRefVector _rpathList;
   StringRefVector _rpathLinkList;
+  StringRefVector _wrapCalls;
   std::map<std::string, uint64_t> _absoluteSymbols;
   llvm::StringSet<> _dynamicallyExportedSymbols;
   std::vector<std::unique_ptr<script::Parser>> _scripts;

Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=228906&r1=228905&r2=228906&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Wed Feb 11 23:02:46 2015
@@ -586,6 +586,10 @@ bool GnuLdDriver::parse(int argc, const
       ctx->addRpathLink(path);
   }
 
+  // Support --wrap option.
+  for (auto *arg : parsedArgs->filtered(OPT_wrap))
+    ctx->addWrapForSymbol(arg->getValue());
+
   // Register possible input file parsers.
   ctx->registry().addSupportELFObjects(*ctx);
   ctx->registry().addSupportArchives(ctx->logInputFiles());

Modified: lld/trunk/lib/Driver/GnuLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdOptions.td?rev=228906&r1=228905&r2=228906&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdOptions.td (original)
+++ lld/trunk/lib/Driver/GnuLdOptions.td Wed Feb 11 23:02:46 2015
@@ -246,7 +246,13 @@ def strip_all : Flag<["--"], "strip-all"
      Group<grp_symbolopts>;
 def alias_strip_all : Flag<["-"], "s">,
      Alias<strip_all>;
-
+defm wrap : smDash<"wrap", "wrap",
+            "Use a wrapper function for symbol. Any "
+            " undefined reference to symbol will be resolved to "
+            "\"__wrap_symbol\". Any undefined reference to \"__real_symbol\""
+            " will be resolved to symbol.">,
+            MetaVarName<"<symbol>">,
+            Group<grp_symbolopts>;
 //===----------------------------------------------------------------------===//
 /// Optimization Options
 //===----------------------------------------------------------------------===//

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFFile.h?rev=228906&r1=228905&r2=228906&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFFile.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFFile.h Wed Feb 11 23:02:46 2015
@@ -17,6 +17,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Allocator.h"
@@ -117,19 +118,23 @@ template <class ELFT> class ELFFile : pu
 public:
   ELFFile(StringRef name, ELFLinkingContext &ctx)
       : File(name, kindObject), _ordinal(0),
-        _doStringsMerge(ctx.mergeCommonStrings()), _ctx(ctx) {
+        _doStringsMerge(ctx.mergeCommonStrings()), _useWrap(false), _ctx(ctx) {
     setLastError(std::error_code());
   }
 
   ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
       : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
-        _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()), _ctx(ctx) {}
+        _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()),
+        _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {}
 
   static ErrorOr<std::unique_ptr<ELFFile>>
   create(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
 
   virtual Reference::KindArch kindArch();
 
+  /// \brief Create symbols from LinkingContext.
+  std::error_code createAtomsFromContext();
+
   /// \brief Read input sections and populate necessary data structures
   /// to read them later and create atoms
   std::error_code createAtomizableSections();
@@ -362,8 +367,14 @@ protected:
   /// \brief the cached options relevant while reading the ELF File
   bool _doStringsMerge;
 
+  /// \brief Is --wrap on ?
+  bool _useWrap;
+
   /// \brief The LinkingContext.
   ELFLinkingContext &_ctx;
+
+  // Wrap map
+  llvm::StringMap<UndefinedAtom *> _wrapSymbolMap;
 };
 
 /// \brief All atoms are owned by a File. To add linker specific atoms
@@ -428,6 +439,9 @@ std::error_code ELFFile<ELFT>::doParse()
   if (ec)
     return ec;
 
+  if ((ec = createAtomsFromContext()))
+    return ec;
+
   // Read input sections from the input file that need to be converted to
   // atoms
   if ((ec = createAtomizableSections()))
@@ -579,6 +593,13 @@ std::error_code ELFFile<ELFT>::createSym
       _absoluteAtoms._atoms.push_back(*absAtom);
       _symbolToAtomMapping.insert(std::make_pair(&*SymI, *absAtom));
     } else if (isUndefinedSymbol(&*SymI)) {
+      if (_useWrap &&
+          (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) {
+        auto wrapAtom = _wrapSymbolMap.find(*symbolName);
+        _symbolToAtomMapping.insert(
+            std::make_pair(&*SymI, wrapAtom->getValue()));
+        continue;
+      }
       ErrorOr<ELFUndefinedAtom<ELFT> *> undefAtom =
           handleUndefinedSymbol(*symbolName, &*SymI);
       _undefinedAtoms._atoms.push_back(*undefAtom);
@@ -731,6 +752,38 @@ template <class ELFT> std::error_code EL
   return std::error_code();
 }
 
+template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
+  if (!_useWrap)
+    return std::error_code();
+  // Steps :-
+  // a) Create an undefined atom for the symbol specified by the --wrap option,
+  // as that
+  // may be needed to be pulled from an archive.
+  // b) Create an undefined atom for __wrap_<symbolname>.
+  // c) All references to the symbol specified by wrap should point to
+  // __wrap_<symbolname>
+  // d) All references to __real_symbol should point to the <symbol>
+  for (auto wrapsym : _ctx.wrapCalls()) {
+    // Create a undefined symbol fror the wrap symbol.
+    UndefinedAtom *wrapSymAtom =
+        new (_readerStorage) SimpleUndefinedAtom(*this, wrapsym);
+    StringRef wrapCallSym =
+        _ctx.allocateString((llvm::Twine("__wrap_") + wrapsym).str());
+    StringRef realCallSym =
+        _ctx.allocateString((llvm::Twine("__real_") + wrapsym).str());
+    UndefinedAtom *wrapCallAtom =
+        new (_readerStorage) SimpleUndefinedAtom(*this, wrapCallSym);
+    // Create maps, when there is call to sym, it should point to wrapCallSym.
+    _wrapSymbolMap.insert(std::make_pair(wrapsym, wrapCallAtom));
+    // Whenever there is a reference to realCall it should point to the symbol
+    // created for each wrap usage.
+    _wrapSymbolMap.insert(std::make_pair(realCallSym, wrapSymAtom));
+    _undefinedAtoms._atoms.push_back(wrapSymAtom);
+    _undefinedAtoms._atoms.push_back(wrapCallAtom);
+  }
+  return std::error_code();
+}
+
 template <class ELFT>
 ELFDefinedAtom<ELFT> *ELFFile<ELFT>::createDefinedAtomAndAssignRelocations(
     StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=228906&r1=228905&r2=228906&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Wed Feb 11 23:02:46 2015
@@ -256,4 +256,13 @@ std::string ELFLinkingContext::demangle(
   return symbolName;
 }
 
+// Support --wrap option.
+void ELFLinkingContext::addWrapForSymbol(StringRef symbol) {
+  _wrapCalls.push_back(symbol);
+}
+
+ELFLinkingContext::StringRefVector ELFLinkingContext::wrapCalls() const {
+  return _wrapCalls;
+}
+
 } // end namespace lld

Added: lld/trunk/test/elf/wrap.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/wrap.test?rev=228906&view=auto
==============================================================================
--- lld/trunk/test/elf/wrap.test (added)
+++ lld/trunk/test/elf/wrap.test Wed Feb 11 23:02:46 2015
@@ -0,0 +1,279 @@
+# This tests the functionality of using the --wrap option.
+# The test case is extracted by compiling and linking the following code.
+#
+#cat > main.c << \!
+#int main() {
+#  foo();
+#  return 0;
+#}
+#!
+#
+#cat > wrapfoo.c << \!
+#int __wrap_foo() {
+#  __real_foo();
+#  return 0;
+#}
+#!
+#
+#cat > realfoo.c << \!
+#int foo() {
+#  return 0;
+#}
+#!
+#
+#clang main.c wrapfoo.c realfoo.c -Xlinker --wrap -Xlinker foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.main.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.wrapfoo.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.realfoo.o
+#RUN: lld -flavor gnu -target x86_64 %t.main.o %t.wrapfoo.o %t.realfoo.o \
+#RUN: --wrap foo --noinhibit-exec --output-filetype=yaml -o %t2.out
+#RUN: lld -flavor gnu -target x86_64 %t.main.o %t.wrapfoo.o  \
+#RUN: --wrap foo --noinhibit-exec --output-filetype=yaml -o %t2.out.undef 2>&1 |  \
+#RUN: FileCheck %s -check-prefix=CHECKUNDEF
+#CHECKWRAP:  - name:            main
+#CHECKWRAP:    references:
+#CHECKWRAP:      - kind:            R_X86_64_PC32
+#CHECKWRAP:        target:          __wrap_foo
+#CHECKWRAP:  - name:            __wrap_foo
+#CHECKWRAP:    references:
+#CHECKWRAP:      - kind:            R_X86_64_PC32
+#CHECKWRAP:        target:          foo
+#CHECKUNDEF: Undefined symbol: {{.*}}main.o: foo
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         5031C0E80000000031C05AC3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000004
+        Symbol:          foo
+        Type:            R_X86_64_PC32
+        Addend:          -4
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000037A5200017810011B0C070890010000140000001C000000000000000C00000000410E1000000000
+  - Name:            .rela.eh_frame
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .eh_frame
+    Relocations:
+      - Offset:          0x0000000000000020
+        Symbol:          .text
+        Type:            R_X86_64_PC32
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+    - Name:            .eh_frame
+      Type:            STT_SECTION
+      Section:         .eh_frame
+  Global:
+    - Name:            main
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000C
+    - Name:            foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         5031C0E80000000031C05AC3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000004
+        Symbol:          __real_foo
+        Type:            R_X86_64_PC32
+        Addend:          -4
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000037A5200017810011B0C070890010000140000001C000000000000000C00000000410E1000000000
+  - Name:            .rela.eh_frame
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .eh_frame
+    Relocations:
+      - Offset:          0x0000000000000020
+        Symbol:          .text
+        Type:            R_X86_64_PC32
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+    - Name:            .eh_frame
+      Type:            STT_SECTION
+      Section:         .eh_frame
+  Global:
+    - Name:            __wrap_foo
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000C
+    - Name:            __real_foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         31C0C3
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000037A5200017810011B0C070890010000140000001C00000000000000030000000000000000000000
+  - Name:            .rela.eh_frame
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .eh_frame
+    Relocations:
+      - Offset:          0x0000000000000020
+        Symbol:          .text
+        Type:            R_X86_64_PC32
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+    - Name:            .eh_frame
+      Type:            STT_SECTION
+      Section:         .eh_frame
+  Global:
+    - Name:            foo
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x0000000000000003
+...





More information about the llvm-commits mailing list