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; +}; + struct Configuration { SymbolBody *EntrySym = nullptr; InputFile *FirstElf = nullptr; @@ -42,7 +53,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,17 @@ expect(")"); } +void LinkerScript::readPhdrs() { + expect("{"); + while (!skip("}")) { + Config->Phdrs.emplace_back(); + Phdr &PH = Config->Phdrs.back(); + PH.Name = next(); + PH.Type = readPhdrType(); + expect(";"); + } +} + void LinkerScript::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); @@ -290,7 +314,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 +323,43 @@ next(); // Skip input file name. expect("("); while (!skip(")")) - InputSections.push_back(next()); + OutSec.InputSections.push_back(next()); } + + // Read headers of the section. + while (true) { + 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 @@ -51,6 +51,7 @@ OutputSectionBase *Sec, uintX_t VA); void assignAddresses(); void buildSectionMap(); + void buildPhdrMap(); void openFile(StringRef OutputPath); void writeHeader(); void writeSections(); @@ -90,7 +91,10 @@ uintX_t FileSize; uintX_t SectionHeaderOff; + typedef llvm::SmallVector IndicesVector; llvm::StringMap InputToOutputSection; + llvm::StringMap> OutputSectionToPhdrs; + llvm::SmallMapVector PhdrNameToIndices; }; } // anonymous namespace @@ -141,6 +145,7 @@ // The main function of the writer. template void Writer::run() { buildSectionMap(); + buildPhdrMap(); if (!Config->DiscardAll) copyLocalSymbols(); createSections(); @@ -824,6 +829,22 @@ return Ret; } +static bool hasCustomPhdrs() { return !Config->Phdrs.empty(); } + +static bool isNonePhdr(const std::vector &Phdrs) { + return Phdrs.size() == 1 && Phdrs[0] == "NONE"; +} + +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, OutputSectionBase *Sec, uintX_t VA) { @@ -847,102 +868,194 @@ Phdrs.resize(getPhdrsNum()); size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); - // 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; + if (!hasCustomPhdrs()) { + // 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; + + // 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{}; + uintX_t ThreadBSSOffset = 0; + // Create phdrs as we assign VAs and file offsets to all output sections. + for (OutputSectionBase *Sec : OutputSections) { + if (needsPhdr(Sec)) { + uintX_t Flags = toPhdrFlags(Sec->getFlags()); + if (Phdrs[PhdrIdx].p_flags != Flags) { + // Flags changed. Create a new PT_LOAD. + VA = RoundUpToAlignment(VA, Target->getPageSize()); + FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); + Elf_Phdr *PH = &Phdrs[++PhdrIdx]; + setPhdr(PH, PT_LOAD, Flags, FileOff, VA, 0, Target->getPageSize()); + } - // PT_INTERP must be the second entry if exists. - int PhdrIdx = 0; - Elf_Phdr *Interp = nullptr; - if (needsInterpSection()) - Interp = &Phdrs[++PhdrIdx]; + 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 = RoundUpToAlignment(VA, Sec->getAlign()); + uintX_t TVA = + RoundUpToAlignment(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 = RoundUpToAlignment(VA, Sec->getAlign()); + Sec->setVA(VA); + VA += Sec->getSize(); + updateRelro(&Phdrs[PhdrIdx], &GnuRelroPhdr, Sec, VA); + } + } - // Add the first PT_LOAD segment for regular output sections. - setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, - Target->getPageSize()); + FileOff = RoundUpToAlignment(FileOff, Sec->getAlign()); + Sec->setFileOffset(FileOff); + if (Sec->getType() != SHT_NOBITS) + FileOff += Sec->getSize(); + if (needsPhdr(Sec)) { + Elf_Phdr *Cur = &Phdrs[PhdrIdx]; + Cur->p_filesz = FileOff - Cur->p_offset; + Cur->p_memsz = VA - Cur->p_vaddr; + } + } - Elf_Phdr GnuRelroPhdr = {}; - Elf_Phdr TlsPhdr{}; - uintX_t ThreadBSSOffset = 0; - // Create phdrs as we assign VAs and file offsets to all output sections. - for (OutputSectionBase *Sec : OutputSections) { - if (needsPhdr(Sec)) { - uintX_t Flags = toPhdrFlags(Sec->getFlags()); - if (Phdrs[PhdrIdx].p_flags != Flags) { - // Flags changed. Create a new PT_LOAD. - VA = RoundUpToAlignment(VA, Target->getPageSize()); - FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - setPhdr(PH, PT_LOAD, Flags, FileOff, VA, 0, Target->getPageSize()); + 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 = RoundUpToAlignment(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); + } + } else { + SmallMapVector PhdrsToFill = PhdrNameToIndices; + std::vector PhdrNames; + for (OutputSectionBase *Sec : OutputSections) { + const std::vector &NewPhdrNames = + OutputSectionToPhdrs.lookup(Sec->getName()); + bool PhdrsChanged = false; + if (!NewPhdrNames.empty()) { + // Headers really changed if they are not a direct subset + // of the previous set of headers. + PhdrsChanged = !isSubset(PhdrNames, NewPhdrNames); + PhdrNames = NewPhdrNames; } - 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 = RoundUpToAlignment(VA, Sec->getAlign()); - uintX_t TVA = RoundUpToAlignment(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(); + // Find appropriate headers for the first section if not defined. + if (PhdrNames.empty()) + for (size_t I = 1, Len = OutputSections.size(); I < Len; ++I) { + const std::vector &NewPhdrNames = + OutputSectionToPhdrs.lookup(OutputSections[I]->getName()); + if (!NewPhdrNames.empty()) { + PhdrsChanged = true; + PhdrNames = NewPhdrNames; + break; + } + } + + const bool IsNonePhdr = isNonePhdr(PhdrNames); + IndicesVector PhdrInds; + if (!IsNonePhdr) + for (StringRef Name : PhdrNames) { + auto It = PhdrNameToIndices.find(Name); + if (It == std::end(PhdrNameToIndices)) + error("Output section " + Sec->getName() + + " assigned to non-existent header " + Name); + std::copy(std::begin(It->second), std::end(It->second), + std::back_inserter(PhdrInds)); } - TlsPhdr.p_align = std::max(TlsPhdr.p_align, Sec->getAlign()); - } else { + + if (needsPhdr(Sec) && !IsNonePhdr) { + if (PhdrsChanged) { + VA = RoundUpToAlignment(VA, Target->getPageSize()); + FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); + 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()); + } + } + VA = RoundUpToAlignment(VA, Sec->getAlign()); Sec->setVA(VA); VA += Sec->getSize(); - updateRelro(&Phdrs[PhdrIdx], &GnuRelroPhdr, Sec, VA); } - } - FileOff = RoundUpToAlignment(FileOff, Sec->getAlign()); - Sec->setFileOffset(FileOff); - if (Sec->getType() != SHT_NOBITS) - FileOff += Sec->getSize(); - if (needsPhdr(Sec)) { - Elf_Phdr *Cur = &Phdrs[PhdrIdx]; - Cur->p_filesz = FileOff - Cur->p_offset; - Cur->p_memsz = VA - Cur->p_vaddr; + FileOff = RoundUpToAlignment(FileOff, Sec->getAlign()); + Sec->setFileOffset(FileOff); + if (Sec->getType() != SHT_NOBITS) + FileOff += Sec->getSize(); + if (needsPhdr(Sec) && !IsNonePhdr) { + 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 = RoundUpToAlignment(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); - } + // Fixup not used headers from PHDRS command. + for (const std::pair &p : PhdrsToFill) + for (size_t Ind : p.second) { + const Phdr &PH = Config->Phdrs[Ind]; - 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); + 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 space for section headers. @@ -960,6 +1073,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()) @@ -1085,10 +1201,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 lld::elf2::writeResult(SymbolTable *Symtab); Index: test/ELF/linkerscript-phdrs.s =================================================================== --- /dev/null +++ test/ELF/linkerscript-phdrs.s @@ -0,0 +1,587 @@ +# 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 + +# 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 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 0000000000000000 +# 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