Skip to content

Commit 0b01b96

Browse files
[LLD][COFF] Deduplicate common chunks when linking COFF files. (#162553)
This fixes [issue 162148](#162148). Common symbols are intended to have only a single version of the data present in the final executable. The MSVC linker is able to successfully deduplicate these chunks. If you have an application with a large number of translation units with a large block of common data (this is possible, for example, with Fortran code), then failing to deduplicate these chunks can make the data size so large that the resulting executable fails to load. The logic in this patch doesn't catch all of the potential cases for deduplication, but it should catch the most common ones.
1 parent 251edd1 commit 0b01b96

File tree

5 files changed

+48
-1
lines changed

5 files changed

+48
-1
lines changed

lld/COFF/Chunks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ uint32_t SectionChunk::getSectionNumber() const {
777777
return s.getIndex() + 1;
778778
}
779779

780-
CommonChunk::CommonChunk(const COFFSymbolRef s) : sym(s) {
780+
CommonChunk::CommonChunk(const COFFSymbolRef s) : live(false), sym(s) {
781781
// The value of a common symbol is its size. Align all common symbols smaller
782782
// than 32 bytes naturally, i.e. round the size up to the next power of two.
783783
// This is what MSVC link.exe does.

lld/COFF/Chunks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ class CommonChunk : public NonSectionChunk {
522522
uint32_t getOutputCharacteristics() const override;
523523
StringRef getSectionName() const override { return ".bss"; }
524524

525+
bool live;
526+
525527
private:
526528
const COFFSymbolRef sym;
527529
};

lld/COFF/Symbols.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ class DefinedCommon : public DefinedCOFF {
236236
CommonChunk *c = nullptr)
237237
: DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {
238238
this->isExternal = true;
239+
if (c)
240+
c->live = true;
239241
}
240242

241243
static bool classof(const Symbol *s) {

lld/COFF/Writer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,10 @@ void Writer::createSections() {
11141114
sc->printDiscardedMessage();
11151115
continue;
11161116
}
1117+
if (auto *cc = dyn_cast<CommonChunk>(c)) {
1118+
if (!cc->live)
1119+
continue;
1120+
}
11171121
StringRef name = c->getSectionName();
11181122
if (shouldStripSectionSuffix(sc, name, ctx.config.mingw))
11191123
name = name.split('$').first;

lld/test/COFF/common-dedup.ll

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; REQUIRES: x86
2+
; RUN: rm -rf %t.dir
3+
; RUN: split-file %s %t.dir
4+
; RUN: llc %t.dir/t1.ll -o %t.dir/t1.obj --filetype=obj
5+
; RUN: llc %t.dir/t2.ll -o %t.dir/t2.obj --filetype=obj
6+
; RUN: lld-link %t.dir/t1.obj %t.dir/t2.obj -entry:main -out:%t.dir/out.exe
7+
; RUN: llvm-readobj --section-headers %t.dir/out.exe | FileCheck %s
8+
9+
; Make sure that the data section contains just one copy of @a, not two.
10+
; CHECK: Name: .data
11+
; CHECK-NEXT: VirtualSize: 0x1000
12+
13+
;--- t1.ll
14+
target triple = "x86_64-pc-windows-msvc"
15+
@a = common global [4096 x i8] zeroinitializer
16+
17+
define i32 @usea() {
18+
%ref_common = load i32, ptr @a
19+
ret i32 %ref_common
20+
}
21+
22+
;--- t2.ll
23+
target triple = "x86_64-pc-windows-msvc"
24+
@a = common global [4096 x i8] zeroinitializer
25+
26+
define i32 @useb() {
27+
%ref_common = load i32, ptr @a
28+
ret i32 %ref_common
29+
}
30+
31+
declare i32 @usea()
32+
33+
define dso_local i32 @main() local_unnamed_addr {
34+
entry:
35+
%a = tail call i32 @usea()
36+
%b = tail call i32 @useb()
37+
%add = add nsw i32 %a, %b
38+
ret i32 %add
39+
}

0 commit comments

Comments
 (0)