Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -30,6 +30,17 @@ ELF64BEKind }; +struct OutputSectionDescription { + llvm::StringRef Name; + std::vector InputSections; + std::vector Phdrs; +}; + +struct Phdr { + llvm::StringRef Name; + uint32_t Type; +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. @@ -47,7 +58,8 @@ llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; - llvm::MapVector> OutputSections; + llvm::MapVector OutputSections; + std::vector Phdrs; std::vector SearchPaths; std::vector Undefined; bool AllowMultipleDefinition; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -16,12 +16,14 @@ #include "Config.h" #include "Driver.h" #include "SymbolTable.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/StringSaver.h" using namespace llvm; +using namespace llvm::ELF; using namespace lld; using namespace lld::elf2; @@ -36,6 +38,7 @@ static std::vector tokenize(StringRef S); static StringRef skipSpace(StringRef S); StringRef next(); + StringRef peek(); bool skip(StringRef Tok); bool atEOF() { return Tokens.size() == Pos; } void expect(StringRef Expect); @@ -50,10 +53,12 @@ void readOutput(); void readOutputArch(); void readOutputFormat(); + void readPhdrs(); void readSearchDir(); void readSections(); void readOutputSectionDescription(); + uint32_t readPhdrType(); StringSaver Saver; std::vector Tokens; @@ -81,6 +86,8 @@ readOutputArch(); } else if (Tok == "OUTPUT_FORMAT") { readOutputFormat(); + } else if (Tok == "PHDRS") { + readPhdrs(); } else if (Tok == "SEARCH_DIR") { readSearchDir(); } else if (Tok == "SECTIONS") { @@ -145,6 +152,12 @@ return Tokens[Pos++]; } +StringRef LinkerScript::peek() { + if (atEOF()) + error("unexpected EOF"); + return Tokens[Pos]; +} + bool LinkerScript::skip(StringRef Tok) { if (atEOF()) error("unexpected EOF"); @@ -276,6 +289,16 @@ expect(")"); } +void LinkerScript::readPhdrs() { + expect("{"); + while (!skip("}")) { + StringRef Name = next(); + uint32_t Type = readPhdrType(); + Config->Phdrs.emplace_back(Phdr{Name, Type}); + expect(";"); + } +} + void LinkerScript::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); @@ -290,7 +313,8 @@ void LinkerScript::readOutputSectionDescription() { StringRef Name = next(); - std::vector &InputSections = Config->OutputSections[Name]; + OutputSectionDescription &OutSec = Config->OutputSections[Name]; + OutSec.Name = Name; expect(":"); expect("{"); @@ -298,8 +322,43 @@ next(); // Skip input file name. expect("("); while (!skip(")")) - InputSections.push_back(next()); + OutSec.InputSections.push_back(next()); } + + // Read headers of the section as zero or more tokens in the form of ':phdr'. + for (;;) { + StringRef Tok = peek(); + if (Tok[0] != ':') + break; + + next(); // Swallow peeked token. + // If token is of one symbol, it's a separate ':', so go to the next token. + // Otherwise, skip starting ':' in header name. + if (Tok.size() == 1) + Tok = next(); + else + Tok = Tok.substr(1); + OutSec.Phdrs.emplace_back(Tok); + } +} + +uint32_t LinkerScript::readPhdrType() { + StringRef Tok = next(); + if (Tok == "PT_NULL") + return PT_NULL; + if (Tok == "PT_LOAD") + return PT_LOAD; + if (Tok == "PT_DYNAMIC") + return PT_DYNAMIC; + if (Tok == "PT_INTERP") + return PT_INTERP; + if (Tok == "PT_NOTE") + return PT_NOTE; + if (Tok == "PT_SHLIB") + return PT_SHLIB; + if (Tok == "PT_PHDR") + return PT_PHDR; + error("Wrong header type " + Tok); } static bool isUnderSysroot(StringRef Path) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -53,8 +53,15 @@ void scanRelocs(InputSection &C); void scanRelocs(InputSectionBase &S, const Elf_Shdr &RelSec); void updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA); + bool updatePhdrsForSection(std::vector &PhdrNames, + StringRef SecName) const; + std::vector getIndicesForPhdrs(const std::vector &Phdrs, + StringRef SecName) const; + void fillUnusedPhdrs(const std::vector &PhdrInds); + void layoutCustomPhdrs(uintX_t &VA, uintX_t &FileOff); void assignAddresses(); void buildSectionMap(); + void buildPhdrMap(); void fixAbsoluteSymbols(); void openFile(StringRef OutputPath); void writeHeader(); @@ -95,6 +102,10 @@ uintX_t SectionHeaderOff; llvm::StringMap InputToOutputSection; + // Mappings to support linker script's PHDRS command. + llvm::StringMap> OutputSectionToPhdrs; + llvm::SmallMapVector, 8> + PhdrNameToIndices; }; } // anonymous namespace @@ -147,6 +158,7 @@ // The main function of the writer. template void Writer::run() { buildSectionMap(); + buildPhdrMap(); if (!Config->DiscardAll) copyLocalSymbols(); addReservedSymbols(); @@ -993,6 +1005,26 @@ return PT_LOAD; } +// Returns true if PHDRS command with headers is defined in linker script. +static bool hasCustomPhdrs() { return !Config->Phdrs.empty(); } + +// Filter all occasions of 'NONE' header out of the list of headers. +static void filterNonePhdr(std::vector &Phdrs) { + Phdrs.erase(std::remove(std::begin(Phdrs), std::end(Phdrs), "NONE"), + std::end(Phdrs)); +} + +// Check if set of names is a subset of another set. +static bool isSubset(const std::vector &Set, + const std::vector &Subset) { + for (StringRef Name : Subset) { + auto It = std::find(std::begin(Set), std::end(Set), Name); + if (It == std::end(Set)) + return false; + } + return true; +} + template void Writer::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA) { @@ -1003,124 +1035,256 @@ GnuRelroPhdr->p_memsz = VA - Cur->p_vaddr; } -// Visits all sections to create PHDRs and to assign incremental, -// non-overlapping addresses to output sections. -template void Writer::assignAddresses() { - uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr); - uintX_t FileOff = sizeof(Elf_Ehdr); +// Update headers for given output section and return true if headers +// have changed. It also filters out 'NONE' header from the list. +template +bool Writer::updatePhdrsForSection(std::vector &PhdrNames, + StringRef SecName) const { + bool NewPhdrs = false; + const std::vector &NewPhdrNames = + OutputSectionToPhdrs.lookup(SecName); + if (!NewPhdrNames.empty()) { + // Headers really changed if they are not a direct subset + // of the previous set of headers. + NewPhdrs = !isSubset(PhdrNames, NewPhdrNames); + PhdrNames = NewPhdrNames; + } + // Filter out 'NONE' header and check if something left. + filterNonePhdr(PhdrNames); + if (PhdrNames.empty()) + NewPhdrs = false; - // Calculate and reserve the space for the program header first so that - // the first section can start right after the program header. - Phdrs.resize(getPhdrsNum()); - size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); + return NewPhdrs; +} - // The first phdr entry is PT_PHDR which describes the program header itself. - setPhdr(&Phdrs[0], PT_PHDR, PF_R, FileOff, VA, PhdrSize, /*Align=*/8); - FileOff += PhdrSize; - VA += PhdrSize; +// Form the list of indices for given header names to simplify future access. +// Check for non-existent header names and issue error in such a case. +template +std::vector +Writer::getIndicesForPhdrs(const std::vector &Phdrs, + StringRef SecName) const { + std::vector PhdrInds; + for (StringRef Name : Phdrs) { + auto It = PhdrNameToIndices.find(Name); + if (It == std::end(PhdrNameToIndices)) + error("Output section " + SecName + " assigned to non-existent header " + + Name); + PhdrInds.insert(std::end(PhdrInds), std::begin(It->second), + std::end(It->second)); + } + return PhdrInds; +} - // PT_INTERP must be the second entry if exists. - int PhdrIdx = 0; - Elf_Phdr *Interp = nullptr; - if (needsInterpSection()) - Interp = &Phdrs[++PhdrIdx]; +// Fill in not used headers with reasonable default values. +template +void Writer::fillUnusedPhdrs(const std::vector &PhdrInds) { + for (size_t Ind : PhdrInds) { + const Phdr &PH = Config->Phdrs[Ind]; + + uintX_t CurFileOff = 0; + if (Ind != 0) { + const Elf_Phdr *Prev = &Phdrs[Ind - 1]; + CurFileOff = Prev->p_offset + Prev->p_filesz; + } + setPhdr(&Phdrs[Ind], PH.Type, 0, CurFileOff, 0, 0, Target->getPageSize()); + } +} - // Add the first PT_LOAD segment for regular output sections. - setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, - Target->getPageSize()); +// Assign output sections to headers specified in linker script's PHDRS command. +// For each output section find headers to assign to. +// Set parameters for each header and for sections that are assigned to these +// headers. +// Fill unused headers with default values setting only proper file offset +// and type. +template +void Writer::layoutCustomPhdrs(uintX_t &VA, uintX_t &FileOff) { + SmallMapVector, 8> PhdrsToFill = + PhdrNameToIndices; + std::vector PhdrNames; + bool NewPhdrs = false; - Elf_Phdr GnuRelroPhdr = {}; - Elf_Phdr TlsPhdr{}; - bool RelroAligned = false; - uintX_t ThreadBssOffset = 0; - // Create phdrs as we assign VAs and file offsets to all output sections. + // Find appropriate headers for the first output section. for (OutputSectionBase *Sec : OutputSections) { - Elf_Phdr *PH = &Phdrs[PhdrIdx]; + NewPhdrs = updatePhdrsForSection(PhdrNames, Sec->getName()); + if (NewPhdrs) + break; + } + if (!NewPhdrs) + error("No sections assigned to PHDRS"); + + for (OutputSectionBase *Sec : OutputSections) { + if (!NewPhdrs) + NewPhdrs = updatePhdrsForSection(PhdrNames, Sec->getName()); + + std::vector PhdrInds = + getIndicesForPhdrs(PhdrNames, Sec->getName()); if (needsPhdr(Sec)) { - uintX_t Flags = toPhdrFlags(Sec->getFlags()); - bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec); - bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned; - if (FirstNonRelRo || PH->p_flags != Flags) { + if (NewPhdrs) { VA = align(VA, Target->getPageSize()); FileOff = align(FileOff, Target->getPageSize()); - if (FirstNonRelRo) - RelroAligned = true; - } - - if (PH->p_flags != Flags) { - // Flags changed. Create a new PT_LOAD. - PH = &Phdrs[++PhdrIdx]; - uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD - : getAmdgpuPhdr(Sec); - setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize()); - } - - if (Sec->getFlags() & SHF_TLS) { - if (!TlsPhdr.p_vaddr) - setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign()); - if (Sec->getType() != SHT_NOBITS) - VA = align(VA, Sec->getAlign()); - uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign()); - Sec->setVA(TVA); - TlsPhdr.p_memsz += Sec->getSize(); - if (Sec->getType() == SHT_NOBITS) { - ThreadBssOffset = TVA - VA + Sec->getSize(); - } else { - TlsPhdr.p_filesz += Sec->getSize(); - VA += Sec->getSize(); + for (size_t Ind : PhdrInds) { + const Phdr &PH = Config->Phdrs[Ind]; + StringRef Name = PH.Name; + // Check that this is the first update of the header. + if (!PhdrsToFill.count(Name)) + continue; + PhdrsToFill.erase(Name); + // Flags for the header will be updated later. + setPhdr(&Phdrs[Ind], PH.Type, 0, FileOff, VA, 0, + Target->getPageSize()); } - TlsPhdr.p_align = std::max(TlsPhdr.p_align, Sec->getAlign()); - } else { - VA = align(VA, Sec->getAlign()); - Sec->setVA(VA); - VA += Sec->getSize(); - if (InRelRo) - updateRelro(PH, &GnuRelroPhdr, VA); } + + VA = align(VA, Sec->getAlign()); + Sec->setVA(VA); + VA += Sec->getSize(); } + NewPhdrs = false; FileOff = align(FileOff, Sec->getAlign()); Sec->setFileOffset(FileOff); if (Sec->getType() != SHT_NOBITS) FileOff += Sec->getSize(); if (needsPhdr(Sec)) { - PH->p_filesz = FileOff - PH->p_offset; - PH->p_memsz = VA - PH->p_vaddr; + uintX_t Flags = toPhdrFlags(Sec->getFlags()); + for (size_t Ind : PhdrInds) { + Elf_Phdr *Cur = &Phdrs[Ind]; + Cur->p_filesz = FileOff - Cur->p_offset; + Cur->p_memsz = VA - Cur->p_vaddr; + Cur->p_flags |= Flags; + } } } - if (TlsPhdr.p_vaddr) { - // The TLS pointer goes after PT_TLS. At least glibc will align it, - // so round up the size to make sure the offsets are correct. - TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align); - Phdrs[++PhdrIdx] = TlsPhdr; - Out::TlsPhdr = &Phdrs[PhdrIdx]; - } + // Fixup not used headers from PHDRS command. + for (const std::pair> &p : PhdrsToFill) + fillUnusedPhdrs(p.second); +} - // Add an entry for .dynamic. - if (isOutputDynamic()) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_DYNAMIC; - copyPhdr(PH, Out::Dynamic); - } +// Visits all sections to create PHDRs and to assign incremental, +// non-overlapping addresses to output sections. +template void Writer::assignAddresses() { + uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr); + uintX_t FileOff = sizeof(Elf_Ehdr); - if (HasRelro) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - *PH = GnuRelroPhdr; - } + // Calculate and reserve the space for the program header first so that + // the first section can start right after the program header. + Phdrs.resize(getPhdrsNum()); - // PT_GNU_STACK is a special section to tell the loader to make the - // pages for the stack non-executable. - if (!Config->ZExecStack) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_GNU_STACK; - PH->p_flags = PF_R | PF_W; - } + if (hasCustomPhdrs()) + layoutCustomPhdrs(VA, FileOff); + else { + // The first phdr entry is PT_PHDR which describes the program header + // itself. + size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); + setPhdr(&Phdrs[0], PT_PHDR, PF_R, FileOff, VA, PhdrSize, /*Align=*/8); + FileOff += PhdrSize; + VA += PhdrSize; + + // PT_INTERP must be the second entry if exists. + int PhdrIdx = 0; + Elf_Phdr *Interp = nullptr; + if (needsInterpSection()) + Interp = &Phdrs[++PhdrIdx]; + + // Add the first PT_LOAD segment for regular output sections. + setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, + Target->getPageSize()); + + Elf_Phdr GnuRelroPhdr = {}; + Elf_Phdr TlsPhdr{}; + bool RelroAligned = false; + uintX_t ThreadBssOffset = 0; + // Create phdrs as we assign VAs and file offsets to all output sections. + for (OutputSectionBase *Sec : OutputSections) { + Elf_Phdr *PH = &Phdrs[PhdrIdx]; + if (needsPhdr(Sec)) { + uintX_t Flags = toPhdrFlags(Sec->getFlags()); + bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec); + bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned; + if (FirstNonRelRo || PH->p_flags != Flags) { + VA = align(VA, Target->getPageSize()); + FileOff = align(FileOff, Target->getPageSize()); + if (FirstNonRelRo) + RelroAligned = true; + } - // Fix up PT_INTERP as we now know the address of .interp section. - if (Interp) { - Interp->p_type = PT_INTERP; - copyPhdr(Interp, Out::Interp); + if (PH->p_flags != Flags) { + // Flags changed. Create a new PT_LOAD. + PH = &Phdrs[++PhdrIdx]; + uint32_t PTType = (Config->EMachine != EM_AMDGPU) + ? (uint32_t)PT_LOAD + : getAmdgpuPhdr(Sec); + setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize()); + } + + if (Sec->getFlags() & SHF_TLS) { + if (!TlsPhdr.p_vaddr) + setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign()); + if (Sec->getType() != SHT_NOBITS) + VA = align(VA, Sec->getAlign()); + uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign()); + Sec->setVA(TVA); + TlsPhdr.p_memsz += Sec->getSize(); + if (Sec->getType() == SHT_NOBITS) { + ThreadBssOffset = TVA - VA + Sec->getSize(); + } else { + TlsPhdr.p_filesz += Sec->getSize(); + VA += Sec->getSize(); + } + TlsPhdr.p_align = std::max(TlsPhdr.p_align, Sec->getAlign()); + } else { + VA = align(VA, Sec->getAlign()); + Sec->setVA(VA); + VA += Sec->getSize(); + if (InRelRo) + updateRelro(PH, &GnuRelroPhdr, VA); + } + } + + FileOff = align(FileOff, Sec->getAlign()); + Sec->setFileOffset(FileOff); + if (Sec->getType() != SHT_NOBITS) + FileOff += Sec->getSize(); + if (needsPhdr(Sec)) { + PH->p_filesz = FileOff - PH->p_offset; + PH->p_memsz = VA - PH->p_vaddr; + } + } + + if (TlsPhdr.p_vaddr) { + // The TLS pointer goes after PT_TLS. At least glibc will align it, + // so round up the size to make sure the offsets are correct. + TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align); + Phdrs[++PhdrIdx] = TlsPhdr; + Out::TlsPhdr = &Phdrs[PhdrIdx]; + } + + // Add an entry for .dynamic. + if (isOutputDynamic()) { + Elf_Phdr *PH = &Phdrs[++PhdrIdx]; + PH->p_type = PT_DYNAMIC; + copyPhdr(PH, Out::Dynamic); + } + + if (HasRelro) { + Elf_Phdr *PH = &Phdrs[++PhdrIdx]; + *PH = GnuRelroPhdr; + } + + // PT_GNU_STACK is a special section to tell the loader to make the + // pages for the stack non-executable. + if (!Config->ZExecStack) { + Elf_Phdr *PH = &Phdrs[++PhdrIdx]; + PH->p_type = PT_GNU_STACK; + PH->p_flags = PF_R | PF_W; + } + + // Fix up PT_INTERP as we now know the address of .interp section. + if (Interp) { + Interp->p_type = PT_INTERP; + copyPhdr(Interp, Out::Interp); + } } // Add space for section headers. @@ -1134,6 +1298,9 @@ // Returns the number of PHDR entries. template int Writer::getPhdrsNum() const { + if (hasCustomPhdrs()) + return Config->Phdrs.size(); + bool Tls = false; int I = 2; // 2 for PT_PHDR and first PT_LOAD if (needsInterpSection()) @@ -1297,10 +1464,24 @@ } template void Writer::buildSectionMap() { - for (const std::pair> &OutSec : + for (const std::pair &OutSec : Config->OutputSections) - for (StringRef Name : OutSec.second) + for (StringRef Name : OutSec.second.InputSections) { InputToOutputSection[Name] = OutSec.first; + + if (!hasCustomPhdrs() || OutSec.second.Phdrs.empty()) + continue; + std::vector &Phdrs = OutputSectionToPhdrs[Name]; + Phdrs.insert(std::end(Phdrs), std::begin(OutSec.second.Phdrs), + std::end(OutSec.second.Phdrs)); + } +} + +template void Writer::buildPhdrMap() { + for (size_t I = 0, Len = Config->Phdrs.size(); I < Len; ++I) { + const Phdr &PH = Config->Phdrs[I]; + PhdrNameToIndices[PH.Name].push_back(I); + } } template void elf2::writeResult(SymbolTable *Symtab); Index: test/ELF/linkerscript-phdrs.s =================================================================== --- /dev/null +++ test/ELF/linkerscript-phdrs.s @@ -0,0 +1,623 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# Empty PHDRS command. +# RUN: echo "PHDRS {}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | \ +# RUN: FileCheck -check-prefix=PHDRS-DEFAULT %s + +# PHDRS-DEFAULT: ProgramHeaders [ +# PHDRS-DEFAULT: ProgramHeader { +# PHDRS-DEFAULT: Type: PT_PHDR +# PHDRS-DEFAULT: Flags [ (0x4) +# PHDRS-DEFAULT: PF_R (0x4) +# PHDRS-DEFAULT: ] +# PHDRS-DEFAULT: Alignment: 8 +# PHDRS-DEFAULT: } +# PHDRS-DEFAULT: ProgramHeader { +# PHDRS-DEFAULT: Type: PT_LOAD (0x1) +# PHDRS-DEFAULT: Flags [ (0x4) +# PHDRS-DEFAULT: PF_R (0x4) +# PHDRS-DEFAULT: ] +# PHDRS-DEFAULT: Alignment: 4096 +# PHDRS-DEFAULT: } +# PHDRS-DEFAULT: ProgramHeader { +# PHDRS-DEFAULT: Type: PT_LOAD +# PHDRS-DEFAULT: Flags [ (0x5) +# PHDRS-DEFAULT: PF_R (0x4) +# PHDRS-DEFAULT: PF_X (0x1) +# PHDRS-DEFAULT: ] +# PHDRS-DEFAULT: Alignment: 4096 +# PHDRS-DEFAULT: } +# PHDRS-DEFAULT: ProgramHeader { +# PHDRS-DEFAULT: Type: PT_LOAD +# PHDRS-DEFAULT: Flags [ (0x6) +# PHDRS-DEFAULT: PF_R (0x4) +# PHDRS-DEFAULT: PF_W (0x2) +# PHDRS-DEFAULT: ] +# PHDRS-DEFAULT: Alignment: 4096 +# PHDRS-DEFAULT: } +# PHDRS-DEFAULT: ProgramHeader { +# PHDRS-DEFAULT: Type: PT_GNU_STACK +# PHDRS-DEFAULT: Flags [ (0x6) +# PHDRS-DEFAULT: PF_R (0x4) +# PHDRS-DEFAULT: PF_W (0x2) +# PHDRS-DEFAULT: ] +# PHDRS-DEFAULT: Alignment: 0 +# PHDRS-DEFAULT: } +# PHDRS-DEFAULT: ] + +# Unknown header type causes error. +# RUN: echo "PHDRS { \ +# RUN: unknown PT_UNKNOWN; \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-ERRTYPE %s < %t.log + +# PHDRS-ERRTYPE: Wrong header type PT_UNKNOWN + +# Unknown header name causes error. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } :unknown \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-ERRNAME %s < %t.log + +# PHDRS-ERRNAME: Output section .data assigned to non-existent header unknown + +# Error if sections are not assigned to any headers. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-NOTASSIGNED %s < %t.log + +# PHDRS-NOTASSIGNED: No sections assigned to PHDRS + +# Error if sections are assigned to only 'NONE' header. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :NONE \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-NOTASSIGNED %s < %t.log + +# Map all sections to one header. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2 --script %t.script %t +# RUN: llvm-readobj -program-headers %t2 | \ +# RUN: FileCheck -check-prefix=PHDRS-ONE-ALL %s +# RUN: llvm-objdump -section-headers %t2 | \ +# RUN: FileCheck -check-prefix=SEC-ONE-ALL %s + +# PHDRS-ONE-ALL: ProgramHeaders [ +# PHDRS-ONE-ALL-NEXT: ProgramHeader { +# PHDRS-ONE-ALL-NEXT: Type: PT_LOAD +# PHDRS-ONE-ALL-NEXT: Offset: 0x1000 +# PHDRS-ONE-ALL-NEXT: VirtualAddress: 0x11000 +# PHDRS-ONE-ALL-NEXT: PhysicalAddress: 0x11000 +# PHDRS-ONE-ALL-NEXT: FileSize: 46 +# PHDRS-ONE-ALL-NEXT: MemSize: 48 +# PHDRS-ONE-ALL-NEXT: Flags [ (0x7) +# PHDRS-ONE-ALL-NEXT: PF_R (0x4) +# PHDRS-ONE-ALL-NEXT: PF_W (0x2) +# PHDRS-ONE-ALL-NEXT: PF_X (0x1) +# PHDRS-ONE-ALL-NEXT: ] +# PHDRS-ONE-ALL-NEXT: Alignment: 4096 +# PHDRS-ONE-ALL-NEXT: } +# PHDRS-ONE-ALL-NEXT: ] + +# Idx Name Size Address +# SEC-ONE-ALL: 1 .text 0000000e 0000000000011000 +# SEC-ONE-ALL: 2 .data 00000020 000000000001100e +# SEC-ONE-ALL: 3 .bss 00000002 000000000001102e + +# Map all sections to one header, +# but separate the header name from the ':' sign. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } : load \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2_1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t2_1 | \ +# RUN: FileCheck -check-prefix=PHDRS-ONE-ALL %s +# RUN: llvm-objdump -section-headers %t2_1 | \ +# RUN: FileCheck -check-prefix=SEC-ONE-ALL %s + +# Map all sections to one header skipping 'NONE' header +# if it's not the only available. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load :NONE \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2_2 --script %t.script %t +# RUN: llvm-readobj -program-headers %t2_2 | \ +# RUN: FileCheck -check-prefix=PHDRS-ONE-ALL %s +# RUN: llvm-objdump -section-headers %t2_2 | \ +# RUN: FileCheck -check-prefix=SEC-ONE-ALL %s + +# Map all sections to couple of headers. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load :phdr \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t3 --script %t.script %t +# RUN: llvm-readobj -program-headers %t3 | \ +# RUN: FileCheck -check-prefix=PHDRS-TWO-ALL %s +# RUN: llvm-objdump -section-headers %t3 | \ +# RUN: FileCheck -check-prefix=SEC-TWO-ALL %s + +# PHDRS-TWO-ALL: ProgramHeaders [ +# PHDRS-TWO-ALL-NEXT: ProgramHeader { +# PHDRS-TWO-ALL-NEXT: Type: PT_PHDR +# PHDRS-TWO-ALL-NEXT: Offset: 0x1000 +# PHDRS-TWO-ALL-NEXT: VirtualAddress: 0x11000 +# PHDRS-TWO-ALL-NEXT: PhysicalAddress: 0x11000 +# PHDRS-TWO-ALL-NEXT: FileSize: 46 +# PHDRS-TWO-ALL-NEXT: MemSize: 48 +# PHDRS-TWO-ALL-NEXT: Flags [ (0x7) +# PHDRS-TWO-ALL-NEXT: PF_R (0x4) +# PHDRS-TWO-ALL-NEXT: PF_W (0x2) +# PHDRS-TWO-ALL-NEXT: PF_X (0x1) +# PHDRS-TWO-ALL-NEXT: ] +# PHDRS-TWO-ALL-NEXT: Alignment: 4096 +# PHDRS-TWO-ALL-NEXT: } +# PHDRS-TWO-ALL-NEXT: ProgramHeader { +# PHDRS-TWO-ALL-NEXT: Type: PT_LOAD +# PHDRS-TWO-ALL-NEXT: Offset: 0x1000 +# PHDRS-TWO-ALL-NEXT: VirtualAddress: 0x11000 +# PHDRS-TWO-ALL-NEXT: PhysicalAddress: 0x11000 +# PHDRS-TWO-ALL-NEXT: FileSize: 46 +# PHDRS-TWO-ALL-NEXT: MemSize: 48 +# PHDRS-TWO-ALL-NEXT: Flags [ (0x7) +# PHDRS-TWO-ALL-NEXT: PF_R (0x4) +# PHDRS-TWO-ALL-NEXT: PF_W (0x2) +# PHDRS-TWO-ALL-NEXT: PF_X (0x1) +# PHDRS-TWO-ALL-NEXT: ] +# PHDRS-TWO-ALL-NEXT: Alignment: 4096 +# PHDRS-TWO-ALL-NEXT: } +# PHDRS-TWO-ALL-NEXT: ] + +# Idx Name Size Address +# SEC-TWO-ALL: 1 .text 0000000e 0000000000011000 +# SEC-TWO-ALL: 2 .data 00000020 000000000001100e +# SEC-TWO-ALL: 3 .bss 00000002 000000000001102e + +# Map sections to different headers explicitly. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: load2 PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } :load \ +# RUN: .bss : { *(.bss) } :load2 \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t4 --script %t.script %t +# RUN: llvm-readobj -program-headers %t4 | \ +# RUN: FileCheck -check-prefix=PHDRS-DIFF %s +# RUN: llvm-objdump -section-headers %t4 | \ +# RUN: FileCheck -check-prefix=SEC-DIFF %s + +# PHDRS-DIFF: ProgramHeaders [ +# PHDRS-DIFF-NEXT: ProgramHeader { +# PHDRS-DIFF-NEXT: Type: PT_LOAD +# PHDRS-DIFF-NEXT: Offset: 0x1000 +# PHDRS-DIFF-NEXT: VirtualAddress: 0x11000 +# PHDRS-DIFF-NEXT: PhysicalAddress: 0x11000 +# PHDRS-DIFF-NEXT: FileSize: 46 +# PHDRS-DIFF-NEXT: MemSize: 46 +# PHDRS-DIFF-NEXT: Flags [ (0x7) +# PHDRS-DIFF-NEXT: PF_R (0x4) +# PHDRS-DIFF-NEXT: PF_W (0x2) +# PHDRS-DIFF-NEXT: PF_X (0x1) +# PHDRS-DIFF-NEXT: ] +# PHDRS-DIFF-NEXT: Alignment: 4096 +# PHDRS-DIFF-NEXT: } +# PHDRS-DIFF-NEXT: ProgramHeader { +# PHDRS-DIFF-NEXT: Type: PT_LOAD +# PHDRS-DIFF-NEXT: Offset: 0x2000 +# PHDRS-DIFF-NEXT: VirtualAddress: 0x12000 +# PHDRS-DIFF-NEXT: PhysicalAddress: 0x12000 +# PHDRS-DIFF-NEXT: FileSize: 0 +# PHDRS-DIFF-NEXT: MemSize: 2 +# PHDRS-DIFF-NEXT: Flags [ (0x6) +# PHDRS-DIFF-NEXT: PF_R (0x4) +# PHDRS-DIFF-NEXT: PF_W (0x2) +# PHDRS-DIFF-NEXT: ] +# PHDRS-DIFF-NEXT: Alignment: 4096 +# PHDRS-DIFF-NEXT: } +# PHDRS-DIFF-NEXT: ] + +# Idx Name Size Address +# SEC-DIFF: 1 .text 0000000e 0000000000011000 +# SEC-DIFF: 2 .data 00000020 000000000001100e +# SEC-DIFF: 3 .bss 00000002 0000000000012000 + +# Map sections to different headers implicitly. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: load2 PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } \ +# RUN: .bss : { *(.bss) } :load2 \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t5 --script %t.script %t +# RUN: llvm-readobj -program-headers %t5 | \ +# RUN: FileCheck -check-prefix=PHDRS-DIFF %s +# RUN: llvm-objdump -section-headers %t5 | \ +# RUN: FileCheck -check-prefix=SEC-DIFF %s + +# Map sections appearing before the section with first assigned header +# to that header (.text is mapped to the 'load' header). +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: load2 PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .data : { *(.data) } :load \ +# RUN: .bss : { *(.bss) } :load2 \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t6 --script %t.script %t +# RUN: llvm-readobj -program-headers %t6 | \ +# RUN: FileCheck -check-prefix=PHDRS-DIFF %s +# RUN: llvm-objdump -section-headers %t6 | \ +# RUN: FileCheck -check-prefix=SEC-DIFF %s + +# Map :NONE header to some sections. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD; \ +# RUN: load2 PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } :NONE \ +# RUN: .bss : { *(.bss) } :load2 \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t7 --script %t.script %t +# RUN: llvm-readobj -program-headers %t7 | \ +# RUN: FileCheck -check-prefix=PHDRS-NONE %s +# RUN: llvm-objdump -section-headers %t7 | \ +# RUN: FileCheck -check-prefix=SEC-NONE %s + +# PHDRS-NONE: ProgramHeaders [ +# PHDRS-NONE-NEXT: ProgramHeader { +# PHDRS-NONE-NEXT: Type: PT_LOAD +# PHDRS-NONE-NEXT: Offset: 0x1000 +# PHDRS-NONE-NEXT: VirtualAddress: 0x11000 +# PHDRS-NONE-NEXT: PhysicalAddress: 0x11000 +# PHDRS-NONE-NEXT: FileSize: 14 +# PHDRS-NONE-NEXT: MemSize: 14 +# PHDRS-NONE-NEXT: Flags [ (0x5) +# PHDRS-NONE-NEXT: PF_R (0x4) +# PHDRS-NONE-NEXT: PF_X (0x1) +# PHDRS-NONE-NEXT: ] +# PHDRS-NONE-NEXT: Alignment: 4096 +# PHDRS-NONE-NEXT: } +# PHDRS-NONE-NEXT: ProgramHeader { +# PHDRS-NONE-NEXT: Type: PT_LOAD +# PHDRS-NONE-NEXT: Offset: 0x2000 +# PHDRS-NONE-NEXT: VirtualAddress: 0x12000 +# PHDRS-NONE-NEXT: PhysicalAddress: 0x12000 +# PHDRS-NONE-NEXT: FileSize: 0 +# PHDRS-NONE-NEXT: MemSize: 2 +# PHDRS-NONE-NEXT: Flags [ (0x6) +# PHDRS-NONE-NEXT: PF_R (0x4) +# PHDRS-NONE-NEXT: PF_W (0x2) +# PHDRS-NONE-NEXT: ] +# PHDRS-NONE-NEXT: Alignment: 4096 +# PHDRS-NONE-NEXT: } +# PHDRS-NONE-NEXT: ] + +# Idx Name Size Address +# SEC-NONE: 1 .text 0000000e 0000000000011000 +# SEC-NONE: 2 .data 00000020 000000000001100e +# SEC-NONE: 3 .bss 00000002 0000000000012000 + +# Map sections to multiple headers. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :phdr :load \ +# RUN: .data : { *(.data) } \ +# RUN: .bss : { *(.bss) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t8 --script %t.script %t +# RUN: llvm-readobj -program-headers %t8 | \ +# RUN: FileCheck -check-prefix=PHDRS-MULT %s +# RUN: llvm-objdump -section-headers %t8 | \ +# RUN: FileCheck -check-prefix=SEC-MULT %s + +# PHDRS-MULT: ProgramHeaders [ +# PHDRS-MULT-NEXT: ProgramHeader { +# PHDRS-MULT-NEXT: Type: PT_PHDR +# PHDRS-MULT-NEXT: Offset: 0x1000 +# PHDRS-MULT-NEXT: VirtualAddress: 0x11000 +# PHDRS-MULT-NEXT: PhysicalAddress: 0x11000 +# PHDRS-MULT-NEXT: FileSize: 46 +# PHDRS-MULT-NEXT: MemSize: 48 +# PHDRS-MULT-NEXT: Flags [ (0x7) +# PHDRS-MULT-NEXT: PF_R (0x4) +# PHDRS-MULT-NEXT: PF_W (0x2) +# PHDRS-MULT-NEXT: PF_X (0x1) +# PHDRS-MULT-NEXT: ] +# PHDRS-MULT-NEXT: Alignment: 4096 +# PHDRS-MULT-NEXT: } +# PHDRS-MULT-NEXT: ProgramHeader { +# PHDRS-MULT-NEXT: Type: PT_LOAD +# PHDRS-MULT-NEXT: Offset: 0x1000 +# PHDRS-MULT-NEXT: VirtualAddress: 0x11000 +# PHDRS-MULT-NEXT: PhysicalAddress: 0x11000 +# PHDRS-MULT-NEXT: FileSize: 46 +# PHDRS-MULT-NEXT: MemSize: 48 +# PHDRS-MULT-NEXT: Flags [ (0x7) +# PHDRS-MULT-NEXT: PF_R (0x4) +# PHDRS-MULT-NEXT: PF_W (0x2) +# PHDRS-MULT-NEXT: PF_X (0x1) +# PHDRS-MULT-NEXT: ] +# PHDRS-MULT-NEXT: Alignment: 4096 +# PHDRS-MULT-NEXT: } +# PHDRS-MULT-NEXT: ] + +# Idx Name Size Address +# SEC-MULT: 1 .text 0000000e 0000000000011000 +# SEC-MULT: 2 .data 00000020 000000000001100e +# SEC-MULT: 3 .bss 00000002 000000000001102e + +# Map sections initially to multiple headers, then map +# other sections to the subset of these headers. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :phdr :load \ +# RUN: .data : { *(.data) } :load \ +# RUN: .bss : { *(.bss) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t9 --script %t.script %t +# RUN: llvm-readobj -program-headers %t9 | \ +# RUN: FileCheck -check-prefix=PHDRS-SUBSET %s +# RUN: llvm-objdump -section-headers %t9 | \ +# RUN: FileCheck -check-prefix=SEC-SUBSET %s + +# PHDRS-SUBSET: ProgramHeaders [ +# PHDRS-SUBSET-NEXT: ProgramHeader { +# PHDRS-SUBSET-NEXT: Type: PT_PHDR +# PHDRS-SUBSET-NEXT: Offset: 0x1000 +# PHDRS-SUBSET-NEXT: VirtualAddress: 0x11000 +# PHDRS-SUBSET-NEXT: PhysicalAddress: 0x11000 +# PHDRS-SUBSET-NEXT: FileSize: 14 +# PHDRS-SUBSET-NEXT: MemSize: 14 +# PHDRS-SUBSET-NEXT: Flags [ (0x5) +# PHDRS-SUBSET-NEXT: PF_R (0x4) +# PHDRS-SUBSET-NEXT: PF_X (0x1) +# PHDRS-SUBSET-NEXT: ] +# PHDRS-SUBSET-NEXT: Alignment: 4096 +# PHDRS-SUBSET-NEXT: } +# PHDRS-SUBSET-NEXT: ProgramHeader { +# PHDRS-SUBSET-NEXT: Type: PT_LOAD +# PHDRS-SUBSET-NEXT: Offset: 0x1000 +# PHDRS-SUBSET-NEXT: VirtualAddress: 0x11000 +# PHDRS-SUBSET-NEXT: PhysicalAddress: 0x11000 +# PHDRS-SUBSET-NEXT: FileSize: 46 +# PHDRS-SUBSET-NEXT: MemSize: 48 +# PHDRS-SUBSET-NEXT: Flags [ (0x7) +# PHDRS-SUBSET-NEXT: PF_R (0x4) +# PHDRS-SUBSET-NEXT: PF_W (0x2) +# PHDRS-SUBSET-NEXT: PF_X (0x1) +# PHDRS-SUBSET-NEXT: ] +# PHDRS-SUBSET-NEXT: Alignment: 4096 +# PHDRS-SUBSET-NEXT: } +# PHDRS-SUBSET-NEXT: ] + +# Idx Name Size Address +# SEC-SUBSET: 1 .text 0000000e 0000000000011000 +# SEC-SUBSET: 2 .data 00000020 000000000001100e +# SEC-SUBSET: 3 .bss 00000002 000000000001102e + +# Map sections initially to multiple headers, then map +# sections to other headers. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD; \ +# RUN: load2 PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :phdr :load \ +# RUN: .data : { *(.data) } \ +# RUN: .bss : { *(.bss) } :load2 \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t10 --script %t.script %t +# RUN: llvm-readobj -program-headers %t10 | \ +# RUN: FileCheck -check-prefix=PHDRS-NOSUBSET %s +# RUN: llvm-objdump -section-headers %t10 | \ +# RUN: FileCheck -check-prefix=SEC-NOSUBSET %s + +# PHDRS-NOSUBSET: ProgramHeaders [ +# PHDRS-NOSUBSET-NEXT: ProgramHeader { +# PHDRS-NOSUBSET-NEXT: Type: PT_PHDR +# PHDRS-NOSUBSET-NEXT: Offset: 0x1000 +# PHDRS-NOSUBSET-NEXT: VirtualAddress: 0x11000 +# PHDRS-NOSUBSET-NEXT: PhysicalAddress: 0x11000 +# PHDRS-NOSUBSET-NEXT: FileSize: 46 +# PHDRS-NOSUBSET-NEXT: MemSize: 46 +# PHDRS-NOSUBSET-NEXT: Flags [ (0x7) +# PHDRS-NOSUBSET-NEXT: PF_R (0x4) +# PHDRS-NOSUBSET-NEXT: PF_W (0x2) +# PHDRS-NOSUBSET-NEXT: PF_X (0x1) +# PHDRS-NOSUBSET-NEXT: ] +# PHDRS-NOSUBSET-NEXT: Alignment: 4096 +# PHDRS-NOSUBSET-NEXT: } +# PHDRS-NOSUBSET-NEXT: ProgramHeader { +# PHDRS-NOSUBSET-NEXT: Type: PT_LOAD +# PHDRS-NOSUBSET-NEXT: Offset: 0x1000 +# PHDRS-NOSUBSET-NEXT: VirtualAddress: 0x11000 +# PHDRS-NOSUBSET-NEXT: PhysicalAddress: 0x11000 +# PHDRS-NOSUBSET-NEXT: FileSize: 46 +# PHDRS-NOSUBSET-NEXT: MemSize: 46 +# PHDRS-NOSUBSET-NEXT: Flags [ (0x7) +# PHDRS-NOSUBSET-NEXT: PF_R (0x4) +# PHDRS-NOSUBSET-NEXT: PF_W (0x2) +# PHDRS-NOSUBSET-NEXT: PF_X (0x1) +# PHDRS-NOSUBSET-NEXT: ] +# PHDRS-NOSUBSET-NEXT: Alignment: 4096 +# PHDRS-NOSUBSET-NEXT: } +# PHDRS-NOSUBSET-NEXT: ProgramHeader { +# PHDRS-NOSUBSET-NEXT: Type: PT_LOAD +# PHDRS-NOSUBSET-NEXT: Offset: 0x2000 +# PHDRS-NOSUBSET-NEXT: VirtualAddress: 0x12000 +# PHDRS-NOSUBSET-NEXT: PhysicalAddress: 0x12000 +# PHDRS-NOSUBSET-NEXT: FileSize: 0 +# PHDRS-NOSUBSET-NEXT: MemSize: 2 +# PHDRS-NOSUBSET-NEXT: Flags [ (0x6) +# PHDRS-NOSUBSET-NEXT: PF_R (0x4) +# PHDRS-NOSUBSET-NEXT: PF_W (0x2) +# PHDRS-NOSUBSET-NEXT: ] +# PHDRS-NOSUBSET-NEXT: Alignment: 4096 +# PHDRS-NOSUBSET-NEXT: } +# PHDRS-NOSUBSET-NEXT: ] + +# Idx Name Size Address +# SEC-NOSUBSET: 1 .text 0000000e 0000000000011000 +# SEC-NOSUBSET: 2 .data 00000020 000000000001100e +# SEC-NOSUBSET: 3 .bss 00000002 0000000000012000 + +# Check unused headers are filled, +# plus check all header types are allowed. +# RUN: echo "PHDRS { \ +# RUN: null PT_NULL; \ +# RUN: load PT_LOAD; \ +# RUN: dynamic PT_DYNAMIC; \ +# RUN: interp PT_INTERP; \ +# RUN: note PT_NOTE; \ +# RUN: shlib PT_SHLIB; \ +# RUN: phdr PT_PHDR; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } \ +# RUN: .bss : { *(.bss) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t11 --script %t.script %t +# RUN: llvm-readobj -program-headers %t11 | \ +# RUN: FileCheck -check-prefix=PHDRS-UNUSED %s + +# PHDRS-UNUSED: ProgramHeaders [ +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_NULL +# PHDRS-UNUSED-NEXT: Offset: 0x0 +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_LOAD +# PHDRS-UNUSED-NEXT: Offset: 0x1000 +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x11000 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x11000 +# PHDRS-UNUSED-NEXT: FileSize: 46 +# PHDRS-UNUSED-NEXT: MemSize: 48 +# PHDRS-UNUSED-NEXT: Flags [ (0x7) +# PHDRS-UNUSED-NEXT: PF_R (0x4) +# PHDRS-UNUSED-NEXT: PF_W (0x2) +# PHDRS-UNUSED-NEXT: PF_X (0x1) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_DYNAMIC +# PHDRS-UNUSED-NEXT: Offset: 0x102E +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_INTERP +# PHDRS-UNUSED-NEXT: Offset: 0x102E +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_NOTE +# PHDRS-UNUSED-NEXT: Offset: 0x102E +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_SHLIB +# PHDRS-UNUSED-NEXT: Offset: 0x102E +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_PHDR +# PHDRS-UNUSED-NEXT: Offset: 0x102E +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x0 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x0 +# PHDRS-UNUSED-NEXT: FileSize: 0 +# PHDRS-UNUSED-NEXT: MemSize: 0 +# PHDRS-UNUSED-NEXT: Flags [ (0x0) +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 4096 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ] + +.globl _start; +_start: + mov $60, %rax + mov $42, %rdi + +.section .data,"aw" +.quad 10, 10, 20, 20 +.section .bss,"",@nobits +.short 0