Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -228,8 +228,9 @@ unsigned getNumSections() const { return OutputSections.size() + 1; } uintX_t FileSize; - uintX_t SizeOfHeaders; + uintX_t ProgramHeaderOff; uintX_t SectionHeaderOff; + unsigned NumPhdrs; StringTableSection StrTabSec; StringTableSection DynStrSec; @@ -556,17 +557,34 @@ OutputSections[I]->setSectionIndex(I + 1); } +template +static bool outputSectionHasPHDR(OutputSectionBase *Sec) { + return (Sec->getSize() != 0) && (Sec->getFlags() & SHF_ALLOC); +} + // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. template void Writer::assignAddresses() { - SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr), PageSize); uintX_t VA = 0x1000; // The first page is kept unmapped. - uintX_t FileOff = SizeOfHeaders; + uintX_t FileOff = sizeof(Elf_Ehdr); + + // Reserve space for PHDRs. + ProgramHeaderOff = FileOff; + FileOff = RoundUpToAlignment(FileOff, PageSize); + NumPhdrs = 0; 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); + } + uintX_t Align = Sec->getAlign(); uintX_t Size = Sec->getSize(); if (Sec->getFlags() & SHF_ALLOC) { @@ -578,15 +596,19 @@ FileOff += RoundUpToAlignment(Size, Align); } + // Add a PHDR for the dynamic table. + if (!SymTable.getSymTable().getSharedFiles().empty()) + ++NumPhdrs; + FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); // Add space for section headers. SectionHeaderOff = FileOff; FileOff += getNumSections() * sizeof(Elf_Shdr); - FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8); + FileSize = FileOff; } -static uint32_t convertSectionFlagsToSegmentFlags(uint64_t Flags) { +static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) { uint32_t Ret = PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; @@ -613,42 +635,41 @@ // FIXME: Generalize the segment construction similar to how we create // output sections. - unsigned NumSegments = 1; const SymbolTable &Symtab = SymTable.getSymTable(); - const std::vector> &SharedFiles = - Symtab.getSharedFiles(); - bool HasDynamicSegment = !SharedFiles.empty(); - if (HasDynamicSegment) - NumSegments++; + bool HasDynamicSegment = !Symtab.getSharedFiles().empty(); EHdr->e_type = ET_EXEC; auto &FirstObj = cast>(*Symtab.getFirstELF()); EHdr->e_machine = FirstObj.getEMachine(); EHdr->e_version = EV_CURRENT; EHdr->e_entry = getSymVA(cast>(Symtab.getEntrySym())); - EHdr->e_phoff = sizeof(Elf_Ehdr); + EHdr->e_phoff = ProgramHeaderOff; EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); - EHdr->e_phnum = NumSegments; + EHdr->e_phnum = NumPhdrs; EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = getNumSections(); EHdr->e_shstrndx = StrTabSec.getSectionIndex(); auto PHdrs = reinterpret_cast(Buf + EHdr->e_phoff); - PHdrs->p_type = PT_LOAD; - PHdrs->p_flags = PF_R | PF_X; - PHdrs->p_offset = 0x0000; - PHdrs->p_vaddr = 0x1000; - PHdrs->p_paddr = PHdrs->p_vaddr; - PHdrs->p_filesz = FileSize; - PHdrs->p_memsz = FileSize; - PHdrs->p_align = 0x4000; + 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 (HasDynamicSegment) { - PHdrs++; PHdrs->p_type = PT_DYNAMIC; - PHdrs->p_flags = convertSectionFlagsToSegmentFlags(DynamicSec.getFlags()); + PHdrs->p_flags = convertSectionFlagsToPHDRFlags(DynamicSec.getFlags()); PHdrs->p_offset = DynamicSec.getFileOff(); PHdrs->p_vaddr = DynamicSec.getVA(); PHdrs->p_paddr = PHdrs->p_vaddr; Index: test/elf2/basic.s =================================================================== --- test/elf2/basic.s +++ test/elf2/basic.s @@ -151,16 +151,16 @@ # CHECK-NEXT: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1000 # CHECK-NEXT: PhysicalAddress: 0x1000 -# CHECK-NEXT: FileSize: 4592 -# CHECK-NEXT: MemSize: 4592 +# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: MemSize: 16 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: PF_X (0x1) # CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 16384 +# CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } # CHECK-NEXT: ] Index: test/elf2/basic32.s =================================================================== --- test/elf2/basic32.s +++ test/elf2/basic32.s @@ -130,15 +130,15 @@ # CHECK-NEXT: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1000 # CHECK-NEXT: PhysicalAddress: 0x1000 -# CHECK-NEXT: FileSize: 4424 -# CHECK-NEXT: MemSize: 4424 +# 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: 16384 +# CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } # CHECK-NEXT: ] Index: test/elf2/basic32be.s =================================================================== --- test/elf2/basic32be.s +++ test/elf2/basic32be.s @@ -130,15 +130,15 @@ # CHECK-NEXT: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Offset: 0x1000 # CHECK-NEXT: VirtualAddress: 0x1000 # CHECK-NEXT: PhysicalAddress: 0x1000 -# CHECK-NEXT: FileSize: 4424 -# CHECK-NEXT: MemSize: 4424 +# 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: 16384 +# CHECK-NEXT: Alignment: 4096 # CHECK-NEXT: } # CHECK-NEXT: ] Index: test/elf2/basic64be.s =================================================================== --- test/elf2/basic64be.s +++ test/elf2/basic64be.s @@ -28,14 +28,14 @@ # CHECK-NEXT: Type: Executable (0x2) # CHECK-NEXT: Machine: EM_PPC64 (0x15) # CHECK-NEXT: Version: 1 -# CHECK-NEXT: Entry: 0x100C +# CHECK-NEXT: Entry: 0x2000 # CHECK-NEXT: ProgramHeaderOffset: 0x40 -# CHECK-NEXT: SectionHeaderOffset: 0x1088 +# CHECK-NEXT: SectionHeaderOffset: 0x2078 # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 64 # CHECK-NEXT: ProgramHeaderEntrySize: 56 -# CHECK-NEXT: ProgramHeaderCount: 1 +# CHECK-NEXT: ProgramHeaderCount: 2 # CHECK-NEXT: SectionHeaderEntrySize: 64 # CHECK-NEXT: SectionHeaderCount: 7 # CHECK-NEXT: StringTableSectionIndex: 6 @@ -111,8 +111,8 @@ # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: SHF_WRITE (0x1) # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x100C -# CHECK-NEXT: Offset: 0x100C +# CHECK-NEXT: Address: 0x2000 +# CHECK-NEXT: Offset: 0x2000 # CHECK-NEXT: Size: 24 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -126,7 +126,7 @@ # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1024 +# CHECK-NEXT: Offset: 0x2018 # CHECK-NEXT: Size: 48 # CHECK-NEXT: Link: 6 # CHECK-NEXT: Info: 1 @@ -140,7 +140,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1054 +# CHECK-NEXT: Offset: 0x2048 # CHECK-NEXT: Size: 46 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -149,17 +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: 0x1000 -# CHECK-NEXT: PhysicalAddress: 0x1000 -# CHECK-NEXT: FileSize: 4680 -# CHECK-NEXT: MemSize: 4680 -# CHECK-NEXT: Flags [ (0x5) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: PF_X (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 16384 -# CHECK-NEXT: } -# CHECK-NEXT: ] +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# 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) +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x2000 +# CHECK-NEXT: FileSize: 24 +# CHECK-NEXT: MemSize: 24 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT:] Index: test/elf2/relocation.s =================================================================== --- test/elf2/relocation.s +++ test/elf2/relocation.s @@ -26,4 +26,4 @@ // CHECK: e8 04 00 00 00 callq 4 // Also check that symbols match. -// CHECK: 0000000000001000 .text 00000000 bar +// CHECK: 000000000001000 .text 00000000 bar Index: test/elf2/symbols.s =================================================================== --- test/elf2/symbols.s +++ test/elf2/symbols.s @@ -59,8 +59,8 @@ // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: SHF_WRITE (0x1) // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1004 -// CHECK-NEXT: Offset: 0x1004 +// CHECK-NEXT: Address: 0x2000 +// CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: Size: 4 // CHECK: Name: foobar @@ -68,7 +68,7 @@ // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1008 +// CHECK-NEXT: Address: 0x3000 // CHECK: Symbols [ // CHECK-NEXT: Symbol { @@ -118,7 +118,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: common (34) -// CHECK-NEXT: Value: 0x1004 +// CHECK-NEXT: Value: 0x2000 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Binding: Global (0x1) // CHECK-NEXT: Type: Object (0x1) @@ -127,7 +127,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: zed -// CHECK-NEXT: Value: 0x1008 +// CHECK-NEXT: Value: 0x3000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) // CHECK-NEXT: Type: None @@ -136,7 +136,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: protected -// CHECK-NEXT: Value: 0x1010 +// CHECK-NEXT: Value: 0x3008 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: None @@ -145,7 +145,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: zed3 -// CHECK-NEXT: Value: 0x1010 +// CHECK-NEXT: Value: 0x3008 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: None @@ -154,7 +154,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: zed2 -// CHECK-NEXT: Value: 0x100C +// CHECK-NEXT: Value: 0x3004 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: None