[lld] r361678 - [WebAssembly] Relax signature checking for undefined functions that are not called directly

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri May 24 15:45:08 PDT 2019


Author: sbc
Date: Fri May 24 15:45:08 2019
New Revision: 361678

URL: http://llvm.org/viewvc/llvm-project?rev=361678&view=rev
Log:
[WebAssembly] Relax signature checking for undefined functions that are not called directly

When function signatures don't match and the undefined function is not
called directly (i.e. only has its address taken) we don't issue a
warning or create a runtime thunk for the undefined function.

Instead in this case we simply use the defined version of the function.
This is possible since checking signatures of dynamic calls happens
at runtime so any invalid usage will still result in a runtime error.

This is needed to allow C++ programs to link without generating
warnings.  Its not uncommon in C++ for vtables to be populated by
function address whee the signature of the function is not known in the
compilation unit.  In this case clang declares the method as void(void)
and relies on the vtable caller casting the data back to the correct
signature.

Fixes: https://bugs.llvm.org/show_bug.cgi?id=40412

Differential Revision: https://reviews.llvm.org/D62153

Added:
    lld/trunk/test/wasm/signature-mismatch-unknown.ll
Modified:
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/InputFiles.cpp
    lld/trunk/wasm/InputFiles.h
    lld/trunk/wasm/SymbolTable.cpp
    lld/trunk/wasm/SymbolTable.h
    lld/trunk/wasm/Symbols.h

Added: lld/trunk/test/wasm/signature-mismatch-unknown.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/signature-mismatch-unknown.ll?rev=361678&view=auto
==============================================================================
--- lld/trunk/test/wasm/signature-mismatch-unknown.ll (added)
+++ lld/trunk/test/wasm/signature-mismatch-unknown.ll Fri May 24 15:45:08 2019
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.main.o
+; RUN: wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o
+; RUN: wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o
+
+target triple = "wasm32-unknown-unknown"
+
+; Function declartion with incorrect signature.
+declare dso_local void @ret32()
+
+; Simply taking the address of the function should *not* generate the
+; the signature mismatch warning.
+ at ptr = dso_local global i8* bitcast (void ()* @ret32 to i8*), align 8
+
+define hidden void @_start() local_unnamed_addr {
+  %addr = load i32 ()*, i32 ()** bitcast (i8** @ptr to i32 ()**), align 8
+  call i32 %addr()
+  ret void
+}

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Fri May 24 15:45:08 2019
@@ -550,7 +550,7 @@ struct WrappedSymbol {
 };
 
 static Symbol *addUndefined(StringRef Name) {
-  return Symtab->addUndefinedFunction(Name, "", "", 0, nullptr, nullptr);
+  return Symtab->addUndefinedFunction(Name, "", "", 0, nullptr, nullptr, false);
 }
 
 // Handles -wrap option.

Modified: lld/trunk/wasm/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.cpp?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.cpp (original)
+++ lld/trunk/wasm/InputFiles.cpp Fri May 24 15:45:08 2019
@@ -271,14 +271,16 @@ void ObjFile::parse(bool IgnoreComdats)
     }
   }
 
-  // Find the code and data sections.  Wasm objects can have at most one code
-  // and one data section.
   uint32_t SectionIndex = 0;
+  SymbolIsCalledDirectly.resize(WasmObj->getNumberOfSymbols(), false);
   for (const SectionRef &Sec : WasmObj->sections()) {
     const WasmSection &Section = WasmObj->getWasmSection(Sec);
+    // Wasm objects can have at most one code and one data section.
     if (Section.Type == WASM_SEC_CODE) {
+      assert(!CodeSection);
       CodeSection = &Section;
     } else if (Section.Type == WASM_SEC_DATA) {
+      assert(!DataSection);
       DataSection = &Section;
     } else if (Section.Type == WASM_SEC_CUSTOM) {
       CustomSections.emplace_back(make<InputSection>(Section, this));
@@ -286,6 +288,11 @@ void ObjFile::parse(bool IgnoreComdats)
       CustomSectionsByIndex[SectionIndex] = CustomSections.back();
     }
     SectionIndex++;
+    // Scans relocations to dermine determine if a function symbol is called
+    // directly
+    for (const WasmRelocation &Reloc : Section.Relocations)
+      if (Reloc.Type == R_WASM_FUNCTION_INDEX_LEB)
+        SymbolIsCalledDirectly[Reloc.Index] = true;
   }
 
   TypeMap.resize(getWasmObj()->types().size());
@@ -326,10 +333,16 @@ void ObjFile::parse(bool IgnoreComdats)
   Symbols.reserve(WasmObj->getNumberOfSymbols());
   for (const SymbolRef &Sym : WasmObj->symbols()) {
     const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
-    if (Symbol *Sym = createDefined(WasmSym))
-      Symbols.push_back(Sym);
-    else
-      Symbols.push_back(createUndefined(WasmSym));
+    if (WasmSym.isDefined()) {
+      // createDefined may fail if the symbol is comdat excluded in which case
+      // we fall back to creating an undefined symbol
+      if (Symbol *D = createDefined(WasmSym)) {
+        Symbols.push_back(D);
+        continue;
+      }
+    }
+    size_t Idx = Symbols.size();
+    Symbols.push_back(createUndefined(WasmSym, SymbolIsCalledDirectly[Idx]));
   }
 }
 
@@ -361,9 +374,6 @@ DataSymbol *ObjFile::getDataSymbol(uint3
 }
 
 Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
-  if (!Sym.isDefined())
-    return nullptr;
-
   StringRef Name = Sym.Info.Name;
   uint32_t Flags = Sym.Info.Flags;
 
@@ -417,7 +427,7 @@ Symbol *ObjFile::createDefined(const Was
   llvm_unreachable("unknown symbol kind");
 }
 
-Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
+Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly) {
   StringRef Name = Sym.Info.Name;
   uint32_t Flags = Sym.Info.Flags;
 
@@ -425,7 +435,7 @@ Symbol *ObjFile::createUndefined(const W
   case WASM_SYMBOL_TYPE_FUNCTION:
     return Symtab->addUndefinedFunction(Name, Sym.Info.ImportName,
                                         Sym.Info.ImportModule, Flags, this,
-                                        Sym.Signature);
+                                        Sym.Signature, IsCalledDirectly);
   case WASM_SYMBOL_TYPE_DATA:
     return Symtab->addUndefinedData(Name, Flags, this);
   case WASM_SYMBOL_TYPE_GLOBAL:
@@ -499,7 +509,7 @@ static Symbol *createBitcodeSymbol(const
   if (ObjSym.isUndefined() || ExcludedByComdat) {
     if (ObjSym.isExecutable())
       return Symtab->addUndefinedFunction(Name, Name, DefaultModule, Flags, &F,
-                                          nullptr);
+                                          nullptr, true);
     return Symtab->addUndefinedData(Name, Flags, &F);
   }
 

Modified: lld/trunk/wasm/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.h (original)
+++ lld/trunk/wasm/InputFiles.h Fri May 24 15:45:08 2019
@@ -69,6 +69,13 @@ protected:
 
   // List of all symbols referenced or defined by this file.
   std::vector<Symbol *> Symbols;
+  // Bool for each symbol, true if called directly.  This allows us to implement
+  // a weaker form of signature checking where undefined functions that are not
+  // called directly (i.e. only address taken) don't have to match the defined
+  // function's signature.  We cannot do this for directly called functions
+  // because those signatures are checked at validation times.
+  // See https://bugs.llvm.org/show_bug.cgi?id=40412
+  std::vector<bool> SymbolIsCalledDirectly;
 
 private:
   const Kind FileKind;
@@ -138,7 +145,7 @@ public:
 
 private:
   Symbol *createDefined(const WasmSymbol &Sym);
-  Symbol *createUndefined(const WasmSymbol &Sym);
+  Symbol *createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly);
 
   bool isExcludedByComdat(InputChunk *Chunk) const;
 

Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Fri May 24 15:45:08 2019
@@ -286,7 +286,11 @@ Symbol *SymbolTable::addDefinedFunction(
     return S;
   }
 
-  if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
+  bool CheckSig = true;
+  if (auto UD = dyn_cast<UndefinedFunction>(ExistingFunction))
+    CheckSig = UD->IsCalledDirectly;
+
+  if (CheckSig && Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
     Symbol* Variant;
     if (getFunctionVariant(S, &Function->Signature, File, &Variant))
       // New variant, always replace
@@ -384,7 +388,8 @@ Symbol *SymbolTable::addDefinedEvent(Str
 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
                                           StringRef ImportModule,
                                           uint32_t Flags, InputFile *File,
-                                          const WasmSignature *Sig) {
+                                          const WasmSignature *Sig,
+                                          bool IsCalledDirectly) {
   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
              " [" << (Sig ? toString(*Sig) : "none") << "]\n");
 
@@ -396,7 +401,7 @@ Symbol *SymbolTable::addUndefinedFunctio
 
   auto Replace = [&]() {
     replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
-                                     File, Sig);
+                                     File, Sig, IsCalledDirectly);
   };
 
   if (WasInserted)
@@ -409,7 +414,7 @@ Symbol *SymbolTable::addUndefinedFunctio
       reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
       return S;
     }
-    if (!signatureMatches(ExistingFunction, Sig))
+    if (IsCalledDirectly && !signatureMatches(ExistingFunction, Sig))
       if (getFunctionVariant(S, Sig, File, &S))
         Replace();
   }

Modified: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (original)
+++ lld/trunk/wasm/SymbolTable.h Fri May 24 15:45:08 2019
@@ -63,7 +63,8 @@ public:
 
   Symbol *addUndefinedFunction(StringRef Name, StringRef ImportName,
                                StringRef ImportModule, uint32_t Flags,
-                               InputFile *File, const WasmSignature *Signature);
+                               InputFile *File, const WasmSignature *Signature,
+                               bool IsCalledDirectly);
   Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File);
   Symbol *addUndefinedGlobal(StringRef Name, StringRef ImportName,
                              StringRef ImportModule,  uint32_t Flags,

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=361678&r1=361677&r2=361678&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Fri May 24 15:45:08 2019
@@ -194,9 +194,10 @@ public:
   UndefinedFunction(StringRef Name, StringRef ImportName,
                     StringRef ImportModule, uint32_t Flags,
                     InputFile *File = nullptr,
-                    const WasmSignature *Type = nullptr)
+                    const WasmSignature *Type = nullptr,
+                    bool IsCalledDirectly = true)
       : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type),
-        ImportName(ImportName), ImportModule(ImportModule) {}
+        ImportName(ImportName), ImportModule(ImportModule), IsCalledDirectly(IsCalledDirectly) {}
 
   static bool classof(const Symbol *S) {
     return S->kind() == UndefinedFunctionKind;
@@ -204,6 +205,7 @@ public:
 
   StringRef ImportName;
   StringRef ImportModule;
+  bool IsCalledDirectly;
 };
 
 // Section symbols for output sections are different from those for input




More information about the llvm-commits mailing list