[lld] r247925 - [elf2] Combine adjacent compatible OutputSections in PT_LOADs.
Michael J. Spencer via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 17 12:58:07 PDT 2015
Author: mspencer
Date: Thu Sep 17 14:58:07 2015
New Revision: 247925
URL: http://llvm.org/viewvc/llvm-project?rev=247925&view=rev
Log:
[elf2] Combine adjacent compatible OutputSections in PT_LOADs.
Added:
lld/trunk/test/elf2/program-header-layout.s
Modified:
lld/trunk/ELF/Writer.cpp
lld/trunk/test/elf2/dynamic-reloc.s
lld/trunk/test/elf2/relocation.s
lld/trunk/test/elf2/shared.s
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Sep 17 14:58:07 2015
@@ -446,6 +446,57 @@ private:
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 <bool Is64Bits>
+class ProgramHeader {
+public:
+ typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+ typedef
+ typename std::conditional<Is64Bits, Elf64_Phdr, Elf32_Phdr>::type HeaderT;
+
+ ProgramHeader(uintX_t p_type, uintX_t p_flags) {
+ std::memset(&Header, 0, sizeof(HeaderT));
+ Header.p_type = p_type;
+ Header.p_flags = p_flags;
+ Header.p_align = PageSize;
+ }
+
+ void setValuesFromSection(OutputSectionBase<Is64Bits> &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 <endianness E>
+ void writeHeaderTo(typename ELFFile<ELFType<E, Is64Bits>>::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;
+ }
+
+ HeaderT Header;
+ bool Closed = false;
+};
+
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
@@ -487,14 +538,20 @@ private:
unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; }
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
std::vector<OutputSectionBase<ELFT::Is64Bits> *> OutputSections;
unsigned getNumSections() const { return OutputSections.size() + 1; }
+ llvm::BumpPtrAllocator PAlloc;
+ std::vector<ProgramHeader<ELFT::Is64Bits> *> PHDRs;
+ ProgramHeader<ELFT::Is64Bits> FileHeaderPHDR{PT_LOAD, PF_R};
+ ProgramHeader<ELFT::Is64Bits> InterpPHDR{PT_INTERP, 0};
+ ProgramHeader<ELFT::Is64Bits> DynamicPHDR{PT_DYNAMIC, 0};
+
uintX_t FileSize;
uintX_t ProgramHeaderOff;
uintX_t SectionHeaderOff;
- unsigned NumPhdrs;
StringTableSection<ELFT::Is64Bits> StrTabSec = { /*dynamic=*/false };
StringTableSection<ELFT::Is64Bits> DynStrSec = { /*dynamic=*/true };
@@ -950,12 +1007,13 @@ template <class ELFT> void Writer<ELFT>:
template <class ELFT>
static bool outputSectionHasPHDR(OutputSectionBase<ELFT::Is64Bits> *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 <class ELFT> void Writer<ELFT>::assignAddresses() {
+ assert(!OutputSections.empty() && "No output sections to layout!");
uintX_t VA = getVAStart();
uintX_t FileOff = 0;
@@ -967,26 +1025,41 @@ template <class ELFT> void Writer<ELFT>:
FileOff = RoundUpToAlignment(FileOff, PageSize);
VA = RoundUpToAlignment(VA, PageSize);
- NumPhdrs = 0;
-
- // Add a PHDR for PT_INTERP.
if (needsInterpSection())
- ++NumPhdrs;
+ PHDRs.push_back(&InterpPHDR);
- // 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;
+ ProgramHeader<ELFT::Is64Bits> *LastPHDR = &FileHeaderPHDR;
+ // Create a PHDR for the file header.
+ PHDRs.push_back(&FileHeaderPHDR);
+ FileHeaderPHDR.Header.p_vaddr = getVAStart();
+ FileHeaderPHDR.Header.p_paddr = getVAStart();
+ FileHeaderPHDR.Header.p_align = PageSize;
for (OutputSectionBase<ELFT::Is64Bits> *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<ELFT>(Sec)) {
- ++NumPhdrs;
- VA = RoundUpToAlignment(VA, PageSize);
- FileOff = RoundUpToAlignment(FileOff, PageSize);
+ if (Sec->getSize()) {
+ uintX_t Flags = convertSectionFlagsToPHDRFlags(Sec->getFlags());
+ if (LastPHDR->Header.p_flags != Flags ||
+ !outputSectionHasPHDR<ELFT>(Sec)) {
+ // Flags changed. End current PHDR and potentially create a new one.
+ if (!LastPHDR->Closed) {
+ LastPHDR->Header.p_filesz = FileOff - LastPHDR->Header.p_offset;
+ LastPHDR->Header.p_memsz = VA - LastPHDR->Header.p_vaddr;
+ LastPHDR->Closed = true;
+ }
+
+ if (outputSectionHasPHDR<ELFT>(Sec)) {
+ LastPHDR = new (PAlloc) ProgramHeader<ELFT::Is64Bits>(PT_LOAD, Flags);
+ PHDRs.push_back(LastPHDR);
+ VA = RoundUpToAlignment(VA, PageSize);
+ FileOff = RoundUpToAlignment(FileOff, PageSize);
+ LastPHDR->Header.p_offset = FileOff;
+ LastPHDR->Header.p_vaddr = VA;
+ LastPHDR->Header.p_paddr = VA;
+ }
+ }
}
uintX_t Align = Sec->getAlign();
@@ -1004,7 +1077,7 @@ template <class ELFT> void Writer<ELFT>:
// Add a PHDR for the dynamic table.
if (needsDynamicSections())
- ++NumPhdrs;
+ PHDRs.push_back(&DynamicPHDR);
FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
@@ -1014,29 +1087,6 @@ template <class ELFT> void Writer<ELFT>:
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 <class ELFT>
-static void setValuesFromSection(typename ELFFile<ELFT>::Elf_Phdr &P,
- OutputSectionBase<ELFT::Is64Bits> &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 <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
@@ -1065,46 +1115,24 @@ template <class ELFT> void Writer<ELFT>:
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<Elf_Phdr *>(Buf + EHdr->e_phoff);
- if (needsInterpSection()) {
- PHdrs->p_type = PT_INTERP;
- setValuesFromSection<ELFT>(*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;
+ // If nothing was merged into the file header PT_LOAD, set the size correctly.
+ if (FileHeaderPHDR.Header.p_filesz == PageSize)
+ FileHeaderPHDR.Header.p_filesz = FileHeaderPHDR.Header.p_memsz =
+ sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * PHDRs.size();
- for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections) {
- if (!outputSectionHasPHDR<ELFT>(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<ELFT>(*PHdrs, DynamicSec);
- }
+ auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+ for (ProgramHeader<ELFT::Is64Bits> *PHDR : PHDRs)
+ PHDR->template writeHeaderTo<ELFT::TargetEndianness>(PHdrs++);
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
// First entry is null.
Modified: lld/trunk/test/elf2/dynamic-reloc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/dynamic-reloc.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/dynamic-reloc.s (original)
+++ lld/trunk/test/elf2/dynamic-reloc.s Thu Sep 17 14:58:07 2015
@@ -22,7 +22,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: ]
// CHECK-NEXT: Address: [[RELAADDR:.*]]
-// CHECK-NEXT: Offset: 0x6000
+// CHECK-NEXT: Offset: 0x4058
// CHECK-NEXT: Size: [[RELASIZE:.*]]
// CHECK-NEXT: Link: 4
// CHECK-NEXT: Info: 0
Added: lld/trunk/test/elf2/program-header-layout.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/program-header-layout.s?rev=247925&view=auto
==============================================================================
--- lld/trunk/test/elf2/program-header-layout.s (added)
+++ lld/trunk/test/elf2/program-header-layout.s Thu Sep 17 14:58:07 2015
@@ -0,0 +1,46 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: lld -flavor gnu2 %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# Check that different output sections with the same flags are merged into a
+# single Read/Write PT_LOAD.
+
+.section .r,"a"
+.globl _start
+_start:
+.quad 0
+
+.section .a,"aw"
+.quad 1
+
+.section .b,"aw"
+.quad 2
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize:
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment:
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize: 16
+# CHECK-NEXT: MemSize: 16
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_W
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment:
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
Modified: lld/trunk/test/elf2/relocation.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/relocation.s (original)
+++ lld/trunk/test/elf2/relocation.s Thu Sep 17 14:58:07 2015
@@ -33,7 +33,7 @@ R_X86_64_32:
// constants in hex.
// CHECK: Disassembly of section .text2:
// CHECK-NEXT: R_X86_64_32:
-// CHECK-NEXT: 12000: {{.*}} movl $73728, %edx
+// CHECK-NEXT: 1100c: {{.*}} movl $69644, %edx
.section .R_X86_64_32S,"ax", at progbits
.global R_X86_64_32S
@@ -50,4 +50,4 @@ R_X86_64_64:
.quad R_X86_64_64
// CHECK: Contents of section .R_X86_64_64:
-// CHECK-NEXT: 14000 00400100 00000000
+// CHECK-NEXT: 12000 00200100 00000000
Modified: lld/trunk/test/elf2/shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/shared.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/shared.s (original)
+++ lld/trunk/test/elf2/shared.s Thu Sep 17 14:58:07 2015
@@ -12,7 +12,7 @@
// SO-NEXT: Flags [
// SO-NEXT: ]
// SO-NEXT: Address:
-// SO-NEXT: Offset: 0x400C
+// SO-NEXT: Offset: 0x300C
// SO-NEXT: Size:
// SO-NEXT: Link:
// SO-NEXT: Info:
@@ -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
More information about the llvm-commits
mailing list