diff --git a/lld/test/wasm/Inputs/comdat1.s b/lld/test/wasm/Inputs/comdat1.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/Inputs/comdat1.s @@ -0,0 +1,12 @@ + .section .text.foo,"G",@,foo,comdat + .weak 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 --- /dev/null +++ b/lld/test/wasm/Inputs/comdat2.s @@ -0,0 +1,12 @@ + .section .text.foo,"G",@,foo,comdat + .weak 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 --- /dev/null +++ b/lld/test/wasm/comdat-sections.s @@ -0,0 +1,49 @@ +# 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 --no-gc-sections -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: - Type: CODE +# CHECK: Functions: +# CHECK: - Index: 0 +# CHECK: Locals: [] +# CHECK: Body: 0B +# CHECK: - Index: 1 +# CHECK: Locals: [] +# CHECK: Body: 1082808080000B + +# OOOOPS! we have 2 copies of foo. why? +# CHECK: - Index: 2 +# CHECK: Locals: [] +# CHECK: Body: 0F0B +# CHECK: - Index: 3 +# CHECK: Locals: [] +# CHECK: Body: 0F0B + +# 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: Name: .debug_foo +# CHECK: Payload: 010000007B00000000000000 +# CHECK: - Type: CUSTOM +# CHECK: Name: name +# CHECK: FunctionNames: +# CHECK: - Index: 0 +# CHECK: Name: __wasm_call_ctors +# CHECK: - Index: 1 +# CHECK: Name: _start +# CHECK: - Index: 2 +# CHECK: Name: foo +# CHECK: - Index: 3 +# CHECK: Name: foo diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -221,7 +221,7 @@ 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 data() const override { return section.Content; } diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -341,6 +341,12 @@ } } + ArrayRef 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 @@ assert(!dataSection); dataSection = §ion; } else if (section.Type == WASM_SEC_CUSTOM) { - customSections.emplace_back(make(section, this)); + auto *customSec = make(section, this); + customSec->discarded = isExcludedByComdat(customSec); + customSections.emplace_back(customSec); customSections.back()->setRelocations(section.Relocations); customSectionsByIndex[sectionIndex] = customSections.back(); } @@ -374,11 +382,6 @@ typeMap.resize(getWasmObj()->types().size()); typeIsUsed.resize(getWasmObj()->types().size(), false); - ArrayRef 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()) { @@ -427,9 +430,13 @@ } bool ObjFile::isExcludedByComdat(InputChunk *chunk) const { + llvm::errs() << "Checking " << chunk->getName() << "\n"; uint32_t c = chunk->getComdat(); if (c == UINT32_MAX) return false; + llvm::errs() << "InputChunk kind " << chunk->kind() << " name " + << chunk->getName() << " comdat " << c << " excluded " + << !keptComdats[c] << "\n"; return !keptComdats[c]; } @@ -487,6 +494,10 @@ 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(flags, section, this); } case WASM_SYMBOL_TYPE_EVENT: { diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -239,6 +239,7 @@ os.flush(); for (InputSection *section : inputSections) { + assert(!section->discarded); section->outputSec = this; section->outputOffset = payloadSize; payloadSize += section->getSize(); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -117,6 +117,9 @@ 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.