[lld] ELF: Introduce --shuffle-padding option. (PR #117653)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 27 16:07:35 PST 2024
https://github.com/pcc updated https://github.com/llvm/llvm-project/pull/117653
>From 75ad826539205c52e1d9502938bb814ce914853b Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter at pcc.me.uk>
Date: Mon, 25 Nov 2024 16:43:33 -0800
Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
=?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.6-beta.1
---
lld/ELF/Config.h | 1 +
lld/ELF/Driver.cpp | 2 ++
lld/ELF/Options.td | 3 +++
lld/ELF/OutputSections.h | 4 ++--
lld/ELF/SyntheticSections.cpp | 15 +++++++++++++++
lld/ELF/SyntheticSections.h | 9 +++++++++
lld/ELF/Writer.cpp | 34 ++++++++++++++++++++++++++++++++++
lld/docs/ld.lld.1 | 9 +++++++++
lld/test/ELF/shuffle-padding.s | 29 +++++++++++++++++++++++++++++
9 files changed, 104 insertions(+), 2 deletions(-)
create mode 100644 lld/test/ELF/shuffle-padding.s
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index a2836733c2715e..ed6bce405d1664 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -329,6 +329,7 @@ struct Config {
bool relrPackDynRelocs = false;
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
+ std::optional<uint64_t> shufflePadding;
bool singleRoRx;
bool shared;
bool symbolic;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index bc4b967ccbbbb4..d8bcbe4a2d19d8 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1410,6 +1410,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ctx.arg.searchPaths = args::getStrings(args, OPT_library_path);
ctx.arg.sectionStartMap = getSectionStartMap(ctx, args);
ctx.arg.shared = args.hasArg(OPT_shared);
+ if (args.hasArg(OPT_shuffle_padding))
+ ctx.arg.shufflePadding = args::getInteger(args, OPT_shuffle_padding, 0);
ctx.arg.singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true);
ctx.arg.soName = args.getLastArgValue(OPT_soname);
ctx.arg.sortSection = getSortSection(ctx, args);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index ebe77204264210..44ac0ee43a8502 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -434,6 +434,9 @@ defm section_start: Eq<"section-start", "Set address of section">,
def shared: F<"shared">, HelpText<"Build a shared object">;
+def shuffle_padding: JJ<"shuffle-padding=">,
+ HelpText<"Randomly insert padding between input sections using given seed">;
+
defm soname: Eq<"soname", "Set DT_SONAME">;
defm sort_section:
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 67191392d1dbe7..3ab36a21ce488d 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -124,14 +124,14 @@ class OutputSection final : public SectionBase {
void sortInitFini();
void sortCtorsDtors();
+ std::array<uint8_t, 4> getFiller(Ctx &);
+
// Used for implementation of --compress-debug-sections and
// --compress-sections.
CompressedData compressed;
private:
SmallVector<InputSection *, 0> storage;
-
- std::array<uint8_t, 4> getFiller(Ctx &);
};
struct OutputDesc final : SectionCommand {
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 21fe2a25fa1bd2..70eca0e58036e0 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2753,6 +2753,21 @@ RelroPaddingSection::RelroPaddingSection(Ctx &ctx)
: SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE,
1) {}
+ShufflePaddingSection::ShufflePaddingSection(Ctx &ctx, uint64_t size,
+ OutputSection *parent)
+ : SyntheticSection(ctx, ".shuffle_padding", SHF_ALLOC, SHT_PROGBITS, 1),
+ size(size) {
+ this->parent = parent;
+}
+
+void ShufflePaddingSection::writeTo(uint8_t *buf) {
+ std::array<uint8_t, 4> filler = getParent()->getFiller(ctx);
+ uint8_t *end = buf + size;
+ for (; buf + 4 <= end; buf += 4)
+ memcpy(buf, &filler[0], 4);
+ memcpy(buf, &filler[0], end - buf);
+}
+
// The string hash function for .gdb_index.
static uint32_t computeGdbHash(StringRef s) {
uint32_t h = 0;
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 4b643e86335510..177a0337607da8 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -796,6 +796,15 @@ class RelroPaddingSection final : public SyntheticSection {
void writeTo(uint8_t *buf) override {}
};
+class ShufflePaddingSection final : public SyntheticSection {
+ uint64_t size;
+
+public:
+ ShufflePaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent);
+ size_t getSize() const override { return size; }
+ void writeTo(uint8_t *buf) override;
+};
+
// Used by the merged DWARF32 .debug_names (a per-module index). If we
// move to DWARF64, most of this data will need to be re-sized.
class DebugNamesBaseSection : public SyntheticSection {
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a7fbdc07907044..3c1ab3234801d9 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1444,6 +1444,37 @@ static void finalizeSynthetic(Ctx &ctx, SyntheticSection *sec) {
}
}
+static bool canInsertPadding(OutputSection *sec) {
+ StringRef s = sec->name;
+ return s == ".bss" || s == ".data" || s == ".data.rel.ro" ||
+ s == ".rodata" || s.starts_with(".text");
+}
+
+static void shufflePadding(Ctx &ctx) {
+ std::mt19937 g(*ctx.arg.shufflePadding);
+ PhdrEntry *curPtLoad = nullptr;
+ for (OutputSection *os : ctx.outputSections) {
+ if (!canInsertPadding(os))
+ continue;
+ for (SectionCommand *bc : os->commands) {
+ if (auto *isd = dyn_cast<InputSectionDescription>(bc)) {
+ SmallVector<InputSection *, 0> tmp;
+ if (os->ptLoad != curPtLoad) {
+ tmp.push_back(
+ make<ShufflePaddingSection>(ctx, g() % ctx.arg.maxPageSize, os));
+ curPtLoad = os->ptLoad;
+ }
+ for (InputSection *isec : isd->sections) {
+ if (g() < (1<<28))
+ tmp.push_back(make<ShufflePaddingSection>(ctx, isec->addralign, os));
+ tmp.push_back(isec);
+ }
+ isd->sections = std::move(tmp);
+ }
+ }
+ }
+}
+
// We need to generate and finalize the content that depends on the address of
// InputSections. As the generation of the content may also alter InputSection
// addresses we must converge to a fixed point. We do that here. See the comment
@@ -1470,6 +1501,9 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
if (ctx.arg.emachine == EM_HEXAGON)
hexagonTLSSymbolUpdate(ctx);
+ if (ctx.arg.shufflePadding)
+ shufflePadding(ctx);
+
uint32_t pass = 0, assignPasses = 0;
for (;;) {
bool changed = ctx.target->needsThunks
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index b22cb362837715..5d3d4164622166 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -577,6 +577,15 @@ were concatenated in the order they appeared on the command line.
Set address of section.
.It Fl -shared , Fl -Bsharable
Build a shared object.
+.It Fl -shuffle-padding Ns = Ns Ar seed
+Randomly insert padding between input sections using the given seed.
+Padding is inserted into output sections with names matching the following patterns:
+.Cm .bss ,
+.Cm .data ,
+.Cm .data.rel.ro ,
+.Cm .rodata
+and
+.Cm .text* .
.It Fl -shuffle-sections Ns = Ns Ar seed
Shuffle matched sections using the given seed before mapping them to the output sections.
If -1, reverse the section order. If 0, use a random seed.
diff --git a/lld/test/ELF/shuffle-padding.s b/lld/test/ELF/shuffle-padding.s
new file mode 100644
index 00000000000000..f816100ffba1be
--- /dev/null
+++ b/lld/test/ELF/shuffle-padding.s
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: ld.lld %t.o -o %t.out
+# RUN: llvm-readelf -x .rodata %t.out | FileCheck %s
+# CHECK: Hex dump of section '.rodata':
+# CHECK-NEXT: 0x00201120 010203
+
+## --shuffle-padding= inserts segment offset padding and pre-section padding.
+# RUN: ld.lld --shuffle-padding=1 %t.o -o %t.out
+# RUN: llvm-readelf -x .rodata %t.out | FileCheck --check-prefix=PAD1 %s
+# PAD1: Hex dump of section '.rodata':
+# PAD1-NEXT: 0x00201548 0102cc03
+
+## Size of segment offset padding and location of pre-section padding is
+## dependent on the seed.
+# RUN: ld.lld --shuffle-padding=2 %t.o -o %t.out
+# RUN: llvm-readelf -x .rodata %t.out | FileCheck --check-prefix=PAD2 %s
+# PAD2: Hex dump of section '.rodata':
+# PAD2-NEXT: 0x00201dc8 cc010203
+
+.section .rodata.a,"ax"
+.byte 1
+
+.section .rodata.b,"ax"
+.byte 2
+
+.section .rodata.c,"ax"
+.byte 3
>From c420199d1ce7b6e065924aabb4f1a3edc0b45d14 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter at pcc.me.uk>
Date: Mon, 25 Nov 2024 16:51:54 -0800
Subject: [PATCH 2/3] format
Created using spr 1.3.6-beta.1
---
lld/ELF/Writer.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 3c1ab3234801d9..7591b5c0ff24d2 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1445,9 +1445,9 @@ static void finalizeSynthetic(Ctx &ctx, SyntheticSection *sec) {
}
static bool canInsertPadding(OutputSection *sec) {
- StringRef s = sec->name;
- return s == ".bss" || s == ".data" || s == ".data.rel.ro" ||
- s == ".rodata" || s.starts_with(".text");
+ StringRef s = sec->name;
+ return s == ".bss" || s == ".data" || s == ".data.rel.ro" || s == ".rodata" ||
+ s.starts_with(".text");
}
static void shufflePadding(Ctx &ctx) {
@@ -1465,8 +1465,9 @@ static void shufflePadding(Ctx &ctx) {
curPtLoad = os->ptLoad;
}
for (InputSection *isec : isd->sections) {
- if (g() < (1<<28))
- tmp.push_back(make<ShufflePaddingSection>(ctx, isec->addralign, os));
+ if (g() < (1 << 28))
+ tmp.push_back(
+ make<ShufflePaddingSection>(ctx, isec->addralign, os));
tmp.push_back(isec);
}
isd->sections = std::move(tmp);
>From 667e7bad3979d6e527f63e6ee3e9803073e0c6ed Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <peter at pcc.me.uk>
Date: Wed, 27 Nov 2024 16:07:21 -0800
Subject: [PATCH 3/3] Add tests
Created using spr 1.3.6-beta.1
---
lld/test/ELF/shuffle-padding-bss.s | 23 ++++++++++++
lld/test/ELF/shuffle-padding-data.s | 36 +++++++++++++++++++
...fle-padding.s => shuffle-padding-rodata.s} | 19 ++++++----
lld/test/ELF/shuffle-padding-text.s | 26 ++++++++++++++
4 files changed, 98 insertions(+), 6 deletions(-)
create mode 100644 lld/test/ELF/shuffle-padding-bss.s
create mode 100644 lld/test/ELF/shuffle-padding-data.s
rename lld/test/ELF/{shuffle-padding.s => shuffle-padding-rodata.s} (62%)
create mode 100644 lld/test/ELF/shuffle-padding-text.s
diff --git a/lld/test/ELF/shuffle-padding-bss.s b/lld/test/ELF/shuffle-padding-bss.s
new file mode 100644
index 00000000000000..f56916785fb791
--- /dev/null
+++ b/lld/test/ELF/shuffle-padding-bss.s
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+## --shuffle-padding= inserts segment offset padding and pre-section padding,
+## and does not affect .bss flags.
+# RUN: ld.lld --shuffle-padding=1 %t.o -o %t.out
+# RUN: llvm-readelf -sS %t.out | FileCheck --check-prefix=HEADER %s
+# HEADER: .bss NOBITS 0000000000202580 000580 000f90 00 WA 0 0 1
+# HEADER: 1: 000000000020350c 0 NOTYPE LOCAL DEFAULT 2 a
+# HEADER: 2: 000000000020350e 0 NOTYPE LOCAL DEFAULT 2 b
+# HEADER: 3: 000000000020350f 0 NOTYPE LOCAL DEFAULT 2 c
+
+.section .bss.a,"a", at nobits
+a:
+.zero 1
+
+.section .bss.b,"a", at nobits
+b:
+.zero 1
+
+.section .bss.c,"a", at nobits
+c:
+.zero 1
diff --git a/lld/test/ELF/shuffle-padding-data.s b/lld/test/ELF/shuffle-padding-data.s
new file mode 100644
index 00000000000000..431c79214dd791
--- /dev/null
+++ b/lld/test/ELF/shuffle-padding-data.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: ld.lld %t.o -o %t.out
+# RUN: llvm-readelf -x .data %t.out | FileCheck %s
+# CHECK: Hex dump of section '.data':
+# CHECK-NEXT: 0x00202158 010203
+
+## --shuffle-padding= inserts segment offset padding and pre-section padding.
+# RUN: ld.lld --shuffle-padding=1 %t.o -o %t.out
+# RUN: llvm-readelf -x .data %t.out | FileCheck --check-prefix=PAD1 %s
+# PAD1: Hex dump of section '.data':
+# PAD1: 0x00203500 00000000 00000000 00000000 01000203
+
+## --shuffle-padding= does not affect .rodata flags.
+# RUN: llvm-readelf -S %t.out | FileCheck --check-prefix=HEADER %s
+# HEADER: .data PROGBITS 0000000000202580 000580 000f90 00 WA 0 0 1
+
+## Size of segment offset padding and location of pre-section padding is
+## dependent on the seed.
+# RUN: ld.lld --shuffle-padding=2 %t.o -o %t.out
+# RUN: llvm-readelf -x .data %t.out | FileCheck --check-prefix=PAD2 %s
+# PAD2: Hex dump of section '.data':
+# PAD2: 0x002037e0 00000000 00000000 00000000 00010203
+
+.section .data.a,"aw", at progbits
+a:
+.byte 1
+
+.section .data.b,"aw", at progbits
+b:
+.byte 2
+
+.section .data.c,"aw", at progbits
+c:
+.byte 3
diff --git a/lld/test/ELF/shuffle-padding.s b/lld/test/ELF/shuffle-padding-rodata.s
similarity index 62%
rename from lld/test/ELF/shuffle-padding.s
rename to lld/test/ELF/shuffle-padding-rodata.s
index f816100ffba1be..35f18fcc12c10c 100644
--- a/lld/test/ELF/shuffle-padding.s
+++ b/lld/test/ELF/shuffle-padding-rodata.s
@@ -4,26 +4,33 @@
# RUN: ld.lld %t.o -o %t.out
# RUN: llvm-readelf -x .rodata %t.out | FileCheck %s
# CHECK: Hex dump of section '.rodata':
-# CHECK-NEXT: 0x00201120 010203
+# CHECK-NEXT: 0x00200120 010203
## --shuffle-padding= inserts segment offset padding and pre-section padding.
# RUN: ld.lld --shuffle-padding=1 %t.o -o %t.out
# RUN: llvm-readelf -x .rodata %t.out | FileCheck --check-prefix=PAD1 %s
# PAD1: Hex dump of section '.rodata':
-# PAD1-NEXT: 0x00201548 0102cc03
+# PAD1: 0x00200540 00000000 00010203
+
+## --shuffle-padding= does not affect .rodata flags.
+# RUN: llvm-readelf -S %t.out | FileCheck --check-prefix=HEADER %s
+# HEADER: .rodata PROGBITS 0000000000200120 000120 000428 00 A 0 0 1
## Size of segment offset padding and location of pre-section padding is
## dependent on the seed.
# RUN: ld.lld --shuffle-padding=2 %t.o -o %t.out
# RUN: llvm-readelf -x .rodata %t.out | FileCheck --check-prefix=PAD2 %s
# PAD2: Hex dump of section '.rodata':
-# PAD2-NEXT: 0x00201dc8 cc010203
+# PAD2: 0x00200dc0 00000000 00000000 01000203
-.section .rodata.a,"ax"
+.section .rodata.a,"a", at progbits
+a:
.byte 1
-.section .rodata.b,"ax"
+.section .rodata.b,"a", at progbits
+b:
.byte 2
-.section .rodata.c,"ax"
+.section .rodata.c,"a", at progbits
+c:
.byte 3
diff --git a/lld/test/ELF/shuffle-padding-text.s b/lld/test/ELF/shuffle-padding-text.s
new file mode 100644
index 00000000000000..5f9cafe49fa289
--- /dev/null
+++ b/lld/test/ELF/shuffle-padding-text.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: ld.lld %t.o -o %t.out
+# RUN: llvm-readelf -x .text %t.out | FileCheck %s
+# CHECK: Hex dump of section '.text':
+# CHECK-NEXT: 0x00201120 010203
+
+## --shuffle-padding= inserts segment offset padding and pre-section padding.
+# RUN: ld.lld --shuffle-padding=1 %t.o -o %t.out
+# RUN: llvm-readelf -x .text %t.out | FileCheck --check-prefix=PAD1 %s
+# PAD1: Hex dump of section '.text':
+# PAD1: 0x00201540 cccccccc cccccccc 0102cc03
+
+## --shuffle-padding= does not affect .text flags.
+# RUN: llvm-readelf -S %t.out | FileCheck --check-prefix=HEADER %s
+# HEADER: .text PROGBITS 0000000000201120 000120 00042c 00 AX 0 0 4
+
+.section .text.a,"ax"
+.byte 1
+
+.section .text.b,"ax"
+.byte 2
+
+.section .text.c,"ax"
+.byte 3
More information about the llvm-commits
mailing list