[lld] [LLD][COFF] Support MinGW constructor and destructor lists on ARM64X (PR #127205)
Jacek Caban via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 14 04:00:02 PST 2025
https://github.com/cjacek created https://github.com/llvm/llvm-project/pull/127205
Split the chunks for EC and native views, inserting headers and tails for both.
>From 5acd1bc0f062b521aa795e2872e8c256f5185185 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Thu, 13 Feb 2025 22:05:22 +0100
Subject: [PATCH 1/2] [LLD][COFF] Split native and EC .CRT chunks on ARM64X
---
lld/COFF/Writer.cpp | 11 +++++++++
lld/COFF/Writer.h | 3 +++
lld/test/COFF/arm64x-crt-sec.s | 42 ++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
create mode 100644 lld/test/COFF/arm64x-crt-sec.s
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 678de915b6cdb..504558087c80d 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -403,6 +403,12 @@ void OutputSection::addContributingPartialSection(PartialSection *sec) {
contribSections.push_back(sec);
}
+void OutputSection::splitECChunks() {
+ llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {
+ return (a->getMachine() != ARM64) < (b->getMachine() != ARM64);
+ });
+}
+
// Check whether the target address S is in range from a relocation
// of type relType at address P.
bool Writer::isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin,
@@ -1156,6 +1162,11 @@ void Writer::createSections() {
sec->addContributingPartialSection(pSec);
}
+ if (ctx.hybridSymtab) {
+ if (OutputSection *sec = findSection(".CRT"))
+ sec->splitECChunks();
+ }
+
// Finally, move some output sections to the end.
auto sectionOrder = [&](const OutputSection *s) {
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file
diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h
index 9004bb310d073..7e458b766bae8 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -50,6 +50,9 @@ class OutputSection {
void writeHeaderTo(uint8_t *buf, bool isDebug);
void addContributingPartialSection(PartialSection *sec);
+ // Sort chunks to split native and EC sections on hybrid targets.
+ void splitECChunks();
+
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
diff --git a/lld/test/COFF/arm64x-crt-sec.s b/lld/test/COFF/arm64x-crt-sec.s
new file mode 100644
index 0000000000000..5be70a1845f12
--- /dev/null
+++ b/lld/test/COFF/arm64x-crt-sec.s
@@ -0,0 +1,42 @@
+// REQUIRES: aarch64, x86
+// RUN: split-file %s %t.dir && cd %t.dir
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows crt1-arm64.s -o crt1-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows crt2-arm64.s -o crt2-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows crt1-arm64ec.s -o crt1-arm64ec.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows crt2-amd64.s -o crt2-amd64.obj
+
+// Check that .CRT chunks are correctly sorted and that EC and native chunks are split.
+
+// RUN: lld-link -out:out.dll -machine:arm64x -dll -noentry crt1-arm64.obj crt2-arm64.obj crt1-arm64ec.obj crt2-amd64.obj
+// RUN: llvm-readobj --hex-dump=.CRT out.dll | FileCheck %s
+
+// RUN: lld-link -out:out2.dll -machine:arm64x -dll -noentry crt1-arm64.obj crt1-arm64ec.obj crt2-arm64.obj crt2-amd64.obj
+// RUN: llvm-readobj --hex-dump=.CRT out2.dll | FileCheck %s
+
+// RUN: lld-link -out:out3.dll -machine:arm64x -dll -noentry crt2-amd64.obj crt1-arm64ec.obj crt2-arm64.obj crt1-arm64.obj
+// RUN: llvm-readobj --hex-dump=.CRT out3.dll | FileCheck %s
+
+// CHECK: 0x180002000 01000000 00000000 02000000 00000000
+// CHECK-NEXT: 0x180002010 03000000 00000000 11000000 00000000
+// CHECK-NEXT: 0x180002020 12000000 00000000 13000000 00000000
+
+#--- crt1-arm64.s
+ .section .CRT$A,"dr"
+ .xword 1
+ .section .CRT$Z,"dr"
+ .xword 3
+
+#--- crt2-arm64.s
+ .section .CRT$B,"dr"
+ .xword 2
+
+#--- crt1-arm64ec.s
+ .section .CRT$A,"dr"
+ .xword 0x11
+ .section .CRT$Z,"dr"
+ .xword 0x13
+
+#--- crt2-amd64.s
+ .section .CRT$B,"dr"
+ .quad 0x12
>From 458417a10837445bd875f9c561e69ab71c6a1068 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Tue, 28 Jan 2025 00:09:55 +0100
Subject: [PATCH 2/2] [LLD][COFF] Support MinGW constructor and destructor
lists on ARM64X
Split the chunks for EC and native views, inserting headers and tails for both.
---
lld/COFF/Chunks.cpp | 8 +++-
lld/COFF/Chunks.h | 7 +--
lld/COFF/Writer.cpp | 37 +++++++++-------
lld/test/COFF/arm64x-ctors-sec.s | 76 ++++++++++++++++++++++++++++++++
4 files changed, 108 insertions(+), 20 deletions(-)
create mode 100644 lld/test/COFF/arm64x-ctors-sec.s
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index a01c69c709876..3494d1ba0ac02 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1070,16 +1070,20 @@ void MergeChunk::writeTo(uint8_t *buf) const {
}
// MinGW specific.
-size_t AbsolutePointerChunk::getSize() const { return ctx.config.wordsize; }
+size_t AbsolutePointerChunk::getSize() const {
+ return symtab.ctx.config.wordsize;
+}
void AbsolutePointerChunk::writeTo(uint8_t *buf) const {
- if (ctx.config.is64()) {
+ if (symtab.ctx.config.is64()) {
write64le(buf, value);
} else {
write32le(buf, value);
}
}
+MachineTypes AbsolutePointerChunk::getMachine() const { return symtab.machine; }
+
void ECExportThunkChunk::writeTo(uint8_t *buf) const {
memcpy(buf, ECExportThunkCode, sizeof(ECExportThunkCode));
write32le(buf + 10, target->getRVA() - rva - 14);
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index d6216efdd90bd..06e9aae0e6f6e 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -910,16 +910,17 @@ class PseudoRelocTableChunk : public NonSectionChunk {
// MinGW specific. A Chunk that contains one pointer-sized absolute value.
class AbsolutePointerChunk : public NonSectionChunk {
public:
- AbsolutePointerChunk(COFFLinkerContext &ctx, uint64_t value)
- : value(value), ctx(ctx) {
+ AbsolutePointerChunk(SymbolTable &symtab, uint64_t value)
+ : value(value), symtab(symtab) {
setAlignment(getSize());
}
size_t getSize() const override;
void writeTo(uint8_t *buf) const override;
+ MachineTypes getMachine() const override;
private:
uint64_t value;
- COFFLinkerContext &ctx;
+ SymbolTable &symtab;
};
// Return true if this file has the hotpatch flag set to true in the S_COMPILE3
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 504558087c80d..58727c1615769 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -2335,21 +2335,28 @@ void Writer::createRuntimePseudoRelocs() {
// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
// and __DTOR_LIST__ respectively.
void Writer::insertCtorDtorSymbols() {
- AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(ctx, -1);
- AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(ctx, 0);
- AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(ctx, -1);
- AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(ctx, 0);
- ctorsSec->insertChunkAtStart(ctorListHead);
- ctorsSec->addChunk(ctorListEnd);
- dtorsSec->insertChunkAtStart(dtorListHead);
- dtorsSec->addChunk(dtorListEnd);
-
- Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__");
- Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__");
- replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
- ctorListHead);
- replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
- dtorListHead);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(symtab, -1);
+ AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(symtab, 0);
+ AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(symtab, -1);
+ AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(symtab, 0);
+ ctorsSec->insertChunkAtStart(ctorListHead);
+ ctorsSec->addChunk(ctorListEnd);
+ dtorsSec->insertChunkAtStart(dtorListHead);
+ dtorsSec->addChunk(dtorListEnd);
+
+ Symbol *ctorListSym = symtab.findUnderscore("__CTOR_LIST__");
+ Symbol *dtorListSym = symtab.findUnderscore("__DTOR_LIST__");
+ replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
+ ctorListHead);
+ replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
+ dtorListHead);
+ });
+
+ if (ctx.hybridSymtab) {
+ ctorsSec->splitECChunks();
+ dtorsSec->splitECChunks();
+ }
}
// Handles /section options to allow users to overwrite
diff --git a/lld/test/COFF/arm64x-ctors-sec.s b/lld/test/COFF/arm64x-ctors-sec.s
new file mode 100644
index 0000000000000..283d5f045260d
--- /dev/null
+++ b/lld/test/COFF/arm64x-ctors-sec.s
@@ -0,0 +1,76 @@
+// REQUIRES: aarch64, x86
+// RUN: split-file %s %t.dir && cd %t.dir
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows ctor1-arm64.s -o ctor1-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows ctor2-arm64.s -o ctor2-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ctor1-arm64ec.s -o ctor1-arm64ec.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows ctor2-amd64.s -o ctor2-amd64.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows test.s -o test-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test.s -o test-arm64ec.obj
+
+// Check that .ctors and .dtors chunks are correctly sorted and that EC and native chunks are split.
+
+// RUN: lld-link -out:out.dll -machine:arm64x -lldmingw -dll -noentry test-arm64.obj test-arm64ec.obj \
+// RUN: ctor1-arm64.obj ctor2-arm64.obj ctor1-arm64ec.obj ctor2-amd64.obj
+// RUN: llvm-readobj --hex-dump=.rdata --hex-dump=.test out.dll | FileCheck %s
+
+// RUN: lld-link -out:out2.dll -machine:arm64x -lldmingw -dll -noentry test-arm64.obj test-arm64ec.obj \
+// RUN: ctor1-arm64ec.obj ctor2-amd64.obj ctor1-arm64.obj ctor2-arm64.obj
+// RUN: llvm-readobj --hex-dump=.rdata --hex-dump=.test out2.dll | FileCheck %s
+
+// RUN: lld-link -out:out3.dll -machine:arm64x -lldmingw -dll -noentry test-arm64.obj test-arm64ec.obj \
+// RUN: ctor2-arm64.obj ctor1-arm64ec.obj ctor2-amd64.obj ctor1-arm64.obj
+// RUN: llvm-readobj --hex-dump=.rdata --hex-dump=.test out3.dll | FileCheck %s
+
+// CHECK: Hex dump of section '.rdata':
+// CHECK-NEXT: 0x180001000 ffffffff ffffffff 01000000 00000000
+// CHECK-NEXT: 0x180001010 02000000 00000000 03000000 00000000
+// CHECK-NEXT: 0x180001020 00000000 00000000 ffffffff ffffffff
+// CHECK-NEXT: 0x180001030 11000000 00000000 12000000 00000000
+// CHECK-NEXT: 0x180001040 13000000 00000000 00000000 00000000
+// CHECK-NEXT: 0x180001050 ffffffff ffffffff 01010000 00000000
+// CHECK-NEXT: 0x180001060 02010000 00000000 03010000 00000000
+// CHECK-NEXT: 0x180001070 00000000 00000000 ffffffff ffffffff
+// CHECK-NEXT: 0x180001080 11010000 00000000 12010000 00000000
+// CHECK-NEXT: 0x180001090 13010000 00000000 00000000 00000000
+// CHECK-EMPTY:
+// CHECK-NEXT: Hex dump of section '.test':
+// CHECK-NEXT: 0x180003000 00100000 50100000 28100000 78100000
+
+#--- ctor1-arm64.s
+ .section .ctors.1,"drw"
+ .xword 1
+ .section .ctors.3,"drw"
+ .xword 3
+ .section .dtors.1,"drw"
+ .xword 0x101
+ .section .dtors.3,"drw"
+ .xword 0x103
+
+#--- ctor2-arm64.s
+ .section .ctors.2,"drw"
+ .xword 2
+ .section .dtors.2,"drw"
+ .xword 0x102
+
+#--- ctor1-arm64ec.s
+ .section .ctors.1,"drw"
+ .xword 0x11
+ .section .ctors.3,"drw"
+ .xword 0x13
+ .section .dtors.1,"drw"
+ .xword 0x111
+ .section .dtors.3,"drw"
+ .xword 0x113
+
+#--- ctor2-amd64.s
+ .section .ctors.2,"drw"
+ .quad 0x12
+ .section .dtors.2,"drw"
+ .quad 0x112
+
+#--- test.s
+ .section .test
+ .rva __CTOR_LIST__
+ .rva __DTOR_LIST__
+
More information about the llvm-commits
mailing list