void addPredefinedSections();
std::vector<Phdr> createPhdrs();
+ void removeEmptyPTLoad();
void addPtArmExid(std::vector<Phdr> &Phdrs);
void assignAddresses();
void assignFileOffsets();
template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
+template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
+ auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const Phdr &P) {
+ if (P.H.p_type != PT_LOAD)
+ return false;
+ uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr;
+ return Size == 0;
+ });
+ Phdrs.erase(I, Phdrs.end());
+}
+
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
assignAddresses();
}
+ // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+ // 0 sized region. This has to be done late since only after assignAddresses
+ // we know the size of the sections.
+ removeEmptyPTLoad();
+
if (!Config->OFormatBinary)
assignFileOffsets();
else
--- /dev/null
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -l --elf-output-style=GNU %t.so | FileCheck %s
+
+// Test that we don't create an empty executable PT_LOAD.
+
+// CHECK: PHDR {{.*}} R 0x8
+// CHECK-NEXT: LOAD {{.*}} R 0x1000
+// CHECK-NEXT: LOAD {{.*}} RW 0x1000
+// CHECK-NEXT: DYNAMIC {{.*}} RW 0x8
# CHECK-NEXT: Offset:
# CHECK-NEXT: VirtualAddress:
# CHECK-NEXT: PhysicalAddress:
-# CHECK-NEXT: FileSize: 0
-# CHECK-NEXT: MemSize: 0
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: PF_R
-# CHECK-NEXT: PF_X
-# 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 [