[elf2] Combine adjacent compatible OutputSections in PT_LOADs.
llvm-svn: 247925
This commit is contained in:
parent
d6e597c2be
commit
2f0082424f
|
@ -446,6 +446,57 @@ private:
|
||||||
SymbolTable &SymTab;
|
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.
|
// The writer writes a SymbolTable result to a file.
|
||||||
template <class ELFT> class Writer {
|
template <class ELFT> class Writer {
|
||||||
public:
|
public:
|
||||||
|
@ -487,14 +538,20 @@ private:
|
||||||
unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; }
|
unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; }
|
||||||
|
|
||||||
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
|
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
|
||||||
|
|
||||||
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
|
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
|
||||||
std::vector<OutputSectionBase<ELFT::Is64Bits> *> OutputSections;
|
std::vector<OutputSectionBase<ELFT::Is64Bits> *> OutputSections;
|
||||||
unsigned getNumSections() const { return OutputSections.size() + 1; }
|
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 FileSize;
|
||||||
uintX_t ProgramHeaderOff;
|
uintX_t ProgramHeaderOff;
|
||||||
uintX_t SectionHeaderOff;
|
uintX_t SectionHeaderOff;
|
||||||
unsigned NumPhdrs;
|
|
||||||
|
|
||||||
StringTableSection<ELFT::Is64Bits> StrTabSec = { /*dynamic=*/false };
|
StringTableSection<ELFT::Is64Bits> StrTabSec = { /*dynamic=*/false };
|
||||||
StringTableSection<ELFT::Is64Bits> DynStrSec = { /*dynamic=*/true };
|
StringTableSection<ELFT::Is64Bits> DynStrSec = { /*dynamic=*/true };
|
||||||
|
@ -950,12 +1007,13 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
static bool outputSectionHasPHDR(OutputSectionBase<ELFT::Is64Bits> *Sec) {
|
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
|
// Visits all sections to assign incremental, non-overlapping RVAs and
|
||||||
// file offsets.
|
// file offsets.
|
||||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
|
assert(!OutputSections.empty() && "No output sections to layout!");
|
||||||
uintX_t VA = getVAStart();
|
uintX_t VA = getVAStart();
|
||||||
uintX_t FileOff = 0;
|
uintX_t FileOff = 0;
|
||||||
|
|
||||||
|
@ -967,26 +1025,41 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
FileOff = RoundUpToAlignment(FileOff, PageSize);
|
FileOff = RoundUpToAlignment(FileOff, PageSize);
|
||||||
VA = RoundUpToAlignment(VA, PageSize);
|
VA = RoundUpToAlignment(VA, PageSize);
|
||||||
|
|
||||||
NumPhdrs = 0;
|
|
||||||
|
|
||||||
// Add a PHDR for PT_INTERP.
|
|
||||||
if (needsInterpSection())
|
if (needsInterpSection())
|
||||||
++NumPhdrs;
|
PHDRs.push_back(&InterpPHDR);
|
||||||
|
|
||||||
// Add a PHDR for the elf header and program headers. Some dynamic linkers
|
ProgramHeader<ELFT::Is64Bits> *LastPHDR = &FileHeaderPHDR;
|
||||||
// (musl at least) require them to be covered by a PT_LOAD.
|
// Create a PHDR for the file header.
|
||||||
++NumPhdrs;
|
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) {
|
for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections) {
|
||||||
StrTabSec.add(Sec->getName());
|
StrTabSec.add(Sec->getName());
|
||||||
Sec->finalize();
|
Sec->finalize();
|
||||||
|
|
||||||
// Since each output section gets its own PHDR, align each output section to
|
if (Sec->getSize()) {
|
||||||
// a page.
|
uintX_t Flags = convertSectionFlagsToPHDRFlags(Sec->getFlags());
|
||||||
if (outputSectionHasPHDR<ELFT>(Sec)) {
|
if (LastPHDR->Header.p_flags != Flags ||
|
||||||
++NumPhdrs;
|
!outputSectionHasPHDR<ELFT>(Sec)) {
|
||||||
VA = RoundUpToAlignment(VA, PageSize);
|
// Flags changed. End current PHDR and potentially create a new one.
|
||||||
FileOff = RoundUpToAlignment(FileOff, PageSize);
|
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();
|
uintX_t Align = Sec->getAlign();
|
||||||
|
@ -1004,7 +1077,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
|
|
||||||
// Add a PHDR for the dynamic table.
|
// Add a PHDR for the dynamic table.
|
||||||
if (needsDynamicSections())
|
if (needsDynamicSections())
|
||||||
++NumPhdrs;
|
PHDRs.push_back(&DynamicPHDR);
|
||||||
|
|
||||||
FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
|
FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
|
||||||
|
|
||||||
|
@ -1014,29 +1087,6 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
FileSize = FileOff;
|
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() {
|
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
uint8_t *Buf = Buffer->getBufferStart();
|
||||||
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
|
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
|
||||||
|
@ -1065,46 +1115,24 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
EHdr->e_shoff = SectionHeaderOff;
|
EHdr->e_shoff = SectionHeaderOff;
|
||||||
EHdr->e_ehsize = sizeof(Elf_Ehdr);
|
EHdr->e_ehsize = sizeof(Elf_Ehdr);
|
||||||
EHdr->e_phentsize = sizeof(Elf_Phdr);
|
EHdr->e_phentsize = sizeof(Elf_Phdr);
|
||||||
EHdr->e_phnum = NumPhdrs;
|
EHdr->e_phnum = PHDRs.size();
|
||||||
EHdr->e_shentsize = sizeof(Elf_Shdr);
|
EHdr->e_shentsize = sizeof(Elf_Shdr);
|
||||||
EHdr->e_shnum = getNumSections();
|
EHdr->e_shnum = getNumSections();
|
||||||
EHdr->e_shstrndx = StrTabSec.getSectionIndex();
|
EHdr->e_shstrndx = StrTabSec.getSectionIndex();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
if (needsInterpSection())
|
||||||
|
InterpPHDR.setValuesFromSection(InterpSec);
|
||||||
|
if (needsDynamicSections())
|
||||||
|
DynamicPHDR.setValuesFromSection(DynamicSec);
|
||||||
|
|
||||||
auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
|
auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
|
||||||
if (needsInterpSection()) {
|
for (ProgramHeader<ELFT::Is64Bits> *PHDR : PHDRs)
|
||||||
PHdrs->p_type = PT_INTERP;
|
PHDR->template writeHeaderTo<ELFT::TargetEndianness>(PHdrs++);
|
||||||
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;
|
|
||||||
|
|
||||||
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 (needsDynamicSections()) {
|
|
||||||
PHdrs->p_type = PT_DYNAMIC;
|
|
||||||
setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
|
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
|
||||||
// First entry is null.
|
// First entry is null.
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
// CHECK-NEXT: SHF_ALLOC
|
// CHECK-NEXT: SHF_ALLOC
|
||||||
// CHECK-NEXT: ]
|
// CHECK-NEXT: ]
|
||||||
// CHECK-NEXT: Address: [[RELAADDR:.*]]
|
// CHECK-NEXT: Address: [[RELAADDR:.*]]
|
||||||
// CHECK-NEXT: Offset: 0x6000
|
// CHECK-NEXT: Offset: 0x4058
|
||||||
// CHECK-NEXT: Size: [[RELASIZE:.*]]
|
// CHECK-NEXT: Size: [[RELASIZE:.*]]
|
||||||
// CHECK-NEXT: Link: 4
|
// CHECK-NEXT: Link: 4
|
||||||
// CHECK-NEXT: Info: 0
|
// CHECK-NEXT: Info: 0
|
||||||
|
|
|
@ -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: ]
|
|
@ -33,7 +33,7 @@ R_X86_64_32:
|
||||||
// constants in hex.
|
// constants in hex.
|
||||||
// CHECK: Disassembly of section .text2:
|
// CHECK: Disassembly of section .text2:
|
||||||
// CHECK-NEXT: R_X86_64_32:
|
// CHECK-NEXT: R_X86_64_32:
|
||||||
// CHECK-NEXT: 12000: {{.*}} movl $73728, %edx
|
// CHECK-NEXT: 1100c: {{.*}} movl $69644, %edx
|
||||||
|
|
||||||
.section .R_X86_64_32S,"ax",@progbits
|
.section .R_X86_64_32S,"ax",@progbits
|
||||||
.global R_X86_64_32S
|
.global R_X86_64_32S
|
||||||
|
@ -50,4 +50,4 @@ R_X86_64_64:
|
||||||
.quad R_X86_64_64
|
.quad R_X86_64_64
|
||||||
|
|
||||||
// CHECK: Contents of section .R_X86_64_64:
|
// CHECK: Contents of section .R_X86_64_64:
|
||||||
// CHECK-NEXT: 14000 00400100 00000000
|
// CHECK-NEXT: 12000 00200100 00000000
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// SO-NEXT: Flags [
|
// SO-NEXT: Flags [
|
||||||
// SO-NEXT: ]
|
// SO-NEXT: ]
|
||||||
// SO-NEXT: Address:
|
// SO-NEXT: Address:
|
||||||
// SO-NEXT: Offset: 0x400C
|
// SO-NEXT: Offset: 0x300C
|
||||||
// SO-NEXT: Size:
|
// SO-NEXT: Size:
|
||||||
// SO-NEXT: Link:
|
// SO-NEXT: Link:
|
||||||
// SO-NEXT: Info:
|
// SO-NEXT: Info:
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
// CHECK-NEXT: SHF_ALLOC
|
// CHECK-NEXT: SHF_ALLOC
|
||||||
// CHECK-NEXT: ]
|
// CHECK-NEXT: ]
|
||||||
// CHECK-NEXT: Address: [[DYNSYMADDR:.*]]
|
// CHECK-NEXT: Address: [[DYNSYMADDR:.*]]
|
||||||
// CHECK-NEXT: Offset: 0x3000
|
// CHECK-NEXT: Offset: 0x201C
|
||||||
// CHECK-NEXT: Size: 48
|
// CHECK-NEXT: Size: 48
|
||||||
// CHECK-NEXT: Link: [[DYNSTR:.*]]
|
// CHECK-NEXT: Link: [[DYNSTR:.*]]
|
||||||
// CHECK-NEXT: Info: 1
|
// CHECK-NEXT: Info: 1
|
||||||
|
|
Loading…
Reference in New Issue