[lld] [lld][COFF] Extend merge to merge sections into partial sections (PR #194992)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 19:08:43 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-platform-windows
Author: Austin Hudson (realoriginal)
<details>
<summary>Changes</summary>
Extends the COFF `/merge` directive to permit merging section into a partial section and ordered appropriately.
Reasoning behind the feature is due to an equivalent linker script feature in GNU LD that allows a user to order COFF subsections like:
```
SECTIONS
{
.text ALIGN( 1 ) : ALIGN( 1 )
{
*( .text$A )
*( .text$B )
*( .rdata* )
*( .text$C )
}
}
```
Where .rdata will be placed within .text between the $B and $C partial section chunks. An equivalent with this patch would be `/merge:.rdata=.text$C` that would then place it between named section chunks `.text$B` / `.text$D`. I figured it made sense to place within createSection when its constructing the individual chunks while cloning the target sections characteristics while using the existing parameter without the additional parameter thats far too specific of a need.
---
Full diff: https://github.com/llvm/llvm-project/pull/194992.diff
2 Files Affected:
- (modified) lld/COFF/Writer.cpp (+17-2)
- (added) lld/test/COFF/merge-to-partial.test (+177)
``````````diff
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index a5e30e26b9e5b..57f41200e62d4 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1125,8 +1125,19 @@ void Writer::createSections() {
if (name.starts_with(".tls"))
tlsAlignment = std::max(tlsAlignment, c->getAlignment());
- PartialSection *pSec = createPartialSection(name,
- c->getOutputCharacteristics());
+ uint32_t outChars = c->getOutputCharacteristics();
+ StringRef from = getOutputSectionName(name);
+ auto i = ctx.config.merge.find(from);
+ if (i != ctx.config.merge.end() && i->second.contains('$')) {
+ // Set the name as a partial section chunk
+ name = saver().save(i->second + name.substr(from.size()));
+
+ // Use the existing sections characateristics that were targeting
+ if (OutputSection *targetSec = findSection(getOutputSectionName(name)))
+ outChars = targetSec->header.Characteristics;
+ }
+
+ PartialSection *pSec = createPartialSection(name, outChars);
pSec->chunks.push_back(c);
}
@@ -1655,6 +1666,10 @@ void Writer::createSymbolAndStringTable() {
}
void Writer::mergeSection(const std::map<StringRef, StringRef>::value_type &p) {
+ // This was a rename to a partial section chunk, so skip it. Handled in createSections()
+ if (p.second.contains('$'))
+ return;
+
StringRef toName = p.second;
if (p.first == toName)
return;
diff --git a/lld/test/COFF/merge-to-partial.test b/lld/test/COFF/merge-to-partial.test
new file mode 100644
index 0000000000000..f389de4f1e242
--- /dev/null
+++ b/lld/test/COFF/merge-to-partial.test
@@ -0,0 +1,177 @@
+# RUN: yaml2obj %s -o %t.obj
+
+# RUN: lld-link /out:%t1.exe /entry:main /subsystem:console \
+# RUN: '/merge:.section_2=.text$A' '/merge:.section_4=.text$B' \
+# RUN: '/merge:.section_1=.text$C' '/merge:.section_3=.text$D' \
+# RUN: '/merge:.section_5=.text$E' '/merge:.section_6=.text$F' %t.obj
+# RUN: llvm-readobj --sections %t1.exe | FileCheck --check-prefix=SECTIONS1 %s
+# RUN: llvm-readobj --hex-dump=.text %t1.exe | FileCheck --check-prefix=TEXT1 %s
+
+# RUN: lld-link /out:%t2.exe /entry:main /subsystem:console \
+# RUN: '/merge:.section_4=.text$A' '/merge:.section_2=.text$B' \
+# RUN: '/merge:.section_6=.text$C' '/merge:.section_1=.text$D' \
+# RUN: '/merge:.section_5=.text$E' '/merge:.section_3=.text$F' %t.obj
+# RUN: llvm-readobj --sections %t2.exe | FileCheck --check-prefix=SECTIONS2 %s
+# RUN: llvm-readobj --hex-dump=.text %t2.exe | FileCheck --check-prefix=TEXT2 %s
+
+# RUN: lld-link /out:%t3.exe /entry:main /subsystem:console \
+# RUN: '/merge:.section_2=.text$A' '/merge:.section_4=.text$B' \
+# RUN: '/merge:.section_6=.text$B' '/merge:.section_1=.text$C' \
+# RUN: '/merge:.section_3=.text$D' '/merge:.section_5=.text$E' %t.obj
+# RUN: llvm-readobj --sections %t3.exe | FileCheck --check-prefix=SECTIONS3 %s
+# RUN: llvm-readobj --hex-dump=.text %t3.exe | FileCheck --check-prefix=TEXT3 %s
+
+# SECTIONS1: Name: .text
+# SECTIONS1-NOT: Name: .text$B
+# SECTIONS1-NOT: Name: .section_1
+# SECTIONS1-NOT: Name: .section_2
+# SECTIONS1-NOT: Name: .section_3
+# SECTIONS1-NOT: Name: .section_4
+# SECTIONS1-NOT: Name: .section_5
+# SECTIONS1-NOT: Name: .section_6
+# TEXT1: aaaaaaaa
+# TEXT1: bbbbbbbb
+# TEXT1: cccccccc
+# TEXT1: dddddddd
+# TEXT1: eeeeeeee
+# TEXT1: ffffffff
+
+# SECTIONS2: Name: .text
+# SECTIONS2-NOT: Name: .text$B
+# SECTIONS2-NOT: Name: .section_1
+# SECTIONS2-NOT: Name: .section_2
+# SECTIONS2-NOT: Name: .section_3
+# SECTIONS2-NOT: Name: .section_4
+# SECTIONS2-NOT: Name: .section_5
+# SECTIONS2-NOT: Name: .section_6
+# TEXT2: bbbbbbbb
+# TEXT2: aaaaaaaa
+# TEXT2: ffffffff
+# TEXT2: cccccccc
+# TEXT2: eeeeeeee
+# TEXT2: dddddddd
+
+# SECTIONS3: Name: .text
+# SECTIONS3-NOT: Name: .text$B
+# SECTIONS3-NOT: Name: .section_1
+# SECTIONS3-NOT: Name: .section_2
+# SECTIONS3-NOT: Name: .section_3
+# SECTIONS3-NOT: Name: .section_4
+# SECTIONS3-NOT: Name: .section_5
+# SECTIONS3-NOT: Name: .section_6
+# TEXT3: aaaaaaaa
+# TEXT3: bbbbbbbb
+# TEXT3: ffffffff
+# TEXT3: cccccccc
+# TEXT3: dddddddd
+# TEXT3: eeeeeeee
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .section_1
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: CCCCCCCC
+ - Name: .section_2
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: AAAAAAAA
+ - Name: .section_3
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: DDDDDDDD
+ - Name: .section_4
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: BBBBBBBB
+ - Name: .section_5
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: EEEEEEEE
+ - Name: .section_6
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: FFFFFFFF
+symbols:
+ - Name: .section_1
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .section_2
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .section_3
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .section_4
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .section_5
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .section_6
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/194992
More information about the llvm-commits
mailing list