Skip to content

Commit

Permalink
[ELF] Pad x86 executable sections with 0xcc int3 instructions
Browse files Browse the repository at this point in the history
Executable sections should not be padded with zero by default. On some
architectures, 0x00 is the start of a valid instruction sequence, so can confuse
disassembly between InputSections (and indeed the start of the next InputSection
in some situations). Further, in the case of misjumps into padding, padding may
start to be executed silently.

On x86, the "0xcc" byte represents the int3 trap instruction. It is a single
byte long so can serve well as padding. This change switches x86 (and x86_64) to
use this value for padding in executable sections, if no linker script directive
overrides it. It also puts the behaviour into place making it easy to change the
behaviour of other targets when desired. I do not know the relevant instruction
sequences for trap instructions on other targets however, so somebody should add
this separately.

Because the old behaviour simply wrote padding in the whole section before
overwriting most of it, this change also modifies the padding algorithm to write
padding only where needed. This in turn has caused a small behaviour change with
regards to what values are written via Fill commands in linker scripts, bringing
it into line with ld.bfd. The fill value is now written starting from the end of
the previous block, which means that it always starts from the first byte of the
fill, whereas the old behaviour meant that the padding sometimes started mid-way
through the fill value. See the test changes for more details.

Reviewed by: ruiu

Differential Revision: https://reviews.llvm.org/D30886

Bugzilla: http://bugs.llvm.org/show_bug.cgi?id=32227
llvm-svn: 299635
  • Loading branch information
jh7370 committed Apr 6, 2017
1 parent 1b4b59a commit 8dd4c06
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 18 deletions.
4 changes: 2 additions & 2 deletions lld/ELF/LinkerScript.cpp
Expand Up @@ -862,12 +862,12 @@ bool LinkerScript::ignoreInterpSection() {
return true;
}

uint32_t LinkerScript::getFiller(StringRef Name) {
Optional<uint32_t> LinkerScript::getFiller(StringRef Name) {
for (BaseCommand *Base : Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->Name == Name)
return Cmd->Filler;
return 0;
return None;
}

static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/LinkerScript.h
Expand Up @@ -112,7 +112,7 @@ struct OutputSectionCommand : BaseCommand {
Expr SubalignExpr;
std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
uint32_t Filler = 0;
llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
Expand Down Expand Up @@ -262,7 +262,7 @@ class LinkerScript {
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();

uint32_t getFiller(StringRef Name);
llvm::Optional<uint32_t> getFiller(StringRef Name);
bool hasLMA(StringRef Name);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
Expand Down
40 changes: 35 additions & 5 deletions lld/ELF/OutputSections.cpp
Expand Up @@ -225,6 +225,9 @@ void OutputSection::sortCtorsDtors() {
// Fill [Buf, Buf + Size) with Filler. Filler is written in big
// endian order. This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
if (Filler == 0)
return;

uint8_t V[4];
write32be(V, Filler);
size_t I = 0;
Expand All @@ -233,17 +236,44 @@ static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
memcpy(Buf + I, V, Size - I);
}

uint32_t OutputSection::getFill() {
// Determine what to fill gaps between InputSections with, as specified by the
// linker script. If nothing is specified and this is an executable section,
// fall back to trap instructions to prevent bad diassembly and detect invalid
// jumps to padding.
if (Optional<uint32_t> Filler = Script->getFiller(Name))
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}

template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
Loc = Buf;
if (uint32_t Filler = Script->getFiller(this->Name))
fill(Buf, this->Size, Filler);

parallelForEach(Sections.begin(), Sections.end(),
[=](InputSection *IS) { IS->writeTo<ELFT>(Buf); });
uint32_t Filler = getFill();

// Write leading padding.
size_t FillSize = Sections.empty() ? Size : Sections[0]->OutSecOff;
fill(Buf, FillSize, Filler);

parallelFor(0, Sections.size(), [=](size_t I) {
InputSection *Sec = Sections[I];
Sec->writeTo<ELFT>(Buf);

// Fill gaps between sections with the specified fill value.
uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
});

// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
Script->writeDataBytes(this->Name, Buf);
Script->writeDataBytes(Name, Buf);
}

static uint64_t getOutFlags(InputSectionBase *S) {
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/OutputSections.h
Expand Up @@ -81,6 +81,7 @@ class OutputSection final : public SectionBase {
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
uint32_t getFill();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize();
void assignOffsets();
Expand Down
6 changes: 5 additions & 1 deletion lld/ELF/SyntheticSections.cpp
Expand Up @@ -2180,7 +2180,11 @@ MipsRldMapSection::MipsRldMapSection()

void MipsRldMapSection::writeTo(uint8_t *Buf) {
// Apply filler from linker script.
uint64_t Filler = Script->getFiller(this->Name);
Optional<uint32_t> Fill = Script->getFiller(this->Name);
if (!Fill || *Fill == 0)
return;

uint64_t Filler = *Fill;
Filler = (Filler << 32) | Filler;
memcpy(Buf, &Filler, getSize());
}
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Target.cpp
Expand Up @@ -349,6 +349,8 @@ X86TargetInfo::X86TargetInfo() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
// 0xCC is the "int3" (call debug exception handler) instruction.
TrapInstr = 0xcccccccc;
}

RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
Expand Down Expand Up @@ -647,6 +649,8 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
DefaultImageBase = 0x200000;
// 0xCC is the "int3" (call debug exception handler) instruction.
TrapInstr = 0xcccccccc;
}

template <class ELFT>
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Target.h
Expand Up @@ -90,6 +90,10 @@ class TargetInfo {

bool NeedsThunks = false;

// A 4-byte field corresponding to one or more trap instructions, used to pad
// executable OutputSections.
uint32_t TrapInstr = 0;

virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
RelExpr Expr) const;
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/Writer.cpp
Expand Up @@ -1790,7 +1790,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {

// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
if (EhFrameHdr)
if (EhFrameHdr && !EhFrameHdr->Sections.empty())
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}

Expand Down
38 changes: 38 additions & 0 deletions lld/test/ELF/default-fill.s
@@ -0,0 +1,38 @@
# REQUIRES: x86
# Verify that the fill between sections has a default of interrupt instructions
# (0xcc on x86/x86_64) for executable sections and zero for other sections.

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
# RUN: ld.lld %t1.o -o %t1.elf
# RUN: llvm-objdump -s %t1.elf > %t1.sections
# RUN: FileCheck %s --input-file %t1.sections --check-prefix=TEXT
# RUN: FileCheck %s --input-file %t1.sections --check-prefix=DATA

# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t2.o
# RUN: ld.lld %t2.o -o %t2.elf
# RUN: llvm-objdump -s %t2.elf > %t2.sections
# RUN: FileCheck %s --input-file %t2.sections --check-prefix=TEXT
# RUN: FileCheck %s --input-file %t2.sections --check-prefix=DATA

# TEXT: Contents of section .text:
# TEXT-NEXT: 11cccccc cccccccc cccccccc cccccccc
# TEXT-NEXT: 22
# DATA: Contents of section .data:
# DATA-NEXT: 33000000 00000000 00000000 00000000
# DATA-NEXT: 44

.section .text.1,"ax",@progbits
.align 16
.byte 0x11

.section .text.2,"ax",@progbits
.align 16
.byte 0x22

.section .data.1,"a",@progbits
.align 16
.byte 0x33

.section .data.2,"a",@progbits
.align 16
.byte 0x44
9 changes: 6 additions & 3 deletions lld/test/ELF/linkerscript/excludefile.s
Expand Up @@ -13,11 +13,13 @@
# CHECK: _start:
# CHECK-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax
# CHECK-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi
# CHECK-NEXT: : 00 00 addb %al, (%rax)
# CHECK-NEXT: : cc int3
# CHECK-NEXT: : cc int3
# CHECK: _potato:
# CHECK-NEXT: : 90 nop
# CHECK-NEXT: : 90 nop
# CHECK-NEXT: : 00 00 addb %al, (%rax)
# CHECK-NEXT: : cc int3
# CHECK-NEXT: : cc int3
# CHECK: tomato:
# CHECK-NEXT: : b8 01 00 00 00 movl $1, %eax

Expand All @@ -31,7 +33,8 @@
# EXCLUDE: _start:
# EXCLUDE-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax
# EXCLUDE-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi
# EXCLUDE-NEXT: : 00 00 addb %al, (%rax)
# EXCLUDE-NEXT: : cc int3
# EXCLUDE-NEXT: : cc int3
# EXCLUDE: _potato:
# EXCLUDE-NEXT: : 90 nop
# EXCLUDE-NEXT: : 90 nop
Expand Down
40 changes: 40 additions & 0 deletions lld/test/ELF/linkerscript/fill-exec-sections.s
@@ -0,0 +1,40 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t

## Check that padding of executable sections are filled with trap bytes if not
## otherwise specified in the script.
# RUN: echo "SECTIONS { .exec : { *(.exec*) } }" > %t.script
# RUN: ld.lld -o %t.out --script %t.script %t
# RUN: llvm-objdump -s %t.out | FileCheck %s --check-prefix=EXEC
# EXEC: 0000 66cccccc cccccccc cccccccc cccccccc
# EXEC-NEXT: 0010 66

## Check that a fill expression or command overrides the default filler...
# RUN: echo "SECTIONS { .exec : { *(.exec*) }=0x11223344 }" > %t2.script
# RUN: ld.lld -o %t2.out --script %t2.script %t
# RUN: llvm-objdump -s %t2.out | FileCheck %s --check-prefix=OVERRIDE
# RUN: echo "SECTIONS { .exec : { FILL(0x11223344); *(.exec*) } }" > %t3.script
# RUN: ld.lld -o %t3.out --script %t3.script %t
# RUN: llvm-objdump -s %t3.out | FileCheck %s --check-prefix=OVERRIDE
# OVERRIDE: Contents of section .exec:
# OVERRIDE-NEXT: 0000 66112233 44112233 44112233 44112233
# OVERRIDE-NEXT: 0010 66

## ...even for a value of zero.
# RUN: echo "SECTIONS { .exec : { *(.exec*) }=0x00000000 }" > %t4.script
# RUN: ld.lld -o %t4.out --script %t4.script %t
# RUN: llvm-objdump -s %t4.out | FileCheck %s --check-prefix=ZERO
# RUN: echo "SECTIONS { .exec : { FILL(0x00000000); *(.exec*) } }" > %t5.script
# RUN: ld.lld -o %t5.out --script %t5.script %t
# RUN: llvm-objdump -s %t5.out | FileCheck %s --check-prefix=ZERO
# ZERO: Contents of section .exec:
# ZERO-NEXT: 0000 66000000 00000000 00000000 00000000
# ZERO-NEXT: 0010 66

.section .exec.1,"ax"
.align 16
.byte 0x66

.section .exec.2,"ax"
.align 16
.byte 0x66
3 changes: 2 additions & 1 deletion lld/test/ELF/linkerscript/fill.s
Expand Up @@ -3,6 +3,7 @@
# RUN: echo "SECTIONS { \
# RUN: .out : { \
# RUN: FILL(0x11111111); \
# RUN: . += 2; \
# RUN: *(.aaa) \
# RUN: . += 4; \
# RUN: *(.bbb) \
Expand All @@ -15,7 +16,7 @@
# RUN: llvm-objdump -s %t | FileCheck %s

# CHECK: Contents of section .out:
# CHECK-NEXT: aa222222 22bb2222 22222222 2222
# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222

.text
.globl _start
Expand Down
6 changes: 3 additions & 3 deletions lld/test/ELF/linkerscript/sections-padding.s
Expand Up @@ -5,13 +5,13 @@
# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x1122 }" > %t.script
# RUN: ld.lld -o %t.out --script %t.script %t
# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
# YES: 66001122 00001122 00001122 00001122
# YES: 66000011 22000011 22000011 22000011

## Confirming that address was correct:
# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99887766 }" > %t.script
# RUN: ld.lld -o %t.out --script %t.script %t
# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES2 %s
# YES2: 66887766 99887766 99887766 99887766
# YES2: 66998877 66998877 66998877 66998877

## Default padding value is 0x00:
# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script
Expand All @@ -23,7 +23,7 @@
# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =777 }" > %t.script
# RUN: ld.lld -o %t.out --script %t.script %t
# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=DEC %s
# DEC: 66000309 00000309 00000309 00000309
# DEC: 66000003 09000003 09000003 09000003

## Invalid hex value:
# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script
Expand Down

0 comments on commit 8dd4c06

Please sign in to comment.