Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -294,12 +294,18 @@ // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. - template void writeTo(uint8_t *Buf); + template void writeTo(uint8_t *Buf, uint32_t Filler); - // The offset from beginning of the output sections this section was assigned - // to. The writer sets a value. + // The offset from the beginning of the output section this section was + // assigned to. The writer sets a value. uint64_t OutSecOff = 0; + // The offset from the beginning of the output section to the end of the + // previous InputSection or BYTE()-family linker script command (zero, if + // nothing appears before this section). Padding will be written from here to + // the section start. + size_t PaddingOffset; + static bool classof(const SectionBase *S); InputSectionBase *getRelocatedSection(); Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -641,10 +641,14 @@ } } -template void InputSection::writeTo(uint8_t *Buf) { +template +void InputSection::writeTo(uint8_t *Buf, uint32_t Filler) { if (this->Type == SHT_NOBITS) return; + if (Filler != 0) + fill(Buf + PaddingOffset, OutSecOff - PaddingOffset, Filler); + if (auto *S = dyn_cast(this)) { S->writeTo(Buf + OutSecOff); return; @@ -901,10 +905,10 @@ template std::string InputSectionBase::getObjMsg(uint64_t); template std::string InputSectionBase::getObjMsg(uint64_t); -template void InputSection::writeTo(uint8_t *); -template void InputSection::writeTo(uint8_t *); -template void InputSection::writeTo(uint8_t *); -template void InputSection::writeTo(uint8_t *); +template void InputSection::writeTo(uint8_t *, uint32_t); +template void InputSection::writeTo(uint8_t *, uint32_t); +template void InputSection::writeTo(uint8_t *, uint32_t); +template void InputSection::writeTo(uint8_t *, uint32_t); template elf::ObjectFile *InputSectionBase::getFile() const; template elf::ObjectFile *InputSectionBase::getFile() const; Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -125,7 +125,7 @@ Expr SubalignExpr; std::vector> Commands; std::vector Phdrs; - uint32_t Filler = 0; + llvm::Optional Filler; ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; @@ -178,6 +178,10 @@ Expr Expression; unsigned Offset; unsigned Size; + // The offset of the end of the previous BYTE()-family command or + // InputSection, relative to the output section start. Padding is written from + // this point to the start of the command. + uint64_t PaddingOffset; }; struct PhdrsCommand { @@ -237,9 +241,9 @@ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd, OutputSection *Sec); void switchTo(OutputSection *Sec); - void flush(); - void output(InputSection *Sec); - void process(BaseCommand &Base); + void flush(uint64_t &PreviousEndOffset); + void output(InputSection *Sec, uint64_t &PreviousEndOffset); + void process(BaseCommand &Base, uint64_t &PreviousEndOffset); OutputSection *Aether; bool ErrorOnMissingSection = false; @@ -273,7 +277,7 @@ std::vector createPhdrs(); bool ignoreInterpSection(); - uint32_t getFiller(StringRef Name); + llvm::Optional getFiller(StringRef Name); bool hasLMA(StringRef Name); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); @@ -282,7 +286,7 @@ void assignAddresses(std::vector &Phdrs); int getSectionIndex(StringRef Name); - void writeDataBytes(StringRef Name, uint8_t *Buf); + void writeDataBytes(OutputSection *Section, uint8_t *Buf); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -482,14 +482,16 @@ return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS; } -void LinkerScript::output(InputSection *S) { +void LinkerScript::output(InputSection *S, uint64_t &PreviousEndOffset) { if (!AlreadyOutputIS.insert(S).second) return; bool IsTbss = isTbss(CurOutSec); uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot; + S->PaddingOffset = PreviousEndOffset; Pos = alignTo(Pos, S->Alignment); S->OutSecOff = Pos - CurOutSec->Addr; + PreviousEndOffset = S->OutSecOff + S->getSize(); Pos += S->getSize(); // Update output section size after adding each section. This is so that @@ -497,6 +499,8 @@ // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } CurOutSec->Size = Pos - CurOutSec->Addr; + CurOutSec->LastEnd = CurOutSec->Size; + // If there is a memory region associated with this input section, then // place the section in that region and update the region index. if (CurMemRegion) { @@ -516,12 +520,12 @@ Dot = Pos; } -void LinkerScript::flush() { +void LinkerScript::flush(uint64_t &PreviousEndOffset) { assert(CurOutSec); if (!AlreadyOutputOS.insert(CurOutSec).second) return; for (InputSection *I : CurOutSec->Sections) - output(I); + output(I, PreviousEndOffset); } void LinkerScript::switchTo(OutputSection *Sec) { @@ -543,7 +547,7 @@ CurOutSec->LMAOffset = LMAOffset(); } -void LinkerScript::process(BaseCommand &Base) { +void LinkerScript::process(BaseCommand &Base, uint64_t &PreviousEndOffset) { // This handles the assignments to symbol or to a location counter (.) if (auto *AssignCmd = dyn_cast(&Base)) { assignSymbol(AssignCmd, true); @@ -553,8 +557,11 @@ // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *DataCmd = dyn_cast(&Base)) { DataCmd->Offset = Dot - CurOutSec->Addr; + DataCmd->PaddingOffset = PreviousEndOffset; Dot += DataCmd->Size; + PreviousEndOffset += DataCmd->Size; CurOutSec->Size = Dot - CurOutSec->Addr; + CurOutSec->LastEnd = CurOutSec->Size; return; } @@ -579,7 +586,7 @@ if (!IB->Live) continue; assert(CurOutSec == IB->OutSec || AlreadyOutputOS.count(IB->OutSec)); - output(cast(IB)); + output(cast(IB), PreviousEndOffset); } } @@ -662,11 +669,19 @@ return !isa(*Cmd); }) .base(); + + // Track the end of each previous data block (whether an input section or that + // written by BYTE() etc), relative to the start of the output section. This is + // used to record where to write padding. + uint64_t PreviousEnd = 0; + for (auto I = Cmd->Commands.begin(); I != E; ++I) - process(**I); - flush(); + process(**I, PreviousEnd); + flush(PreviousEnd); std::for_each(E, Cmd->Commands.end(), - [this](std::unique_ptr &B) { process(*B.get()); }); + [this, &PreviousEnd](std::unique_ptr &B) { + process(*B.get(), PreviousEnd); + }); } void LinkerScript::removeEmptyCommands() { @@ -935,12 +950,12 @@ }) == Opt.PhdrsCommands.end(); } -uint32_t LinkerScript::getFiller(StringRef Name) { +Optional LinkerScript::getFiller(StringRef Name) { for (const std::unique_ptr &Base : Opt.Commands) if (auto *Cmd = dyn_cast(Base.get())) if (Cmd->Name == Name) return Cmd->Filler; - return 0; + return Optional(); } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { @@ -962,15 +977,18 @@ } } -void LinkerScript::writeDataBytes(StringRef Name, uint8_t *Buf) { - int I = getSectionIndex(Name); +void LinkerScript::writeDataBytes(OutputSection *Section, uint8_t *Buf) { + int I = getSectionIndex(Section->Name); if (I == INT_MAX) return; auto *Cmd = dyn_cast(Opt.Commands[I].get()); for (const std::unique_ptr &Base : Cmd->Commands) - if (auto *Data = dyn_cast(Base.get())) + if (auto *Data = dyn_cast(Base.get())) { + uint32_t Filler = Section->getFill(); + fill(Buf + Data->PaddingOffset, Data->Offset - Data->PaddingOffset, Filler); writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); + } } bool LinkerScript::hasLMA(StringRef Name) { Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -77,10 +77,16 @@ uint64_t Addr = 0; uint32_t ShName = 0; + // The offset of the end of the last input section or BYTE()-family command, + // relative to the section start. This may not match the section size, because + // assigning to "." can increase the section size beyond this point. + uint64_t LastEnd = 0; + void addSection(InputSectionBase *C); void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); + uint32_t getFill(); template void writeTo(uint8_t *Buf); template void finalize(); void assignOffsets(); @@ -143,6 +149,8 @@ uint64_t getHeaderSize(); +void fill(uint8_t *Buf, size_t Size, uint32_t Filler); + } // namespace elf } // namespace lld Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -133,11 +133,13 @@ void OutputSection::assignOffsets() { uint64_t Off = 0; for (InputSection *S : Sections) { + S->PaddingOffset = Off; Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; Off += S->getSize(); } - this->Size = Off; + Size = Off; + LastEnd = Off; } void OutputSection::sort(std::function Order) { @@ -223,8 +225,9 @@ } // Fill [Buf, Buf + Size) with Filler. Filler is written in big -// endian order. This is used for linker script "=fillexp" command. -void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { +// endian order. This is used for writing padding between input +// sections and/or BYTE()-family commands. +void elf::fill(uint8_t *Buf, size_t Size, uint32_t Filler) { uint8_t V[4]; write32be(V, Filler); size_t I = 0; @@ -233,17 +236,34 @@ 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. + uint32_t FillValue = 0; + if (Optional Filler = Script->getFiller(this->Name)) + FillValue = *Filler; + else if (Flags & SHF_EXECINSTR && Target->TrapInstr != 0) + FillValue = Target->TrapInstr; + + return FillValue; +} + template void OutputSection::writeTo(uint8_t *Buf) { Loc = Buf; - if (uint32_t Filler = Script->getFiller(this->Name)) - fill(Buf, this->Size, Filler); + uint32_t FillValue = getFill(); parallelForEach(Sections.begin(), Sections.end(), - [=](InputSection *IS) { IS->writeTo(Buf); }); + [=](InputSection *IS) { IS->writeTo(Buf, FillValue); }); // 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(this, Buf); + + // Dot assignments after the last input section/BYTE()-family command cause + // the section to be bigger, so write any necessary trailing padding. + fill(Buf + LastEnd, Size - LastEnd, FillValue); } static uint64_t getOutFlags(InputSectionBase *S) { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2180,7 +2180,8 @@ void MipsRldMapSection::writeTo(uint8_t *Buf) { // Apply filler from linker script. - uint64_t Filler = Script->getFiller(this->Name); + Optional Fill = Script->getFiller(this->Name); + uint64_t Filler = Fill ? *Fill : 0; Filler = (Filler << 32) | Filler; memcpy(Buf, &Filler, getSize()); } Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -91,6 +91,10 @@ 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; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -355,6 +355,8 @@ 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 { @@ -647,6 +649,8 @@ // 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 Index: test/ELF/default-fill.s =================================================================== --- test/ELF/default-fill.s +++ test/ELF/default-fill.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# Verify that the fill between sections has a default of interrupt instructions +# (0xcc on x86/x86_64) + +# 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 | FileCheck %s + +# 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 | FileCheck %s + +# CHECK: Contents of section .data: +# CHECK-NEXT: 33000000 00000000 00000000 00000000 +# CHECK-NEXT: 44 +# CHECK: Contents of section .text: +# CHECK-NEXT: 11cccccc cccccccc cccccccc cccccccc +# CHECK-NEXT: 22 + +.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 Index: test/ELF/linkerscript/excludefile.s =================================================================== --- test/ELF/linkerscript/excludefile.s +++ test/ELF/linkerscript/excludefile.s @@ -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 @@ -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 Index: test/ELF/linkerscript/fill-exec-sections.s =================================================================== --- test/ELF/linkerscript/fill-exec-sections.s +++ test/ELF/linkerscript/fill-exec-sections.s @@ -0,0 +1,33 @@ +# 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. +# 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: 66cccccc cccccccc cccccccc cccccccc +# EXEC-NEXT: 66 + +## Check that a fill expression still overrides the default filler... +# RUN: echo "SECTIONS { .exec : { *(.exec*) }=0x11223344 }" > %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 +# 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 Index: test/ELF/linkerscript/sections-padding.s =================================================================== --- test/ELF/linkerscript/sections-padding.s +++ test/ELF/linkerscript/sections-padding.s @@ -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 @@ -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