Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -59,6 +59,7 @@ std::vector createPhdrs(); void removeEmptyPTLoad(); + void findLastPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignFileOffsets(); void assignFileOffsetsBinary(); @@ -86,6 +87,8 @@ OutputSectionCommand *findSectionCommand(StringRef Name); std::vector Phdrs; + PhdrEntry *Last = nullptr; + PhdrEntry *LastRX = nullptr; uint64_t FileSize; uint64_t SectionHeaderOff; @@ -137,6 +140,16 @@ Phdrs.erase(I, Phdrs.end()); } +template void Writer::findLastPTLoad() { + for (PhdrEntry &P : Phdrs) { + if (P.p_type != PT_LOAD) + continue; + Last = &P; + if (P.p_flags & PF_X) + LastRX = &P; + } +} + // This function scans over the input sections and creates mergeable // synthetic sections. It removes MergeInputSections from array and // adds new synthetic ones. Each synthetic section is added to the @@ -263,6 +276,8 @@ // we know the size of the sections. removeEmptyPTLoad(); + findLastPTLoad(); + if (!Config->OFormatBinary) assignFileOffsets(); else @@ -1582,8 +1597,20 @@ Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); - for (OutputSectionCommand *Cmd : OutputSectionCommands) + OutputSection *LastSec = nullptr; + if (LastRX && LastRX == Last) + LastSec = LastRX->Last; + + for (OutputSectionCommand *Cmd : OutputSectionCommands) { Off = setOffset(Cmd->Sec, Off); + if (!Script->Opt.HasSections) { + // Align the offset if this section is the last section of the executable + // segment and this is the last loadable segment, otherwise there would be + // no space for instruction padding. + if (Cmd->Sec == LastSec) + Off = alignTo(Off, Target->PageSize); + } + } SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = @@ -1606,9 +1633,9 @@ if (!P.HasLMA) P.p_paddr = First->getLMA(); } - if (P.p_type == PT_LOAD) + if (P.p_type == PT_LOAD) { P.p_align = Config->MaxPageSize; - else if (P.p_type == PT_GNU_RELRO) { + } else if (P.p_type == PT_GNU_RELRO) { P.p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always @@ -1624,6 +1651,14 @@ P.p_memsz = alignTo(P.p_memsz, P.p_align); } } + + if (!Script->Opt.HasSections) { + // Round up the size of the last segment to the page boundary iff it is the + // executable segment to avoid loading the non-segment parts at the end + // of the ELF file as executable. + if (LastRX && Last == LastRX) + LastRX->p_filesz = alignTo(LastRX->p_filesz, Target->PageSize); + } } // The entry point address is chosen in the following ways. @@ -1804,6 +1839,13 @@ } } +static void fill(uint8_t *Buf, size_t Size) { + size_t I = 0; + for (; I + 4 < Size; I += 4) + memcpy(Buf + I, &Target->TrapInstr, 4); + memcpy(Buf + I, &Target->TrapInstr, Size - I); +} + // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); @@ -1843,6 +1885,21 @@ OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); Cmd->writeTo(Buf + EhFrameHdr->Offset); } + + // Fill the empty space at the end of every executable segment up to the page + // boundary with instruction padding. + for (size_t I = 0; I < Phdrs.size(); I++) { + const PhdrEntry &P = Phdrs[I]; + if (P.p_type != PT_LOAD) + continue; + if (P.p_flags & PF_X) { + unsigned long End = P.Last->Offset + P.Last->Size; + if (&P != LastRX && I + 1 < Phdrs.size()) + fill(Buf + End, Phdrs[I + 1].First->Offset - End); + else if (&P == LastRX) + fill(Buf + End, P.First->Offset + P.p_filesz - End); + } + } } template void Writer::writeBuildId() { Index: test/ELF/avoid-empty-program-headers.s =================================================================== --- test/ELF/avoid-empty-program-headers.s +++ test/ELF/avoid-empty-program-headers.s @@ -42,7 +42,7 @@ // CHECK-NEXT: Offset: 0x1000 // CHECK-NEXT: VirtualAddress: 0x201000 // CHECK-NEXT: PhysicalAddress: 0x201000 -// CHECK-NEXT: FileSize: 1 +// CHECK-NEXT: FileSize: 4096 // CHECK-NEXT: MemSize: 1 // CHECK-NEXT: Flags [ (0x5) // CHECK-NEXT: PF_R (0x4) @@ -52,7 +52,7 @@ // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_TLS (0x7) -// CHECK-NEXT: Offset: 0x1001 +// CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: VirtualAddress: 0x201001 // CHECK-NEXT: PhysicalAddress: 0x201001 // CHECK-NEXT: FileSize: 0 Index: test/ELF/basic-aarch64.s =================================================================== --- test/ELF/basic-aarch64.s +++ test/ELF/basic-aarch64.s @@ -26,7 +26,7 @@ # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: [[ENTRY:0x[0-9A-F]+]] # CHECK-NEXT: ProgramHeaderOffset: 0x40 -# CHECK-NEXT: SectionHeaderOffset: 0x10098 +# CHECK-NEXT: SectionHeaderOffset: 0x11088 # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 64 @@ -76,7 +76,7 @@ # CHECK-NEXT: SHF_STRINGS (0x20) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1000C +# CHECK-NEXT: Offset: 0x11000 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -90,7 +90,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x10018 +# CHECK-NEXT: Offset: 0x11008 # CHECK-NEXT: Size: 72 # CHECK-NEXT: Link: 5 # CHECK-NEXT: Info: 2 @@ -104,7 +104,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x10060 +# CHECK-NEXT: Offset: 0x11050 # CHECK-NEXT: Size: 42 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -118,7 +118,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1008A +# CHECK-NEXT: Offset: 0x1107A # CHECK-NEXT: Size: 13 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -185,7 +185,7 @@ # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x20000 # CHECK-NEXT: PhysicalAddress: 0x20000 -# CHECK-NEXT: FileSize: 12 +# CHECK-NEXT: FileSize: 4096 # CHECK-NEXT: MemSize: 12 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4) Index: test/ELF/basic.s =================================================================== --- test/ELF/basic.s +++ test/ELF/basic.s @@ -28,7 +28,7 @@ # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: [[ENTRY:0x[0-9A-F]+]] # CHECK-NEXT: ProgramHeaderOffset: 0x40 -# CHECK-NEXT: SectionHeaderOffset: 0x1080 +# CHECK-NEXT: SectionHeaderOffset: 0x2070 # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 64 @@ -78,7 +78,7 @@ # CHECK-NEXT: SHF_STRINGS (0x20) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1010 +# CHECK-NEXT: Offset: 0x2000 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -92,7 +92,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1018 +# CHECK-NEXT: Offset: 0x2008 # CHECK-NEXT: Size: 48 # CHECK-NEXT: Link: 5 # CHECK-NEXT: Info: 1 @@ -106,7 +106,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1048 +# CHECK-NEXT: Offset: 0x2038 # CHECK-NEXT: Size: 42 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -120,7 +120,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1072 +# CHECK-NEXT: Offset: 0x2062 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -178,7 +178,7 @@ # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x201000 # CHECK-NEXT: PhysicalAddress: 0x201000 -# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: FileSize: 4096 # CHECK-NEXT: MemSize: 16 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4) Index: test/ELF/basic32.s =================================================================== --- test/ELF/basic32.s +++ test/ELF/basic32.s @@ -25,7 +25,7 @@ # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: 0x11000 # CHECK-NEXT: ProgramHeaderOffset: 0x34 -# CHECK-NEXT: SectionHeaderOffset: 0x1068 +# CHECK-NEXT: SectionHeaderOffset: 0x205C # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 52 @@ -75,7 +75,7 @@ # CHECK-NEXT: SHF_STRINGS (0x20) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x100C +# CHECK-NEXT: Offset: 0x2000 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -89,7 +89,7 @@ # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1014 +# CHECK-NEXT: Offset: 0x2008 # CHECK-NEXT: Size: 32 # CHECK-NEXT: Link: 5 # CHECK-NEXT: Info: 1 @@ -103,7 +103,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1034 +# CHECK-NEXT: Offset: 0x2028 # CHECK-NEXT: Size: 42 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -117,7 +117,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x105E +# CHECK-NEXT: Offset: 0x2052 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -155,7 +155,7 @@ # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x11000 # CHECK-NEXT: PhysicalAddress: 0x11000 -# CHECK-NEXT: FileSize: 12 +# CHECK-NEXT: FileSize: 4096 # CHECK-NEXT: MemSize: 12 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4) Index: test/ELF/build-id.s =================================================================== --- test/ELF/build-id.s +++ test/ELF/build-id.s @@ -48,15 +48,15 @@ # DEFAULT: Contents of section .note.test: # DEFAULT: Contents of section .note.gnu.build-id: # DEFAULT-NEXT: 04000000 08000000 03000000 474e5500 ............GNU. -# DEFAULT-NEXT: fd36edb1 f6ff02af +# DEFAULT-NEXT: b0148597 ba5eb7e9 # MD5: Contents of section .note.gnu.build-id: # MD5-NEXT: 04000000 10000000 03000000 474e5500 ............GNU. -# MD5-NEXT: fc +# MD5-NEXT: 19 # SHA1: Contents of section .note.gnu.build-id: # SHA1-NEXT: 04000000 14000000 03000000 474e5500 ............GNU. -# SHA1-NEXT: 55b1eedb 03b588e1 09987d1d e9a79be7 +# SHA1-NEXT: 2f716666 fe3668fe 370a02a1 579c3eb2 # UUID: Contents of section .note.gnu.build-id: # UUID-NEXT: 04000000 10000000 03000000 474e5500 ............GNU. Index: test/ELF/image-base.s =================================================================== --- test/ELF/image-base.s +++ test/ELF/image-base.s @@ -41,7 +41,7 @@ # CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1001000 # CHECK-NEXT: PhysicalAddress: 0x1001000 -# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: FileSize: 4096 # CHECK-NEXT: MemSize: 1 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4)