Skip to content

Commit 73332d7

Browse files
committed
[lld][WebAssembly] Do not merge comdat data segments
When running in relocatable mode any input data segments that are part of a comdat group should not be merged with other segments of the same name. This is because the final linker needs to keep the separate so they can be included/excluded individually. Often this is not a problem since normally only one section with a given name `foo` ends up in the output object file. However, the problem occurs when one input contains `foo` which part of a comdat and another object contains a local symbol `foo` we were attempting to merge them. This behaviour matches (I believe) that of the ELF linker. See `LinkerScript.cpp:addInputSec`. Fixes: emscripten-core/emscripten#9726 Differential Revision: https://reviews.llvm.org/D101703
1 parent e38ccb7 commit 73332d7

File tree

4 files changed

+80
-16
lines changed

4 files changed

+80
-16
lines changed

lld/test/wasm/Inputs/comdat-data.s

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.globl foo
2+
.section .data.foo,"G",@,foo,comdat
3+
foo:
4+
.int32 42
5+
.int32 43
6+
.size foo, 8

lld/test/wasm/relocatable-comdat.s

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# RUN: llvm-mc -triple=wasm32 -filetype=obj %p/Inputs/comdat-data.s -o %t1.o
2+
# RUN: llvm-mc -triple=wasm32 -filetype=obj %s -o %t.o
3+
# RUN: wasm-ld --relocatable -o %t.wasm %t.o %t1.o
4+
# RUN: obj2yaml %t.wasm | FileCheck %s
5+
6+
7+
.globl _start
8+
.type _start,@function
9+
_start:
10+
.functype _start () -> ()
11+
i32.load foo
12+
end_function
13+
14+
15+
.section .data.foo,"",@
16+
foo:
17+
.int32 42
18+
.size foo, 4
19+
20+
# Verify that .data.foo in this file is not merged with comdat .data.foo
21+
# section in Inputs/comdat-data.s.
22+
23+
# CHECK: - Type: DATA
24+
# CHECK-NEXT: Segments:
25+
# CHECK-NEXT: - SectionOffset: 6
26+
# CHECK-NEXT: InitFlags: 0
27+
# CHECK-NEXT: Offset:
28+
# CHECK-NEXT: Opcode: I32_CONST
29+
# CHECK-NEXT: Value: 0
30+
# CHECK-NEXT: Content: 2A000000
31+
# CHECK-NEXT: - SectionOffset: 15
32+
# CHECK-NEXT: InitFlags: 0
33+
# CHECK-NEXT: Offset:
34+
# CHECK-NEXT: Opcode: I32_CONST
35+
# CHECK-NEXT: Value: 4
36+
# CHECK-NEXT: Content: 2A0000002B000000
37+
38+
# CHECK: SegmentInfo:
39+
# CHECK-NEXT: - Index: 0
40+
# CHECK-NEXT: Name: .data.foo
41+
# CHECK-NEXT: Alignment: 0
42+
# CHECK-NEXT: Flags: [ ]
43+
# CHECK-NEXT: - Index: 1
44+
# CHECK-NEXT: Name: .data.foo
45+
# CHECK-NEXT: Alignment: 0
46+
# CHECK-NEXT: Flags: [ ]

lld/wasm/Writer.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class Writer {
7777
void calculateCustomSections();
7878
void calculateTypes();
7979
void createOutputSegments();
80+
OutputSegment *createOutputSegment(StringRef name);
8081
void combineOutputSegments();
8182
void layoutMemory();
8283
void createHeader();
@@ -830,26 +831,37 @@ static StringRef getOutputDataSegmentName(StringRef name) {
830831
return name;
831832
}
832833

834+
OutputSegment *Writer::createOutputSegment(StringRef name) {
835+
LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
836+
OutputSegment *s = make<OutputSegment>(name);
837+
if (config->sharedMemory)
838+
s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
839+
// Exported memories are guaranteed to be zero-initialized, so no need
840+
// to emit data segments for bss sections.
841+
// TODO: consider initializing bss sections with memory.fill
842+
// instructions when memory is imported and bulk-memory is available.
843+
if (!config->importMemory && !config->relocatable && name.startswith(".bss"))
844+
s->isBss = true;
845+
segments.push_back(s);
846+
return s;
847+
}
848+
833849
void Writer::createOutputSegments() {
834850
for (ObjFile *file : symtab->objectFiles) {
835851
for (InputSegment *segment : file->segments) {
836852
if (!segment->live)
837853
continue;
838854
StringRef name = getOutputDataSegmentName(segment->getName());
839-
OutputSegment *&s = segmentMap[name];
840-
if (s == nullptr) {
841-
LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
842-
s = make<OutputSegment>(name);
843-
if (config->sharedMemory)
844-
s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
845-
// Exported memories are guaranteed to be zero-initialized, so no need
846-
// to emit data segments for bss sections.
847-
// TODO: consider initializing bss sections with memory.fill
848-
// instructions when memory is imported and bulk-memory is available.
849-
if (!config->importMemory && !config->relocatable &&
850-
name.startswith(".bss"))
851-
s->isBss = true;
852-
segments.push_back(s);
855+
OutputSegment *s = nullptr;
856+
// When running in relocatable mode we can't merge segments that are part
857+
// of comdat groups since the ultimate linker needs to be able exclude or
858+
// include them individually.
859+
if (config->relocatable && !segment->getComdatName().empty()) {
860+
s = createOutputSegment(name);
861+
} else {
862+
if (segmentMap.count(name) == 0)
863+
segmentMap[name] = createOutputSegment(name);
864+
s = segmentMap[name];
853865
}
854866
s->addInputSegment(segment);
855867
LLVM_DEBUG(dbgs() << "added data: " << name << ": " << s->size << "\n");

llvm/lib/Object/WasmObjectFile.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ using namespace object;
3939

4040
void WasmSymbol::print(raw_ostream &Out) const {
4141
Out << "Name=" << Info.Name
42-
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
43-
<< ", Flags=" << Info.Flags;
42+
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
43+
<< Twine::utohexstr(Info.Flags);
4444
if (!isTypeData()) {
4545
Out << ", ElemIndex=" << Info.ElementIndex;
4646
} else if (isDefined()) {

0 commit comments

Comments
 (0)