[lld] r361639 - [WebAssebmly] Add support for --wrap
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Fri May 24 07:14:25 PDT 2019
Author: sbc
Date: Fri May 24 07:14:25 2019
New Revision: 361639
URL: http://llvm.org/viewvc/llvm-project?rev=361639&view=rev
Log:
[WebAssebmly] Add support for --wrap
The code for implementing this features is taken almost verbatim
from the ELF backend.
Fixes: https://bugs.llvm.org/show_bug.cgi?id=41681
Differential Revision: https://reviews.llvm.org/D62380
Added:
lld/trunk/test/wasm/wrap.ll
Modified:
lld/trunk/ELF/Driver.cpp
lld/trunk/ELF/InputFiles.h
lld/trunk/include/lld/Common/LLVM.h
lld/trunk/wasm/Driver.cpp
lld/trunk/wasm/InputFiles.h
lld/trunk/wasm/LTO.cpp
lld/trunk/wasm/Options.td
lld/trunk/wasm/SymbolTable.cpp
lld/trunk/wasm/SymbolTable.h
lld/trunk/wasm/Symbols.h
Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Fri May 24 07:14:25 2019
@@ -1522,7 +1522,7 @@ static void wrapSymbols(ArrayRef<Wrapped
// Update pointers in input files.
parallelForEach(ObjectFiles, [&](InputFile *File) {
- std::vector<Symbol *> &Syms = File->getMutableSymbols();
+ MutableArrayRef<Symbol *> Syms = File->getMutableSymbols();
for (size_t I = 0, E = Syms.size(); I != E; ++I)
if (Symbol *S = Map.lookup(Syms[I]))
Syms[I] = S;
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri May 24 07:14:25 2019
@@ -90,7 +90,7 @@ public:
// function on files of other types.
ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
- std::vector<Symbol *> &getMutableSymbols() {
+ MutableArrayRef<Symbol *> getMutableSymbols() {
assert(FileKind == BinaryKind || FileKind == ObjKind ||
FileKind == BitcodeKind);
return Symbols;
Modified: lld/trunk/include/lld/Common/LLVM.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Common/LLVM.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/include/lld/Common/LLVM.h (original)
+++ lld/trunk/include/lld/Common/LLVM.h Fri May 24 07:14:25 2019
@@ -29,6 +29,7 @@ class Twine;
class MemoryBuffer;
class MemoryBufferRef;
template <typename T> class ArrayRef;
+template <typename T> class MutableArrayRef;
template <unsigned InternalLen> class SmallString;
template <typename T, unsigned N> class SmallVector;
template <typename T> class ErrorOr;
@@ -62,6 +63,7 @@ using llvm::isa;
// ADT's.
using llvm::ArrayRef;
+using llvm::MutableArrayRef;
using llvm::Error;
using llvm::ErrorOr;
using llvm::Expected;
Added: lld/trunk/test/wasm/wrap.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/wrap.ll?rev=361639&view=auto
==============================================================================
--- lld/trunk/test/wasm/wrap.ll (added)
+++ lld/trunk/test/wasm/wrap.ll Fri May 24 07:14:25 2019
@@ -0,0 +1,40 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -wrap nosuchsym -wrap foo -o %t.wasm %t.o
+; RUN: wasm-ld -emit-relocs -wrap foo -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i32 @foo() {
+ ret i32 1
+}
+
+define void @_start() {
+entry:
+ call i32 @foo()
+ ret void
+}
+
+declare i32 @__real_foo()
+
+define i32 @__wrap_foo() {
+ %rtn = call i32 @__real_foo()
+ ret i32 %rtn
+}
+
+; CHECK: - Type: CODE
+; CHECK-NEXT: Relocations:
+; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Offset: 0x00000009
+; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x00000013
+
+; CHECK: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: foo
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: __wrap_foo
Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Fri May 24 07:14:25 2019
@@ -535,6 +535,84 @@ static std::string createResponseFile(co
return Data.str();
}
+// The --wrap option is a feature to rename symbols so that you can write
+// wrappers for existing functions. If you pass `-wrap=foo`, all
+// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
+// expected to write `wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `real_foo`, so you can call that from your
+// wrapper.
+//
+// This data structure is instantiated for each -wrap option.
+struct WrappedSymbol {
+ Symbol *Sym;
+ Symbol *Real;
+ Symbol *Wrap;
+};
+
+static Symbol *addUndefined(StringRef Name) {
+ return Symtab->addUndefinedFunction(Name, "", "", 0, nullptr, nullptr);
+}
+
+// Handles -wrap option.
+//
+// This function instantiates wrapper symbols. At this point, they seem
+// like they are not being used at all, so we explicitly set some flags so
+// that LTO won't eliminate them.
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
+ std::vector<WrappedSymbol> V;
+ DenseSet<StringRef> Seen;
+
+ for (auto *Arg : Args.filtered(OPT_wrap)) {
+ StringRef Name = Arg->getValue();
+ if (!Seen.insert(Name).second)
+ continue;
+
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ continue;
+
+ Symbol *Real = addUndefined(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+ V.push_back({Sym, Real, Wrap});
+
+ // We want to tell LTO not to inline symbols to be overwritten
+ // because LTO doesn't know the final symbol contents after renaming.
+ Real->CanInline = false;
+ Sym->CanInline = false;
+
+ // Tell LTO not to eliminate these symbols.
+ Sym->IsUsedInRegularObj = true;
+ Wrap->IsUsedInRegularObj = true;
+ Real->IsUsedInRegularObj = false;
+ }
+ return V;
+}
+
+// Do renaming for -wrap by updating pointers to symbols.
+//
+// When this function is executed, only InputFiles and symbol table
+// contain pointers to symbol objects. We visit them to replace pointers,
+// so that wrapped symbols are swapped as instructed by the command line.
+static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
+ DenseMap<Symbol *, Symbol *> Map;
+ for (const WrappedSymbol &W : Wrapped) {
+ Map[W.Sym] = W.Wrap;
+ Map[W.Real] = W.Sym;
+ }
+
+ // Update pointers in input files.
+ parallelForEach(Symtab->ObjectFiles, [&](InputFile *File) {
+ MutableArrayRef<Symbol *> Syms = File->getMutableSymbols();
+ for (size_t I = 0, E = Syms.size(); I != E; ++I)
+ if (Symbol *S = Map.lookup(Syms[I]))
+ Syms[I] = S;
+ });
+
+ // Update pointers in the symbol table.
+ for (const WrappedSymbol &W : Wrapped)
+ Symtab->wrap(W.Sym, W.Real, W.Wrap);
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
WasmOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -628,6 +706,9 @@ void LinkerDriver::link(ArrayRef<const c
for (auto *Arg : Args.filtered(OPT_export))
handleUndefined(Arg->getValue());
+ // Create wrapped symbols for -wrap option.
+ std::vector<WrappedSymbol> Wrapped = addWrappedSymbols(Args);
+
// Do link-time optimization if given files are LLVM bitcode files.
// This compiles bitcode files into real object files.
Symtab->addCombinedLTOObject();
@@ -640,6 +721,10 @@ void LinkerDriver::link(ArrayRef<const c
if (errorCount())
return;
+ // Apply symbol renames for -wrap.
+ if (!Wrapped.empty())
+ wrapSymbols(Wrapped);
+
for (auto *Arg : Args.filtered(OPT_export)) {
Symbol *Sym = Symtab->find(Arg->getValue());
if (Sym && Sym->isDefined())
Modified: lld/trunk/wasm/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.h (original)
+++ lld/trunk/wasm/InputFiles.h Fri May 24 07:14:25 2019
@@ -61,6 +61,8 @@ public:
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
+ MutableArrayRef<Symbol *> getMutableSymbols() { return Symbols; }
+
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
MemoryBufferRef MB;
Modified: lld/trunk/wasm/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/LTO.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/LTO.cpp (original)
+++ lld/trunk/wasm/LTO.cpp Fri May 24 07:14:25 2019
@@ -108,6 +108,11 @@ void BitcodeCompiler::add(BitcodeFile &F
(R.Prevailing && Sym->isExported());
if (R.Prevailing)
undefine(Sym);
+
+ // We tell LTO to not apply interprocedural optimization for wrapped
+ // (with --wrap) symbols because otherwise LTO would inline them while
+ // their values are still not final.
+ R.LinkerRedefined = !Sym->CanInline;
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Fri May 24 07:14:25 2019
@@ -112,6 +112,9 @@ def version: F<"version">, HelpText<"Dis
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
+
// The follow flags are unique to wasm
def allow_undefined: F<"allow-undefined">,
Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Fri May 24 07:14:25 2019
@@ -65,7 +65,8 @@ void SymbolTable::addCombinedLTOObject()
}
void SymbolTable::reportRemainingUndefines() {
- for (Symbol *Sym : SymVector) {
+ for (const auto& Pair : SymMap) {
+ const Symbol *Sym = SymVector[Pair.second];
if (!Sym->isUndefined() || Sym->isWeak())
continue;
if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
@@ -104,6 +105,7 @@ std::pair<Symbol *, bool> SymbolTable::i
Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->IsUsedInRegularObj = false;
+ Sym->CanInline = true;
Sym->Traced = Trace;
SymVector.emplace_back(Sym);
return {Sym, true};
@@ -539,6 +541,19 @@ void SymbolTable::trace(StringRef Name)
SymMap.insert({CachedHashStringRef(Name), -1});
}
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+ // Swap symbols as instructed by -wrap.
+ int &OrigIdx = SymMap[CachedHashStringRef(Sym->getName())];
+ int &RealIdx= SymMap[CachedHashStringRef(Real->getName())];
+ int &WrapIdx = SymMap[CachedHashStringRef(Wrap->getName())];
+ LLVM_DEBUG(dbgs() << "wrap: " << Sym->getName() << "\n");
+
+ // Anyone looking up __real symbols should get the original
+ RealIdx = OrigIdx;
+ // Anyone looking up the original should get the __wrap symbol
+ OrigIdx = WrapIdx;
+}
+
static const uint8_t UnreachableFn[] = {
0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
0x00 /* opcode unreachable */, 0x0b /* opcode end */
Modified: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (original)
+++ lld/trunk/wasm/SymbolTable.h Fri May 24 07:14:25 2019
@@ -35,14 +35,11 @@ class InputSegment;
// There is one add* function per symbol type.
class SymbolTable {
public:
+ void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
+
void addFile(InputFile *File);
- void addCombinedLTOObject();
- std::vector<ObjFile *> ObjectFiles;
- std::vector<SharedFile *> SharedFiles;
- std::vector<BitcodeFile *> BitcodeFiles;
- std::vector<InputFunction *> SyntheticFunctions;
- std::vector<InputGlobal *> SyntheticGlobals;
+ void addCombinedLTOObject();
void reportRemainingUndefines();
@@ -87,6 +84,12 @@ public:
void handleSymbolVariants();
void handleWeakUndefines();
+ std::vector<ObjFile *> ObjectFiles;
+ std::vector<SharedFile *> SharedFiles;
+ std::vector<BitcodeFile *> BitcodeFiles;
+ std::vector<InputFunction *> SyntheticFunctions;
+ std::vector<InputGlobal *> SyntheticGlobals;
+
private:
std::pair<Symbol *, bool> insert(StringRef Name, const InputFile *File);
std::pair<Symbol *, bool> insertName(StringRef Name);
Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Fri May 24 07:14:25 2019
@@ -114,6 +114,11 @@ public:
// command line flag)
unsigned ForceExport : 1;
+ // False if LTO shouldn't inline whatever this symbol points to. If a symbol
+ // is overwritten after LTO, LTO shouldn't inline the symbol because it
+ // doesn't know the final contents of the symbol.
+ unsigned CanInline : 1;
+
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
@@ -131,8 +136,8 @@ public:
protected:
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
- : IsUsedInRegularObj(false), ForceExport(false), Traced(false),
- Name(Name), SymbolKind(K), Flags(Flags), File(F),
+ : IsUsedInRegularObj(false), ForceExport(false), CanInline(false),
+ Traced(false), Name(Name), SymbolKind(K), Flags(Flags), File(F),
Referenced(!Config->GcSections) {}
StringRef Name;
@@ -474,6 +479,7 @@ T *replaceSymbol(Symbol *S, ArgT &&... A
T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
S2->ForceExport = SymCopy.ForceExport;
+ S2->CanInline = SymCopy.CanInline;
S2->Traced = SymCopy.Traced;
// Print out a log message if --trace-symbol was specified.
More information about the llvm-commits
mailing list