Index: ELF/Arch/X86.cpp =================================================================== --- ELF/Arch/X86.cpp +++ ELF/Arch/X86.cpp @@ -443,6 +443,7 @@ 0x89, 0xc8, // 2b: mov %ecx, %eax 0x59, // 2d: pop %ecx 0xc3, // 2e: ret + 0xcc // 2f: int3; .align 48 }; memcpy(Buf, Insn, sizeof(Insn)); @@ -456,12 +457,13 @@ uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x50, // pushl %eax - 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax - 0xe8, 0, 0, 0, 0, // call plt+0x20 - 0xe9, 0, 0, 0, 0, // jmp plt+0x12 - 0x68, 0, 0, 0, 0, // pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0x50, // pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax + 0xe8, 0, 0, 0, 0, // call plt+0x20 + 0xe9, 0, 0, 0, 0, // jmp plt+0x12 + 0x68, 0, 0, 0, 0, // pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc // int3; .align 32 }; memcpy(Buf, Insn, sizeof(Insn)); @@ -500,6 +502,7 @@ 0x89, 0xc8, // 2b: mov %ecx, %eax 0x59, // 2d: pop %ecx 0xc3, // 2e: ret + 0xcc // 2f: int3; .align 48 }; memcpy(Buf, PltData, sizeof(PltData)); @@ -512,12 +515,13 @@ uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x50, // 0: pushl %eax - 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax - 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 - 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 - 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + 0x50, // 0: pushl %eax + 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax + 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 + 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 + 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc // 16: int3; .align 32 }; memcpy(Buf, Insn, sizeof(Insn)); Index: ELF/Arch/X86_64.cpp =================================================================== --- ELF/Arch/X86_64.cpp +++ ELF/Arch/X86_64.cpp @@ -491,15 +491,17 @@ template void Retpoline::writePltHeader(uint8_t *Buf) const { const uint8_t Insn[] = { - 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 - 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next - 0xf3, 0x90, // 12: loop: pause - 0x0f, 0xae, 0xe8, // 14: lfence - 0xeb, 0xf9, // 17: jmp loop + 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) 0xc3, // 24: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc // 25: int3; .align 48 }; memcpy(Buf, Insn, sizeof(Insn)); @@ -514,11 +516,12 @@ uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 - 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 - 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 - 0x68, 0, 0, 0, 0, // 11: pushq - 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 + 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 + 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 + 0x68, 0, 0, 0, 0, // 11: pushq + 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc // 1b: int3; .align 32 }; memcpy(Buf, Insn, sizeof(Insn)); @@ -546,6 +549,8 @@ 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) 0xc3, // 14: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc // 15: int3; .align 48 }; memcpy(Buf, Insn, sizeof(Insn)); } @@ -555,8 +560,9 @@ uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 - 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc // int3; .align 32 }; memcpy(Buf, Insn, sizeof(Insn)); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -2182,9 +2182,18 @@ Sec->writeTo(Buf + Sec->Offset); } -static void fillTrap(uint8_t *I, uint8_t *End) { +static std::vector getSectionsInLoad(PhdrEntry *Load) { + std::vector V; + for (OutputSection *Sec : OutputSections) + if (Sec->PtLoad == Load) + V.push_back(Sec); + return V; +} + +void fillTrap(uint8_t *I, uint8_t *End) { for (; I + 4 <= End; I += 4) memcpy(I, &Target->TrapInstr, 4); + memcpy(I, &Target->TrapInstr, End - I); } // Fill the last page of executable segments with trap instructions @@ -2197,12 +2206,24 @@ if (Script->HasSectionsCommand) return; - // Fill the last page. + // Here we want to fill all paddings inside PT_LOAD with trap instructions. + // For that, we want to fill all gaps between sections and two gaps between + // the first and last sections and segment boundaries. There is never a gap + // between the beginning of the segment and first section, so we ignore it. uint8_t *Buf = Buffer->getBufferStart(); - for (PhdrEntry *P : Phdrs) - if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) - fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize), - Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize)); + for (PhdrEntry *P : Phdrs) { + if (P->p_type != PT_LOAD || !(P->p_flags & PF_X)) + continue; + + // Fill gaps between output sections. + std::vector V = getSectionsInLoad(P); + for (size_t I = 0; I < V.size() - 1; ++I) + fillTrap(Buf + V[I]->Offset + V[I]->Size, Buf + V[I + 1]->Offset); + + // Fill gap between the last section and end of the segment. + fillTrap(Buf + V.back()->Offset + V.back()->Size, + Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize)); + } // Round up the file size of the last segment to the page boundary iff it is // an executable segment to ensure that other tools don't accidentally Index: test/ELF/fill-trap2.s =================================================================== --- test/ELF/fill-trap2.s +++ test/ELF/fill-trap2.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s +# RUN: od -Ax -t x1 -N16 -j0x1000 %t2 | FileCheck %s -check-prefix=FILL + +# CHECK: ProgramHeader { +# CHECK: Type: PT_LOAD +# CHECK: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: +# CHECK-NEXT: PhysicalAddress: +# CHECK-NEXT: FileSize: 8192 +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] + +# FILL: 001000 90 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc + +nop + +.section .foo,"ax" +.align 16 +nop +.zero 0x1000