Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -362,6 +362,61 @@ SymbolTable &SymTab; }; +static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) { + uint32_t Ret = PF_R; + if (Flags & SHF_WRITE) + Ret |= PF_W; + + if (Flags & SHF_EXECINSTR) + Ret |= PF_X; + + return Ret; +} + +template +class ProgramHeader { +public: + typedef typename std::conditional::type uintX_t; + typedef + typename std::conditional::type HeaderT; + + ProgramHeader(uintX_t p_type, uintX_t p_flags) : Closed(false) { + std::memset(&Header, 0, sizeof(HeaderT)); + Header.p_type = p_type; + Header.p_flags = p_flags; + Header.p_align = PageSize; + } + + HeaderT &getHeader() { return Header; } + + void setValuesFromSection(OutputSectionBase &Sec) { + Header.p_flags = convertSectionFlagsToPHDRFlags(Sec.getFlags()); + Header.p_offset = Sec.getFileOff(); + Header.p_vaddr = Sec.getVA(); + Header.p_paddr = Header.p_vaddr; + Header.p_filesz = Sec.getSize(); + Header.p_memsz = Header.p_filesz; + Header.p_align = Sec.getAlign(); + } + + template + void writeHeaderTo(typename ELFFile>::Elf_Phdr *PHDR) { + PHDR->p_type = Header.p_type; + PHDR->p_flags = Header.p_flags; + PHDR->p_offset = Header.p_offset; + PHDR->p_vaddr = Header.p_vaddr; + PHDR->p_paddr = Header.p_paddr; + PHDR->p_filesz = Header.p_filesz; + PHDR->p_memsz = Header.p_memsz; + PHDR->p_align = Header.p_align; + } + + bool Closed; + +protected: + HeaderT Header; +}; + // The writer writes a SymbolTable result to a file. template class Writer { public: @@ -396,14 +451,20 @@ unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; } std::unique_ptr Buffer; + llvm::SpecificBumpPtrAllocator> CAlloc; std::vector *> OutputSections; unsigned getNumSections() const { return OutputSections.size() + 1; } + llvm::BumpPtrAllocator PAlloc; + std::vector *> PHDRs; + ProgramHeader FileHeaderPHDR{PT_LOAD, PF_R}; + ProgramHeader InterpPHDR{PT_INTERP, 0}; + ProgramHeader DynamicPHDR{PT_DYNAMIC, 0}; + uintX_t FileSize; uintX_t ProgramHeaderOff; uintX_t SectionHeaderOff; - unsigned NumPhdrs; StringTableSection StrTabSec = { /*dynamic=*/false }; StringTableSection DynStrSec = { /*dynamic=*/true }; @@ -744,12 +805,13 @@ template static bool outputSectionHasPHDR(OutputSectionBase *Sec) { - return (Sec->getSize() != 0) && (Sec->getFlags() & SHF_ALLOC); + return Sec->getFlags() & SHF_ALLOC; } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. template void Writer::assignAddresses() { + assert(!OutputSections.empty() && "No output sections to layout!"); uintX_t VA = getVAStart(); uintX_t FileOff = 0; @@ -761,26 +823,51 @@ FileOff = RoundUpToAlignment(FileOff, PageSize); VA = RoundUpToAlignment(VA, PageSize); - NumPhdrs = 0; - - // Add a PHDR for PT_INTERP. if (needsInterpSection()) - ++NumPhdrs; + PHDRs.push_back(&InterpPHDR); + + // Create a PHDR for the file header. + PHDRs.push_back(&FileHeaderPHDR); + typename ProgramHeader::HeaderT *PHDR = + &FileHeaderPHDR.getHeader(); + PHDR->p_vaddr = getVAStart(); + PHDR->p_paddr = PHDR->p_vaddr; + PHDR->p_align = PageSize; - // Add a PHDR for the elf header and program headers. Some dynamic linkers - // (musl at least) require them to be covered by a PT_LOAD. - ++NumPhdrs; + // Create a PHDR for the first output section. + PHDRs.push_back(new (PAlloc) ProgramHeader( + PT_LOAD, convertSectionFlagsToPHDRFlags(OutputSections[0]->getFlags()))); + + PHDR = &PHDRs.back()->getHeader(); + PHDR->p_offset = FileOff; + PHDR->p_vaddr = VA; + PHDR->p_paddr = PHDR->p_vaddr; for (OutputSectionBase *Sec : OutputSections) { StrTabSec.add(Sec->getName()); Sec->finalize(); - // Since each output section gets its own PHDR, align each output section to - // a page. - if (outputSectionHasPHDR(Sec)) { - ++NumPhdrs; - VA = RoundUpToAlignment(VA, PageSize); - FileOff = RoundUpToAlignment(FileOff, PageSize); + if (Sec->getSize()) { + uintX_t Flags = convertSectionFlagsToPHDRFlags(Sec->getFlags()); + if (PHDR->p_flags != Flags || !outputSectionHasPHDR(Sec)) { + // Flags changed. End current PHDR and potentially create a new one. + if (!PHDRs.back()->Closed) { + PHDR->p_filesz = FileOff - PHDR->p_offset; + PHDR->p_memsz = VA - PHDR->p_vaddr; + PHDRs.back()->Closed = true; + } + + if (outputSectionHasPHDR(Sec)) { + PHDRs.push_back(new (PAlloc) + ProgramHeader(PT_LOAD, Flags)); + VA = RoundUpToAlignment(VA, PageSize); + FileOff = RoundUpToAlignment(FileOff, PageSize); + PHDR = &PHDRs.back()->getHeader(); + PHDR->p_offset = FileOff; + PHDR->p_vaddr = VA; + PHDR->p_paddr = PHDR->p_vaddr; + } + } } uintX_t Align = Sec->getAlign(); @@ -798,7 +885,7 @@ // Add a PHDR for the dynamic table. if (needsDynamicSections()) - ++NumPhdrs; + PHDRs.push_back(&DynamicPHDR); FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); @@ -808,29 +895,6 @@ FileSize = FileOff; } -static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) { - uint32_t Ret = PF_R; - if (Flags & SHF_WRITE) - Ret |= PF_W; - - if (Flags & SHF_EXECINSTR) - Ret |= PF_X; - - return Ret; -} - -template -static void setValuesFromSection(typename ELFFile::Elf_Phdr &P, - OutputSectionBase &S) { - P.p_flags = convertSectionFlagsToPHDRFlags(S.getFlags()); - P.p_offset = S.getFileOff(); - P.p_vaddr = S.getVA(); - P.p_paddr = P.p_vaddr; - P.p_filesz = S.getSize(); - P.p_memsz = P.p_filesz; - P.p_align = S.getAlign(); -} - template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); auto *EHdr = reinterpret_cast(Buf); @@ -859,46 +923,22 @@ EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); - EHdr->e_phnum = NumPhdrs; + EHdr->e_phnum = PHDRs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = getNumSections(); EHdr->e_shstrndx = StrTabSec.getSectionIndex(); - auto PHdrs = reinterpret_cast(Buf + EHdr->e_phoff); - if (needsInterpSection()) { - PHdrs->p_type = PT_INTERP; - setValuesFromSection(*PHdrs, InterpSec); - ++PHdrs; - } - - PHdrs->p_type = PT_LOAD; - PHdrs->p_flags = PF_R; - PHdrs->p_offset = 0; - PHdrs->p_vaddr = getVAStart(); - PHdrs->p_paddr = PHdrs->p_vaddr; - PHdrs->p_filesz = ProgramHeaderOff + NumPhdrs * sizeof(Elf_Phdr); - PHdrs->p_memsz = PHdrs->p_filesz; - PHdrs->p_align = PageSize; - ++PHdrs; + FileHeaderPHDR.getHeader().p_filesz = FileHeaderPHDR.getHeader().p_memsz = + sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * PHDRs.size(); - for (OutputSectionBase *Sec : OutputSections) { - if (!outputSectionHasPHDR(Sec)) - continue; - PHdrs->p_type = PT_LOAD; - PHdrs->p_flags = convertSectionFlagsToPHDRFlags(Sec->getFlags()); - PHdrs->p_offset = Sec->getFileOff(); - PHdrs->p_vaddr = Sec->getVA(); - PHdrs->p_paddr = PHdrs->p_vaddr; - PHdrs->p_filesz = Sec->getType() == SHT_NOBITS ? 0 : Sec->getSize(); - PHdrs->p_memsz = Sec->getSize(); - PHdrs->p_align = PageSize; - ++PHdrs; - } + if (needsInterpSection()) + InterpPHDR.setValuesFromSection(InterpSec); + if (needsDynamicSections()) + DynamicPHDR.setValuesFromSection(DynamicSec); - if (needsDynamicSections()) { - PHdrs->p_type = PT_DYNAMIC; - setValuesFromSection(*PHdrs, DynamicSec); - } + auto PHdrs = reinterpret_cast(Buf + EHdr->e_phoff); + for (ProgramHeader *PHDR : PHDRs) + PHDR->template writeHeaderTo(PHdrs++); auto SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); // First entry is null. Index: test/elf2/basic.s =================================================================== --- test/elf2/basic.s +++ test/elf2/basic.s @@ -156,8 +156,8 @@ # CHECK-NEXT: PhysicalAddress: 0x10000 # CHECK-NEXT: FileSize: 176 # CHECK-NEXT: MemSize: 176 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } Index: test/elf2/basic32.s =================================================================== --- test/elf2/basic32.s +++ test/elf2/basic32.s @@ -135,8 +135,8 @@ # CHECK-NEXT: PhysicalAddress: 0x10000 # CHECK-NEXT: FileSize: 116 # CHECK-NEXT: MemSize: 116 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } Index: test/elf2/basic32be.s =================================================================== --- test/elf2/basic32be.s +++ test/elf2/basic32be.s @@ -135,8 +135,8 @@ # CHECK-NEXT: PhysicalAddress: 0x10000 # CHECK-NEXT: FileSize: 116 # CHECK-NEXT: MemSize: 116 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } Index: test/elf2/basic64be.s =================================================================== --- test/elf2/basic64be.s +++ test/elf2/basic64be.s @@ -149,30 +149,30 @@ # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: ProgramHeaders [ -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x10000 -# CHECK-NEXT: PhysicalAddress: 0x10000 -# CHECK-NEXT: FileSize: 232 -# CHECK-NEXT: MemSize: 232 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 4096 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x1000 -# CHECK-NEXT: VirtualAddress: 0x11000 -# CHECK-NEXT: PhysicalAddress: 0x11000 -# CHECK-NEXT: FileSize: 12 -# CHECK-NEXT: MemSize: 12 -# CHECK-NEXT: Flags [ (0x5) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: PF_X (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x10000 +# CHECK-NEXT: PhysicalAddress: 0x10000 +# CHECK-NEXT: FileSize: 232 +# CHECK-NEXT: MemSize: 232 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x11000 +# CHECK-NEXT: PhysicalAddress: 0x11000 +# CHECK-NEXT: FileSize: 12 +# CHECK-NEXT: MemSize: 12 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) Index: test/elf2/shared.s =================================================================== --- test/elf2/shared.s +++ test/elf2/shared.s @@ -44,7 +44,7 @@ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: ] // CHECK-NEXT: Address: [[DYNSYMADDR:.*]] -// CHECK-NEXT: Offset: 0x3000 +// CHECK-NEXT: Offset: 0x201C // CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: [[DYNSTR:.*]] // CHECK-NEXT: Info: 1