Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ struct Config {
bool printGcSections;
bool printIcfSections;
bool printMemoryUsage;
std::optional<uint64_t> randomizeSectionPadding;
bool rejectMismatch;
bool relax;
bool relaxGP;
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,9 @@ 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_randomize_section_padding))
ctx.arg.randomizeSectionPadding =
args::getInteger(args, OPT_randomize_section_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);
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ defm section_start: Eq<"section-start", "Set address of section">,

def shared: F<"shared">, HelpText<"Build a shared object">;

def randomize_section_padding: JJ<"randomize-section-padding=">,
HelpText<"Randomly insert padding between input sections using given seed">;

defm soname: Eq<"soname", "Set DT_SONAME">;

defm sort_section:
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/OutputSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 15 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2753,6 +2753,21 @@ RelroPaddingSection::RelroPaddingSection(Ctx &ctx)
: SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE,
1) {}

RandomizePaddingSection::RandomizePaddingSection(Ctx &ctx, uint64_t size,
OutputSection *parent)
: SyntheticSection(ctx, ".randomize_padding", SHT_PROGBITS, SHF_ALLOC, 1),
size(size) {
this->parent = parent;
}

void RandomizePaddingSection::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;
Expand Down
9 changes: 9 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,15 @@ class RelroPaddingSection final : public SyntheticSection {
void writeTo(uint8_t *buf) override {}
};

class RandomizePaddingSection final : public SyntheticSection {
uint64_t size;

public:
RandomizePaddingSection(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 {
Expand Down
36 changes: 36 additions & 0 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,39 @@ 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 randomizeSectionPadding(Ctx &ctx) {
std::mt19937 g(*ctx.arg.randomizeSectionPadding);
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<RandomizePaddingSection>(
ctx, g() % ctx.arg.maxPageSize, os));
curPtLoad = os->ptLoad;
}
for (InputSection *isec : isd->sections) {
// Probability of inserting padding is 1 in 16.
if (g() % 16 == 0)
tmp.push_back(
make<RandomizePaddingSection>(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
Expand All @@ -1470,6 +1503,9 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
if (ctx.arg.emachine == EM_HEXAGON)
hexagonTLSSymbolUpdate(ctx);

if (ctx.arg.randomizeSectionPadding)
randomizeSectionPadding(ctx);

uint32_t pass = 0, assignPasses = 0;
for (;;) {
bool changed = ctx.target->needsThunks
Expand Down
9 changes: 9 additions & 0 deletions lld/docs/ld.lld.1
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,15 @@ and
.It Fl -pop-state
Restore the states saved by
.Fl -push-state.
.It Fl -randomize-section-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 --relax-gp
Enable global pointer relaxation for RISC-V.
.It Fl -relocatable , Fl r
Expand Down
125 changes: 125 additions & 0 deletions lld/test/ELF/randomize-section-padding.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# REQUIRES: x86
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o

## --randomize-section-padding= inserts segment offset padding and pre-section
## padding, and does not affect flags. Segment offset padding is only inserted
## when PT_LOAD changes, as shown by .bss size (.data and .bss share a PT_LOAD).

# RUN: ld.lld --randomize-section-padding=6 %t/a.o -o %t/a.out
# RUN: llvm-readelf -sS -x .rodata -x .text -x .data %t/a.out | FileCheck --check-prefix=PAD6 %s

# PAD6: .rodata PROGBITS 0000000000200158 000158 000b8d 00 A 0 0 1
# PAD6: .text PROGBITS 0000000000201ce8 000ce8 000270 00 AX 0 0 4
# PAD6: .data PROGBITS 0000000000202f58 000f58 000941 00 WA 0 0 1
# PAD6: .bss NOBITS 0000000000203899 001899 000003 00 WA 0 0 1

# PAD6: 0000000000203899 0 NOTYPE LOCAL DEFAULT 4 a
# PAD6: 000000000020389a 0 NOTYPE LOCAL DEFAULT 4 b
# PAD6: 000000000020389b 0 NOTYPE LOCAL DEFAULT 4 c

# PAD6: Hex dump of section '.rodata':
# PAD6: 0x00200cd8 00000000 00000000 00000102 03
# PAD6: Hex dump of section '.text':
# PAD6: 0x00201f48 cccccccc cccccccc cccccccc 0405cc06
# PAD6: Hex dump of section '.data':
# PAD6: 0x00203888 00000000 00000000 00000000 00000708
# PAD6: 0x00203898 09

## Size of segment offset padding and location of pre-section padding is
## dependent on the seed.

# RUN: ld.lld --randomize-section-padding=46 %t/a.o -o %t/a.out
# RUN: llvm-readelf -sS -x .rodata -x .text -x .data %t/a.out | FileCheck --check-prefix=PAD46 %s

# PAD46: .rodata PROGBITS 0000000000200158 000158 000cc0 00 A 0 0 1
# PAD46: .text PROGBITS 0000000000201e18 000e18 0009bf 00 AX 0 0 4
# PAD46: .data PROGBITS 00000000002037d7 0017d7 000540 00 WA 0 0 1
# PAD46: .bss NOBITS 0000000000203d17 001d17 000004 00 WA 0 0 1

# PAD46: 0000000000203d17 0 NOTYPE LOCAL DEFAULT 4 a
# PAD46: 0000000000203d18 0 NOTYPE LOCAL DEFAULT 4 b
# PAD46: 0000000000203d1a 0 NOTYPE LOCAL DEFAULT 4 c

# PAD46: Hex dump of section '.rodata':
# PAD46: 0x00200e08 00000000 00000000 00000000 00010203
# PAD46: Hex dump of section '.text':
# PAD46: 0x002027c8 cccccccc cccccccc cccccccc 040506
# PAD46: Hex dump of section '.data':
# PAD46: 0x00203d07 00000000 00000000 00000000 07000809

## When there are multiple InputSectionDescriptions for an output section,
## segment offset padding is inserted in the first InputSectionDescription.

# RUN: ld.lld --randomize-section-padding=46 %t/a.o %t/a.lds -o %t/a.out

# RUN: llvm-readelf -sS -x .rodata -x .text -x .data %t/a.out | FileCheck --check-prefix=PAD46-LDS %s

# PAD46-LDS: .rodata PROGBITS 0000000000000158 000158 000cc0 00 A 0 0 1
# PAD46-LDS: .text PROGBITS 0000000000001000 001000 0009c0 00 AX 0 0 4
# PAD46-LDS: .data PROGBITS 0000000000002000 002000 000540 00 WA 0 0 1
# PAD46-LDS: .bss NOBITS 0000000000002540 002540 000004 00 WA 0 0 1

# PAD46-LDS: 0000000000002543 0 NOTYPE LOCAL DEFAULT 4 a
# PAD46-LDS: 0000000000002541 0 NOTYPE LOCAL DEFAULT 4 b
# PAD46-LDS: 0000000000002540 0 NOTYPE LOCAL DEFAULT 4 c

# PAD46-LDS: Hex dump of section '.rodata':
# PAD46-LDS: 0x00000e08 00000000 00000000 00000000 00030201 ................
# PAD46-LDS: Hex dump of section '.text':
# PAD46-LDS: 0x000019b0 cccccccc cccccccc cccc0605 04cccccc ................
# PAD46-LDS: Hex dump of section '.data':
# PAD46-LDS: 0x00002530 00000000 00000000 00000000 09000807 ................

#--- a.s

.section .rodata.a,"a",@progbits
.byte 1

.section .rodata.b,"a",@progbits
.byte 2

.section .rodata.c,"a",@progbits
.byte 3

.section .text.a,"ax",@progbits
.byte 4

.section .text.b,"ax",@progbits
.byte 5

.section .text.c,"ax",@progbits
.byte 6

.section .data.a,"aw",@progbits
.byte 7

.section .data.b,"aw",@progbits
.byte 8

.section .data.c,"aw",@progbits
.byte 9

.section .bss.a,"a",@nobits
a:
.zero 1

.section .bss.b,"a",@nobits
b:
.zero 1

.section .bss.c,"a",@nobits
c:
.zero 1

#--- a.lds

SECTIONS {
. = SIZEOF_HEADERS;
.rodata : { *(.rodata.c) *(.rodata.b) *(.rodata.a) }
. = ALIGN(CONSTANT(MAXPAGESIZE));
.text : { *(.text.c) *(.text.b) *(.text.a) }
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : { *(.data.c) *(.data.b) *(.data.a) }
.bss : { *(.bss.c) *(.bss.b) *(.bss.a) }
}
Loading