aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Caban <jacek@codeweavers.com>2025-02-17 20:03:32 +0100
committerGitHub <noreply@github.com>2025-02-17 20:03:32 +0100
commit15944056aa5c1ab2c777dd2e3b4f19b8a1f1403d (patch)
tree8970613605868f7cd5d992eb9f1e86f2c6a85ad2
parent0d2722c20d75b237524dd4ec87a1d3da707ec96e (diff)
downloadllvm-15944056aa5c1ab2c777dd2e3b4f19b8a1f1403d.zip
llvm-15944056aa5c1ab2c777dd2e3b4f19b8a1f1403d.tar.gz
llvm-15944056aa5c1ab2c777dd2e3b4f19b8a1f1403d.tar.bz2
[LLD][COFF] Split native and EC .CRT chunks on ARM64X (#127203)
-rw-r--r--lld/COFF/Writer.cpp11
-rw-r--r--lld/COFF/Writer.h3
-rw-r--r--lld/test/COFF/arm64x-crt-sec.s42
3 files changed, 56 insertions, 0 deletions
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 678de91..5045580 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 9004bb3..7e458b7 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -50,6 +50,9 @@ public:
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 0000000..5be70a1
--- /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