Skip to content

Commit 48dcc96

Browse files
committed
[LLD][COFF] Ensure .bss is merged at the end of a section.
Because it is full of zeros, it is expected that as much of it as possible is elided from the actual image, and that cannot happen if there is initialized data in the section after it.
1 parent 0547e84 commit 48dcc96

File tree

2 files changed

+126
-21
lines changed

2 files changed

+126
-21
lines changed

lld/COFF/Writer.cpp

+34-21
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class Writer {
215215
void appendImportThunks();
216216
void locateImportTables();
217217
void createExportTable();
218+
void mergeSection(const std::map<StringRef, StringRef>::value_type &p);
218219
void mergeSections();
219220
void sortECChunks();
220221
void appendECImportTables();
@@ -1566,6 +1567,30 @@ void Writer::createSymbolAndStringTable() {
15661567
fileSize = alignTo(fileOff, ctx.config.fileAlign);
15671568
}
15681569

1570+
void Writer::mergeSection(const std::map<StringRef, StringRef>::value_type &p) {
1571+
StringRef toName = p.second;
1572+
if (p.first == toName)
1573+
return;
1574+
StringSet<> names;
1575+
while (true) {
1576+
if (!names.insert(toName).second)
1577+
Fatal(ctx) << "/merge: cycle found for section '" << p.first << "'";
1578+
auto i = ctx.config.merge.find(toName);
1579+
if (i == ctx.config.merge.end())
1580+
break;
1581+
toName = i->second;
1582+
}
1583+
OutputSection *from = findSection(p.first);
1584+
OutputSection *to = findSection(toName);
1585+
if (!from)
1586+
return;
1587+
if (!to) {
1588+
from->name = toName;
1589+
return;
1590+
}
1591+
to->merge(from);
1592+
}
1593+
15691594
void Writer::mergeSections() {
15701595
llvm::TimeTraceScope timeScope("Merge sections");
15711596
if (!pdataSec->chunks.empty()) {
@@ -1594,28 +1619,16 @@ void Writer::mergeSections() {
15941619
}
15951620

15961621
for (auto &p : ctx.config.merge) {
1597-
StringRef toName = p.second;
1598-
if (p.first == toName)
1599-
continue;
1600-
StringSet<> names;
1601-
while (true) {
1602-
if (!names.insert(toName).second)
1603-
Fatal(ctx) << "/merge: cycle found for section '" << p.first << "'";
1604-
auto i = ctx.config.merge.find(toName);
1605-
if (i == ctx.config.merge.end())
1606-
break;
1607-
toName = i->second;
1608-
}
1609-
OutputSection *from = findSection(p.first);
1610-
OutputSection *to = findSection(toName);
1611-
if (!from)
1612-
continue;
1613-
if (!to) {
1614-
from->name = toName;
1615-
continue;
1616-
}
1617-
to->merge(from);
1622+
if (p.first != ".bss")
1623+
mergeSection(p);
16181624
}
1625+
1626+
// Because .bss contains all zeros, it should be merged at the end of
1627+
// whatever section it is being merged into (usually .data) so that the image
1628+
// need not actually contain all of the zeros.
1629+
auto it = ctx.config.merge.find(".bss");
1630+
if (it != ctx.config.merge.end())
1631+
mergeSection(*it);
16191632
}
16201633

16211634
// EC targets may have chunks of various architectures mixed together at this

lld/test/COFF/merge-data-bss.test

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# RUN: yaml2obj %s -o %t.obj
2+
# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
3+
# RUN: /merge:.other=.data %t.obj /debug
4+
# RUN: llvm-readobj --sections %t.exe | FileCheck %s
5+
6+
# CHECK: Name: .data
7+
# CHECK-NEXT: VirtualSize: 0x2018
8+
# CHECK-NEXT: VirtualAddress: 0x3000
9+
# CHECK-NEXT: RawDataSize: 512
10+
# CHECK-NOT: Name: .other
11+
12+
--- !COFF
13+
header:
14+
Machine: IMAGE_FILE_MACHINE_AMD64
15+
Characteristics: [ ]
16+
sections:
17+
- Name: .text
18+
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
19+
Alignment: 4
20+
SectionData: '90'
21+
SizeOfRawData: 1
22+
- Name: .data
23+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
24+
Alignment: 4
25+
SectionData: '010000000000000002'
26+
SizeOfRawData: 9
27+
- Name: .bss
28+
Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
29+
Alignment: 4
30+
SectionData: ''
31+
SizeOfRawData: 8192
32+
- Name: .other
33+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
34+
Alignment: 4
35+
SectionData: '030000000000000004'
36+
SizeOfRawData: 9
37+
symbols:
38+
- Name: .text
39+
Value: 0
40+
SectionNumber: 1
41+
SimpleType: IMAGE_SYM_TYPE_NULL
42+
ComplexType: IMAGE_SYM_DTYPE_NULL
43+
StorageClass: IMAGE_SYM_CLASS_STATIC
44+
SectionDefinition:
45+
Length: 1
46+
NumberOfRelocations: 0
47+
NumberOfLinenumbers: 0
48+
CheckSum: 4027552580
49+
Number: 1
50+
- Name: .data
51+
Value: 0
52+
SectionNumber: 2
53+
SimpleType: IMAGE_SYM_TYPE_NULL
54+
ComplexType: IMAGE_SYM_DTYPE_NULL
55+
StorageClass: IMAGE_SYM_CLASS_STATIC
56+
SectionDefinition:
57+
Length: 9
58+
NumberOfRelocations: 0
59+
NumberOfLinenumbers: 0
60+
CheckSum: 4185224559
61+
Number: 2
62+
- Name: .bss
63+
Value: 0
64+
SectionNumber: 3
65+
SimpleType: IMAGE_SYM_TYPE_NULL
66+
ComplexType: IMAGE_SYM_DTYPE_NULL
67+
StorageClass: IMAGE_SYM_CLASS_STATIC
68+
SectionDefinition:
69+
Length: 8192
70+
NumberOfRelocations: 0
71+
NumberOfLinenumbers: 0
72+
CheckSum: 0
73+
Number: 3
74+
- Name: .other
75+
Value: 0
76+
SectionNumber: 4
77+
SimpleType: IMAGE_SYM_TYPE_NULL
78+
ComplexType: IMAGE_SYM_DTYPE_NULL
79+
StorageClass: IMAGE_SYM_CLASS_STATIC
80+
SectionDefinition:
81+
Length: 9
82+
NumberOfRelocations: 0
83+
NumberOfLinenumbers: 0
84+
CheckSum: 1054931164
85+
Number: 4
86+
- Name: main
87+
Value: 0
88+
SectionNumber: 1
89+
SimpleType: IMAGE_SYM_TYPE_NULL
90+
ComplexType: IMAGE_SYM_DTYPE_NULL
91+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
92+
...

0 commit comments

Comments
 (0)