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; @@ -273,7 +273,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); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -935,12 +935,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) { Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -81,6 +81,7 @@ void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); + uint32_t getFill(); template void writeTo(uint8_t *Buf); template void finalize(); void assignOffsets(); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -225,6 +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) { + if (Filler == 0) + return; + uint8_t V[4]; write32be(V, Filler); size_t I = 0; @@ -233,13 +236,46 @@ 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) + 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); - parallelForEach(Sections.begin(), Sections.end(), - [=](InputSection *IS) { IS->writeTo(Buf); }); + uint32_t FillValue = getFill(); + if (!Sections.empty()) { + // Write any leading padding, in case the first input section does not + // appear at offset zero. + fill(Buf, Sections.front()->OutSecOff, FillValue); + } else { + // If the section has no input sections, fill it completely with the fill. + fill(Buf, this->Size, FillValue); + } + + parallelFor(0, Sections.size(), [=](size_t I) { + InputSection *Sec = Sections[I]; + Sec->writeTo(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 + this->Size; + else + End = Buf + Sections[I + 1]->OutSecOff; + fill(Start, End - Start, FillValue); + }); // Linker scripts may have BYTE()-family commands with which you // can write arbitrary bytes to the output. Process them if any. 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.getValueOr(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: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1041,8 +1041,9 @@ // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always -// required to be in output. For example we don't need dynamic section content -// sometimes. This function filters out such unused sections from output. +// required to be in the output. For example we don't need dynamic section +// content sometimes. This function filters out such unused sections from +// the output. static void removeUnusedSyntheticSections(std::vector &V) { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first @@ -1054,10 +1055,11 @@ if (!SS->empty() || !SS->OutSec) continue; - OutputSection *OutSec = cast(SS->OutSec); + OutputSection *OutSec = SS->OutSec; OutSec->Sections.erase( std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS)); - // If there is no other sections in output section, remove it from output. + // If there are no other sections in the output section, remove it from + // the output. if (OutSec->Sections.empty()) V.erase(std::find(V.begin(), V.end(), OutSec)); } @@ -1794,7 +1796,7 @@ // 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(Buf + EhFrameHdr->Offset); } 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) 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 | 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,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 Index: test/ELF/linkerscript/fill.s =================================================================== --- test/ELF/linkerscript/fill.s +++ test/ELF/linkerscript/fill.s @@ -3,6 +3,7 @@ # RUN: echo "SECTIONS { \ # RUN: .out : { \ # RUN: FILL(0x11111111); \ +# RUN: . += 2; \ # RUN: *(.aaa) \ # RUN: . += 4; \ # RUN: *(.bbb) \ @@ -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 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