[WebAssembly][lld] Exclude COMDAT sections
authorDerek Schuff <dschuff@chromium.org>
Wed, 9 Dec 2020 18:57:27 +0000 (10:57 -0800)
committerDerek Schuff <dschuff@chromium.org>
Fri, 11 Dec 2020 01:47:41 +0000 (17:47 -0800)
Allow exclusion/discarding of custom sections with COMDAT groups.
It piggybacks on the existing COMDAT-handling code, but applies to custom sections as well.

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

lld/test/wasm/Inputs/comdat1.s [new file with mode: 0644]
lld/test/wasm/Inputs/comdat2.s [new file with mode: 0644]
lld/test/wasm/comdat-sections.s [new file with mode: 0644]
lld/wasm/InputChunks.h
lld/wasm/InputFiles.cpp
lld/wasm/OutputSections.cpp
lld/wasm/Writer.cpp

diff --git a/lld/test/wasm/Inputs/comdat1.s b/lld/test/wasm/Inputs/comdat1.s
new file mode 100644 (file)
index 0000000..ff988cc
--- /dev/null
@@ -0,0 +1,13 @@
+        .text
+        .section .text.foo,"G",@,foo,comdat
+        .globl foo
+        .type foo,@function
+foo:
+        .functype foo () -> ()
+        return
+        end_function
+
+        .section .debug_foo,"G",@,foo,comdat
+        .int32 1
+        .section .debug_foo,"G",@,duplicate,comdat
+        .int64 123
diff --git a/lld/test/wasm/Inputs/comdat2.s b/lld/test/wasm/Inputs/comdat2.s
new file mode 100644 (file)
index 0000000..f498fdd
--- /dev/null
@@ -0,0 +1,13 @@
+        .text
+        .section .text.foo,"G",@,foo,comdat
+        .globl foo
+        .type foo,@function
+foo:
+        .functype foo () -> ()
+        return
+        end_function
+
+        .section .debug_foo,"G",@,foo,comdat
+        .int32 2
+        .section .debug_foo,"G",@,duplicate,comdat
+        .int64 234
diff --git a/lld/test/wasm/comdat-sections.s b/lld/test/wasm/comdat-sections.s
new file mode 100644 (file)
index 0000000..fc8d2de
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: llvm-mc -triple=wasm32 -filetype=obj %p/Inputs/comdat1.s -o %t1.o
+# RUN: llvm-mc -triple=wasm32 -filetype=obj %p/Inputs/comdat2.s -o %t2.o
+# RUN: llvm-mc -triple=wasm32 -filetype=obj %s -o %t.o
+# RUN: wasm-ld  -o %t.wasm %t.o %t1.o %t2.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+
+        .globl  _start
+        .type  _start,@function
+_start:
+        .functype _start () -> ()
+        call foo
+        end_function
+
+        .functype foo () -> ()
+
+
+# Check that we got 1 copy of each of the .debug_foo sections from the 2 object
+# files, and that they came from the same object.
+# CHECK:  - Type:            CUSTOM
+# CHECK-NEXT:    Name:            .debug_foo
+# CHECK-NEXT:    Payload:         010000007B00000000000000
index ba4e2a5..9082d1d 100644 (file)
@@ -221,7 +221,7 @@ public:
 
   StringRef getName() const override { return section.Name; }
   StringRef getDebugName() const override { return StringRef(); }
-  uint32_t getComdat() const override { return UINT32_MAX; }
+  uint32_t getComdat() const override { return section.Comdat; }
 
 protected:
   ArrayRef<uint8_t> data() const override { return section.Content; }
index 2b3c259..68a9472 100644 (file)
@@ -341,6 +341,12 @@ void ObjFile::parse(bool ignoreComdats) {
     }
   }
 
+  ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats;
+  for (StringRef comdat : comdats) {
+    bool isNew = ignoreComdats || symtab->addComdat(comdat);
+    keptComdats.push_back(isNew);
+  }
+
   uint32_t sectionIndex = 0;
 
   // Bool for each symbol, true if called directly.  This allows us to implement
@@ -360,7 +366,9 @@ void ObjFile::parse(bool ignoreComdats) {
       assert(!dataSection);
       dataSection = &section;
     } else if (section.Type == WASM_SEC_CUSTOM) {
-      customSections.emplace_back(make<InputSection>(section, this));
+      auto *customSec = make<InputSection>(section, this);
+      customSec->discarded = isExcludedByComdat(customSec);
+      customSections.emplace_back(customSec);
       customSections.back()->setRelocations(section.Relocations);
       customSectionsByIndex[sectionIndex] = customSections.back();
     }
@@ -374,11 +382,6 @@ void ObjFile::parse(bool ignoreComdats) {
   typeMap.resize(getWasmObj()->types().size());
   typeIsUsed.resize(getWasmObj()->types().size(), false);
 
-  ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats;
-  for (StringRef comdat : comdats) {
-    bool isNew = ignoreComdats || symtab->addComdat(comdat);
-    keptComdats.push_back(isNew);
-  }
 
   // Populate `Segments`.
   for (const WasmSegment &s : wasmObj->dataSegments()) {
@@ -487,6 +490,10 @@ Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
   case WASM_SYMBOL_TYPE_SECTION: {
     InputSection *section = customSectionsByIndex[sym.Info.ElementIndex];
     assert(sym.isBindingLocal());
+    // Need to return null if discarded here? data and func only do that when
+    // binding is not local.
+    if (section->discarded)
+      return nullptr;
     return make<SectionSymbol>(flags, section, this);
   }
   case WASM_SYMBOL_TYPE_EVENT: {
index 89f51ec..1af448d 100644 (file)
@@ -239,6 +239,7 @@ void CustomSection::finalizeContents() {
   os.flush();
 
   for (InputSection *section : inputSections) {
+    assert(!section->discarded);
     section->outputSec = this;
     section->outputOffset = payloadSize;
     payloadSize += section->getSize();
index 3f25596..c95b925 100644 (file)
@@ -120,6 +120,9 @@ void Writer::calculateCustomSections() {
   bool stripDebug = config->stripDebug || config->stripAll;
   for (ObjFile *file : symtab->objectFiles) {
     for (InputSection *section : file->customSections) {
+      // Exclude COMDAT sections that are not selected for inclusion
+      if (section->discarded)
+        continue;
       StringRef name = section->getName();
       // These custom sections are known the linker and synthesized rather than
       // blindly copied.