[lld][WebAssembly] Fail if bitcode objects are pulled in after LTO
authorSam Clegg <sbc@chromium.org>
Fri, 20 Dec 2019 01:30:24 +0000 (17:30 -0800)
committerSam Clegg <sbc@chromium.org>
Wed, 12 Feb 2020 01:36:15 +0000 (17:36 -0800)
This can happen if lto::LTO::getRuntimeLibcallSymbols doesn't return
an complete/accurate list of libcalls.  In this case new bitcode
object can be linked in after LTO.

For example the WebAssembly backend currently calls:
  setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");

But `__truncsfhf2` is not part of `getRuntimeLibcallSymbols` so if
this symbol is generated during LTO the link will currently fail.

Without this change the linker crashes because the bitcode symbol
makes it all the way to the output phase.

See: https://bugs.llvm.org/show_bug.cgi?id=44353

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

lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll [new file with mode: 0644]
lld/test/wasm/lto/libcall-truncsfhf2.ll [new file with mode: 0644]
lld/wasm/InputFiles.cpp
lld/wasm/InputFiles.h
lld/wasm/SymbolTable.cpp

diff --git a/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll b/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll
new file mode 100644 (file)
index 0000000..839890e
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define half @__truncsfhf2(float) {
+  ret half 0.0
+}
diff --git a/lld/test/wasm/lto/libcall-truncsfhf2.ll b/lld/test/wasm/lto/libcall-truncsfhf2.ll
new file mode 100644 (file)
index 0000000..a427acd
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/libcall-truncsfhf2.ll -o %t.truncsfhf2.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t.truncsfhf2.o
+; RUN: not wasm-ld --export-all %t.o %t.a -o %t.wasm 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@g_float = global float 0.0
+@g_half = global half 0.0
+
+define void @_start() {
+  %val1 = load float, float* @g_float
+  %v0 = fptrunc float %val1 to half
+  store half %v0, half* @g_half
+  ret void
+}
+
+; CHECK: wasm-ld: error: {{.*}}truncsfhf2.o: attempt to add bitcode file after LTO.
index 2d96062..d71a2b4 100644 (file)
@@ -536,7 +536,15 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
   return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0);
 }
 
+bool BitcodeFile::doneLTO = false;
+
 void BitcodeFile::parse() {
+  if (doneLTO) {
+    error(toString(mb.getBufferIdentifier()) +
+          ": attempt to add bitcode file after LTO.");
+    return;
+  }
+
   obj = check(lto::InputFile::create(MemoryBufferRef(
       mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier()))));
   Triple t(obj->getTargetTriple());
index d5aebf4..bf4a4ec 100644 (file)
@@ -160,6 +160,10 @@ public:
 
   void parse();
   std::unique_ptr<llvm::lto::InputFile> obj;
+
+  // Set to true once LTO is complete in order prevent further bitcode objects
+  // being added.
+  static bool doneLTO;
 };
 
 inline bool isBitcode(MemoryBufferRef mb) {
index 3c1acbd..ce74b6a 100644 (file)
@@ -65,6 +65,9 @@ void SymbolTable::addFile(InputFile *file) {
 // Because all bitcode files that the program consists of are passed
 // to the compiler at once, it can do whole-program optimization.
 void SymbolTable::addCombinedLTOObject() {
+  // Prevent further LTO objects being included
+  BitcodeFile::doneLTO = true;
+
   if (bitcodeFiles.empty())
     return;