ELF: Implement --wrap.
In this patch, all symbols are resolved normally and then wrap options
are applied. Renaming is implemented by mutating `Body` pointers of
Symbols. (As a result, Symtab.find(SymbolName)->getName() may return
a string that's different from SymbolName, but that is by design.
I designed the symbol and the symbol table to allow this kind of
operations.)
http://reviews.llvm.org/D15896
llvm-svn: 257075
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index da666cf..12ad8ec 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -310,6 +310,9 @@
for (StringRef S : Config->Undefined)
Symtab.addUndefinedOpt(S);
+ for (auto *Arg : Args.filtered(OPT_wrap))
+ Symtab.wrap(Arg->getValue());
+
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 622cbb9..1b02c5c 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -109,6 +109,9 @@
def whole_archive : Flag<["--", "-"], "whole-archive">,
HelpText<"Force load of all members in a static library">;
+def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"<symbol>">,
+ HelpText<"Use wrapper functions for symbol">;
+
def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
@@ -136,6 +139,7 @@
def alias_script_T : Separate<["-"], "T">, Alias<script>;
def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>;
+def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias<wrap>;
// Our symbol resolution algorithm handles symbols in archive files differently
// than traditional linkers, so we don't need --start-group and --end-group.
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 74951ba..01738d0 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -18,6 +18,7 @@
#include "Config.h"
#include "Error.h"
#include "Symbols.h"
+#include "llvm/Support/StringSaver.h"
using namespace llvm;
using namespace llvm::object;
@@ -124,6 +125,19 @@
return Sym;
}
+// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
+// Used to implement --wrap.
+template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
+ if (Symtab.count(Name) == 0)
+ return;
+ StringSaver Saver(Alloc);
+ Symbol *Sym = addUndefined(Name)->getSymbol();
+ Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol();
+ Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol();
+ Real->Body = Sym->Body;
+ Sym->Body = Wrap->Body;
+}
+
// Returns a file from which symbol B was created.
// If B does not belong to any file, returns a nullptr.
template <class ELFT>
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 4f8f5af..f240d81 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -57,6 +57,7 @@
SymbolBody *addIgnored(StringRef Name);
void scanShlibUndefined();
SymbolBody *find(StringRef Name);
+ void wrap(StringRef Name);
ELFFileBase<ELFT> *findFile(SymbolBody *B);
private:
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 16a3b33..59135bf 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -105,6 +105,7 @@
// you can access P->Backref->Body to get the resolver's result.
void setBackref(Symbol *P) { Backref = P; }
SymbolBody *repl() { return Backref ? Backref->Body : this; }
+ Symbol *getSymbol() { return Backref; }
// Decides which symbol should "win" in the symbol table, this or
// the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if