[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