Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -30,6 +30,20 @@ ELF64BEKind }; +struct OutputSectionDescription { + llvm::StringRef Name; + std::vector InputSections; + std::vector Phdrs; +}; + +struct Phdr { + llvm::StringRef Name; + uint32_t Flags = (uint32_t)-1; + uint32_t Type; + bool HasFileHdr; + bool HasPhdrs; +}; + // 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 +61,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,13 @@ void readOutput(); void readOutputArch(); void readOutputFormat(); + void readPhdrs(); void readSearchDir(); void readSections(); void readOutputSectionDescription(); + uint32_t readInteger(); + uint32_t readPhdrType(); StringSaver Saver; std::vector Tokens; @@ -81,6 +87,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 +153,12 @@ return Tokens[Pos++]; } +StringRef LinkerScript::peek() { + if (atEOF()) + error("unexpected EOF"); + return Tokens[Pos]; +} + bool LinkerScript::skip(StringRef Tok) { if (atEOF()) fatal("unexpected EOF"); @@ -276,6 +290,38 @@ expect(")"); } +uint32_t LinkerScript::readInteger() { + StringRef Tok = next(); + uint32_t Val; + if (Tok.getAsInteger(0, Val)) + error("Integer can't be parsed: " + Tok); + return Val; +} + +void LinkerScript::readPhdrs() { + expect("{"); + while (!skip("}")) { + Phdr &Hdr = *Config->Phdrs.emplace(Config->Phdrs.end(), Phdr{}); + Hdr.Name = next(); + Hdr.Type = readPhdrType(); + while (!skip(";")) { + StringRef Tok = next(); + if (Tok == "FLAGS") { + expect("("); + Hdr.Flags = readInteger(); + expect(")"); + continue; + } + if (Tok == "PHDRS") + Hdr.HasPhdrs = true; + else if (Tok == "FILEHDR") + Hdr.HasFileHdr = true; + else + error("Unknown header attribute " + Tok); + } + } +} + void LinkerScript::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); @@ -290,7 +336,8 @@ void LinkerScript::readOutputSectionDescription() { StringRef Name = next(); - std::vector &InputSections = Config->OutputSections[Name]; + OutputSectionDescription &OutSec = Config->OutputSections[Name]; + OutSec.Name = Name; expect(":"); expect("{"); @@ -298,10 +345,49 @@ 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; + + // Swallow peeked token. + next(); + // 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; + if (Tok == "PT_TLS") + return PT_TLS; + error("Wrong header type " + Tok); + return PT_NULL; +} + static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -19,6 +19,9 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/StringSaver.h" +#include +#include + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; @@ -41,6 +44,30 @@ void run(); private: + // This describes the programm header that will be created in output. + // Each contains type, access flags and list of output sections that will be + // placed in segment. + struct Phdr { + Phdr(unsigned Type = 0, unsigned Flags = 0, bool HasPhdrs = false, + bool HasFileHdr = false) + : Type(Type), Flags(Flags), HasPhdrs(HasPhdrs), HasFileHdr(HasFileHdr) { + } + unsigned Type; + unsigned Flags; + bool HasPhdrs = false; + bool HasFileHdr = false; + std::list *> OutSections; + }; + // Its a headers map which contains list of headers and also some additional + // parameters, like prefound IDs of specific headers. + struct PhdrMap { + std::vector> PhdrList; + size_t FirstLoadId = (size_t)-1; + size_t TlsPhdrId = (size_t)-1; + size_t RelroPhdrId = (size_t)-1; + size_t PhdrHdrId = (size_t)-1; + }; + void copyLocalSymbols(); void addReservedSymbols(); bool createSections(); @@ -53,7 +80,10 @@ void scanRelocs(InputSection &C); void scanRelocs(InputSectionBase &S, const Elf_Shdr &RelSec); void updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA); + PhdrMap scanHeaders(); + PhdrMap scanHeadersLinkerScript(); void assignAddresses(); + void finalizeHeaders(Elf_Phdr *PH, const Phdr &Map); void buildSectionMap(); void fixAbsoluteSymbols(); void openFile(StringRef OutputPath); @@ -67,7 +97,6 @@ bool isOutputDynamic() const { return !Symtab.getSharedFiles().empty() || Config->Shared; } - int getPhdrsNum() const; OutputSection *getBss(); void addCommonSymbols(std::vector &Syms); @@ -1123,138 +1152,341 @@ void Writer::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA) { if (!GnuRelroPhdr->p_type) - setPhdr(GnuRelroPhdr, PT_GNU_RELRO, PF_R, Cur->p_offset, Cur->p_vaddr, + setPhdr(GnuRelroPhdr, PT_GNU_RELRO, 0, Cur->p_offset, Cur->p_vaddr, VA - Cur->p_vaddr, 1 /*p_align*/); GnuRelroPhdr->p_filesz = VA - Cur->p_vaddr; 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); - - // 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(); +// This method generates some kind of map where each phdr +// is associated with zero or more output sections. +// Output structure contains final list of phdrs used. +// assignAddresses() will use this structure to assign addressed to sections. +template +typename Writer::PhdrMap Writer::scanHeaders() { + PhdrMap Map; + auto AddHdr = [this, &Map](unsigned Type, unsigned Flags) { + std::unique_ptr U = std::unique_ptr(new Phdr(Type, Flags)); + return Map.PhdrList.emplace(Map.PhdrList.end(), std::move(U))->get(); + }; // 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; + Phdr *PhdrHdr = AddHdr(PT_PHDR, PF_R); + PhdrHdr->HasPhdrs = true; + Map.PhdrHdrId = Map.PhdrList.size() - 1; // PT_INTERP must be the second entry if exists. - int PhdrIdx = 0; - Elf_Phdr *Interp = nullptr; - if (needsInterpSection()) - Interp = &Phdrs[++PhdrIdx]; + if (needsInterpSection()) { + Phdr *Hdr = AddHdr(PT_INTERP, toPhdrFlags(Out::Interp->getFlags())); + Hdr->OutSections.push_back(Out::Interp); + } // Add the first PT_LOAD segment for regular output sections. - setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, - Target->PageSize); + uintX_t Flags = PF_R; + Map.FirstLoadId = Map.PhdrList.size(); + Phdr *Load = AddHdr(PT_LOAD, Flags); + Load->HasPhdrs = true; + Load->HasFileHdr = true; - 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. + std::unique_ptr TlsHdr; 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 = alignTo(VA, Target->PageSize); - FileOff = alignTo(FileOff, Target->PageSize); - 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->PageSize); + // If flags changed then we want new load segment. + uintX_t NewFlags = toPhdrFlags(Sec->getFlags()); + if (Flags != NewFlags) { + uint32_t LoadType = (Config->EMachine == EM_AMDGPU) ? getAmdgpuPhdr(Sec) + : (uint32_t)PT_LOAD; + Load = AddHdr(LoadType, NewFlags); + Flags = NewFlags; } - + // If we meet TLS section then we create TLS header + // and put all TLS sections inside for futher use when + // assign addresses. 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 = alignTo(VA, Sec->getAlign()); - uintX_t TVA = alignTo(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 = alignTo(VA, Sec->getAlign()); - Sec->setVA(VA); - VA += Sec->getSize(); - if (InRelRo) - updateRelro(PH, &GnuRelroPhdr, VA); + if (!TlsHdr) + TlsHdr = std::unique_ptr(new Phdr(PT_TLS, PF_R)); + TlsHdr->OutSections.push_back(Sec); } } - - FileOff = alignTo(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; - } + Load->OutSections.push_back(Sec); } - 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 = alignTo(TlsPhdr.p_memsz, TlsPhdr.p_align); - Phdrs[++PhdrIdx] = TlsPhdr; - Out::TlsPhdr = &Phdrs[PhdrIdx]; + // TLS header. + if (TlsHdr) { + Map.TlsPhdrId = Map.PhdrList.size(); + Map.PhdrList.push_back(std::move(TlsHdr)); } // Add an entry for .dynamic. if (isOutputDynamic()) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_DYNAMIC; - copyPhdr(PH, Out::Dynamic); + Phdr *Hdr = AddHdr(PT_DYNAMIC, toPhdrFlags(Out::Dynamic->getFlags())); + Hdr->OutSections.push_back(Out::Dynamic); } + // PT_GNU_RELRO includes all sections that should be marked as + // read-only by dynamic linker after proccessing relocations. if (HasRelro) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - *PH = GnuRelroPhdr; + Map.RelroPhdrId = Map.PhdrList.size(); + AddHdr(PT_GNU_RELRO, PF_R); } + // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (Out::EhFrameHdr->Live) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_GNU_EH_FRAME; - copyPhdr(PH, Out::EhFrameHdr); + Phdr *Hdr = AddHdr(PT_GNU_EH_FRAME, toPhdrFlags(Out::EhFrameHdr->getFlags())); + Hdr->OutSections.push_back(Out::EhFrameHdr); } // 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 (!Config->ZExecStack) + AddHdr(PT_GNU_STACK, PF_R | PF_W); + + return Map; +} + +template +typename Writer::PhdrMap Writer::scanHeadersLinkerScript() { + PhdrMap Map; + auto AddHdr = [this, &Map](unsigned Type, bool HasPhdrs, bool HasFileHdr) { + std::unique_ptr U = + std::unique_ptr(new Phdr(Type, 0, HasPhdrs, HasFileHdr)); + return Map.PhdrList.emplace(Map.PhdrList.end(), std::move(U))->get(); + }; + + // Adds section Sec to each segment from the list Seg. If OnlyLoads is + // specified then all segments except PT_LOADS are ignored. + auto AddSec = [](std::vector &Seg, OutputSectionBase *Sec, + bool OnlyLoads = false) { + if (Seg.empty()) + error("No sections assigned to PHDRS"); + for (Phdr *Dest : Seg) { + if (Dest->Type != PT_LOAD && OnlyLoads) + continue; + Dest->OutSections.push_back(Sec); + Dest->Flags |= toPhdrFlags(Sec->getFlags()); + } + }; + + // Relro is not supported for linker script yet. + HasRelro = false; + + // Add each header specified in PHDRS, build + // association map for phdrs lookup by name. + llvm::DenseMap NameToPhdr; + for (size_t I = 0, E = Config->Phdrs.size(); I != E; ++I) { + lld::elf2::Phdr &PH = Config->Phdrs[I]; + if (!I) { + if (PH.Type != PT_PHDR) + error("First header is not PT_PHDR"); + if (!PH.HasPhdrs) + error("PHDRS is not set for PT_PHDR"); + } + + NameToPhdr[PH.Name] = AddHdr(PH.Type, PH.HasPhdrs, PH.HasFileHdr); + + // Remember indices of specific header types. + if (PH.Type == PT_LOAD && Map.FirstLoadId == (size_t)-1) { + // This is a restriction of current implementation: + // both FILEHDR and PHDRS must be set for first load segment. + if (!PH.HasFileHdr || !PH.HasPhdrs) + error("FILEHDR and PHDRS must be set for first PT_LOAD"); + Map.FirstLoadId = I; + } + if (PH.Type == PT_PHDR) + Map.PhdrHdrId = I; + if (PH.Type == PT_TLS) + Map.TlsPhdrId = I; + } + + // Add synthetic NONE header. Sectons can be assigned to it, + // but it will not be emited. + if (NameToPhdr.count("NONE")) + error("'NONE' is reserved alias for PHDRS"); + NameToPhdr["NONE"] = AddHdr(PT_NULL, false, false); + size_t SynNoneNdx = Map.PhdrList.size() - 1; + + // Build list of segments to attach the section to + auto CreateSegmentList = [&](StringRef Sec, std::vector Names) { + bool HasLoad = false; + std::vector Out; + for (StringRef N : Names) { + auto HdrInMap = NameToPhdr.find(N); + if (HdrInMap == NameToPhdr.end()) { + error("Section " + Sec + " assigned to non-existent header " + N); + return std::vector{}; + } + if (HdrInMap->second->Type == PT_LOAD) { + if (HasLoad) + error("Output section " + Sec + " in two PT_LOAD segments"); + HasLoad = true; + } + Out.push_back((*HdrInMap).second); + } + return Out; + }; + + // At first we should find the appropriate segments list for first output + // section(s). All sections will be put into this segment until we met the + // section that directly specifies where it should be placed to. + std::vector LastSeg; + for (OutputSectionBase *Sec : OutputSections) { + StringRef Name = Sec->getName(); + auto S = Config->OutputSections.find(Sec->getName()); + if (S == Config->OutputSections.end()) + continue; + LastSeg = CreateSegmentList(Name, S->second.Phdrs); + break; + } + + // Iterate over all output sections. Main aim is to assign + // them to the headers they belong to. + for (OutputSectionBase *Sec : OutputSections) { + if (HasError) + return PhdrMap(); + // Find the section with the same name in linker script parameters. + StringRef Name = Sec->getName(); + auto S = Config->OutputSections.find(Name); + + // If section do not list any phdrs to attach to, then it should be attached + // to lastest ones. The same is when there is no description at all for + // section, but we attach only to LOAD segments then. We don't attach it to + // other headers types because otherwise for example PT_INTERP segment will + // pick up following orphan sections, which does not make sense. + if (S == Config->OutputSections.end() || S->second.Phdrs.empty()) { + AddSec(LastSeg, Sec, S == Config->OutputSections.end()); + continue; + } + + // Build list of segments to attach the current section. + // And add the output section to each segment. + LastSeg = CreateSegmentList(Name, S->second.Phdrs); + AddSec(LastSeg, Sec); } - // Fix up PT_INTERP as we now know the address of .interp section. - if (Interp) { - Interp->p_type = PT_INTERP; - copyPhdr(Interp, Out::Interp); + // Erase synthetic "NONE" from final map. + Map.PhdrList.erase(Map.PhdrList.begin() + SynNoneNdx); + + // Assign flags that were set directly from linker script. + for (lld::elf2::Phdr &PH : Config->Phdrs) { + if (PH.Flags != (uint32_t)-1) + NameToPhdr[PH.Name]->Flags = PH.Flags; } + return Map; +} + +// Returns true if PHDRS command with headers is defined in linker script. +static bool hasCustomPhdrs() { return !Config->Phdrs.empty(); } + +static bool isLoadPhdr(unsigned H) { + return H == PT_LOAD || H == PT_AMDGPU_HSA_LOAD_CODE_AGENT || + H == PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM; +} + +// Visits all headers in PhdrMap and assigns the adresses to +// the output sections. Also creates common and special headers. +template void Writer::assignAddresses() { + // We know the final amount of program headers here. + PhdrMap Map = hasCustomPhdrs() ? scanHeadersLinkerScript() : scanHeaders(); + if (HasError) + return; + Phdrs.resize(Map.PhdrList.size()); + + bool RelroAligned = false; + uintX_t ThreadBssOffset = 0; + size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); + uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr) + PhdrSize; + uintX_t FileOff = sizeof(Elf_Ehdr) + PhdrSize; + + // Set up PT_PHDR right after ELF file header. + setPhdr(&Phdrs[0], 0, 0, FileOff - PhdrSize, VA - PhdrSize, PhdrSize, 8); + + // Main pass, here all load segments are processed and + // final addresses are assigned to all sections. + // Flags and header types are not assigned during pass. + // Them are assigned once for all headers at second pass. + for (size_t I = 0, E = Map.PhdrList.size(); I != E; ++I) { + std::unique_ptr &PHdr = Map.PhdrList[I]; + if (!isLoadPhdr(PHdr->Type)) + continue; + + Elf_Phdr *PH = &Phdrs[I]; + // New PT_LOAD is usually created when access flags were changed. + // If it is the very first load then it is special case, + // it contains elf header and program headers. + // Otherwise we need to align VA and FileOff to new memory page + // and create a new load. + const bool FirstLoad = (Map.FirstLoadId == I); + if (!FirstLoad) { + VA = alignTo(VA, Target->PageSize); + FileOff = alignTo(FileOff, Target->PageSize); + } + uintX_t Offset = FirstLoad ? 0 : FileOff; + uintX_t LoadVA = FirstLoad ? Target->getVAStart() : VA; + uintX_t LoadSize = FirstLoad ? FileOff : 0; + setPhdr(PH, 0, 0, Offset, LoadVA, LoadSize, Target->PageSize); + + for (OutputSectionBase *Sec : PHdr->OutSections) { + bool InRelRo = HasRelro && (PHdr->Flags & PF_W) && isRelroSection(Sec); + bool FirstNonRelRo = HasRelro && Phdrs[Map.RelroPhdrId].p_type && + needsPhdr(Sec) && !RelroAligned && !InRelRo; + // If this is a first non relro section after relro sequence then + // we want to align to page boundaries. We do this because we dont want + // any other sections except relro were marked as read only by dynamic + // loader. Them should be placed on a different memory page for that. + if (FirstNonRelRo) { + VA = alignTo(VA, Target->PageSize); + FileOff = alignTo(FileOff, Target->PageSize); + RelroAligned = true; + } + + if (needsPhdr(Sec)) { + bool IsTls = Sec->getFlags() & SHF_TLS; + // If we found TLS section we want to fill phdr parameters early + // because later we will not have its VA and FileOff. + if (IsTls && !Phdrs[Map.TlsPhdrId].p_vaddr) + setPhdr(&Phdrs[Map.TlsPhdrId], 0, 0, FileOff, VA, 0, 0); + + // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is + // responsible for allocating space for them, not the PT_LOAD that + // contains the TLS initialization image. + if (!IsTls || Sec->getType() != SHT_NOBITS) + VA = alignTo(VA, Sec->getAlign()); + + uintX_t TVA = alignTo(VA + ThreadBssOffset, Sec->getAlign()); + Sec->setVA(IsTls ? TVA : VA); + + if (IsTls && Sec->getType() == SHT_NOBITS) + ThreadBssOffset = TVA - VA + Sec->getSize(); + else + VA += Sec->getSize(); + + // If we are in relro then we need to update + // the GnuRelroPhdr header. + if (InRelRo) + updateRelro(PH, &Phdrs[Map.RelroPhdrId], VA); + } + + FileOff = alignTo(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; + } + } + } + + // Assign phdrs values in according to sections parameters attached. + // Each segment can contain zero, one or multiple sections assigned. + // Not just load segments but any others as well. That can be achieved usually + // with linker script. finalizeHeaders modifies each segment parameters and + // size + // in the way to cover all sections inside. + for (size_t I = 0, E = Map.PhdrList.size(); I != E; ++I) + finalizeHeaders(&Phdrs[I], *Map.PhdrList[I].get()); + // Add space for section headers. SectionHeaderOff = alignTo(FileOff, sizeof(uintX_t)); FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); @@ -1264,35 +1496,36 @@ ElfSym::End.st_value = VA; } -// Returns the number of PHDR entries. -template int Writer::getPhdrsNum() const { - bool Tls = false; - int I = 2; // 2 for PT_PHDR and first PT_LOAD - if (needsInterpSection()) - ++I; - if (isOutputDynamic()) - ++I; - if (!Config->ZExecStack) - ++I; - uintX_t Last = PF_R; - for (OutputSectionBase *Sec : OutputSections) { - if (!needsPhdr(Sec)) - continue; - if (Sec->getFlags() & SHF_TLS) - Tls = true; - uintX_t Flags = toPhdrFlags(Sec->getFlags()); - if (Last != Flags) { - Last = Flags; - ++I; +template +void Writer::finalizeHeaders(Elf_Phdr *PH, const Phdr &PHdr) { + // We already handled PT_LOAD and PT_PHDR and do not proccess them. + if (!isLoadPhdr(PHdr.Type) && PHdr.Type != PT_PHDR) { + for (OutputSectionBase *Sec : PHdr.OutSections) { + // Initially we initialize the header with parameters + // of first output section attached. + if (PH->p_memsz == 0 && PHdr.Type != PT_TLS) { + copyPhdr(PH, Sec); + continue; + } + // Here we extending the header size to cover all sections inside it. + if (Sec->getType() != SHT_NOBITS) + PH->p_filesz += Sec->getSize(); + PH->p_memsz += Sec->getSize(); + PH->p_align = std::max(PH->p_align, Sec->getAlign()); } } - if (Tls) - ++I; - if (HasRelro) - ++I; - if (Out::EhFrameHdr->Live) - ++I; - return I; + + // Set type and flags. + PH->p_type = PHdr.Type; + PH->p_flags = PHdr.Flags; + + // 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. + if (PHdr.Type == PT_TLS) { + if (PH->p_align) + PH->p_memsz = alignTo(PH->p_memsz, PH->p_align); + Out::TlsPhdr = PH; + } } static uint32_t getELFFlags() { @@ -1422,10 +1655,11 @@ } 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; + } } template void elf2::writeResult(SymbolTable *Symtab); Index: test/ELF/linkerscript-phdrs-errors.s =================================================================== --- test/ELF/linkerscript-phdrs-errors.s +++ test/ELF/linkerscript-phdrs-errors.s @@ -0,0 +1,106 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# 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 + +# Error if first header is not PT_PHDR. +# That the restriction of current implementation. +# RUN: echo "PHDRS { \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-NOT-PHDR %s < %t.log +# PHDRS-NOT-PHDR: First header is not PT_PHDR + +# Unknown header name causes error. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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: Section .data assigned to non-existent header unknown + +# In current implementation PHDRS should be set for PT_PHDR +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=PHDRS-ERRFLAG %s < %t.log +# PHDRS-ERRFLAG: PHDRS is not set for PT_PHDR + +# In current implementation FILEHDR and PHDRS +# keywords should be set for first PT_LOAD +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR; \ +# RUN: load PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=LOADS-NOFLAGS %s < %t.log +# LOADS-NOFLAGS: FILEHDR and PHDRS must be set for first PT_LOAD + +# Error if sections are not assigned to any headers. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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 NONE is used as phdr alias. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: NONE PT_LOAD FILEHDR PHDRS; \ +# 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=NONE-RESERVED %s < %t.log +# NONE-RESERVED: 'NONE' is reserved alias for PHDRS + +# Error if section is in two or more PT_LOAD segments +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: text PT_LOAD FILEHDR PHDRS; \ +# RUN: data PT_LOAD; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :text :data \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t > %t.log 2>&1 +# RUN: FileCheck -check-prefix=TWO-LOADS %s < %t.log +# TWO-LOADS: Output section .text in two PT_LOAD segments + +.globl _start; +_start: + nop + +.section .data,"aw" +.quad 10, 10, 20, 20 +.section .bss,"",@nobits +.short 0 Index: test/ELF/linkerscript-phdrs-flags.s =================================================================== --- test/ELF/linkerscript-phdrs-flags.s +++ test/ELF/linkerscript-phdrs-flags.s @@ -0,0 +1,64 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# Check FLAGS attribute for header (HEX). +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS FLAGS(0x2); \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t +# RUN: llvm-readobj -program-headers %t | \ +# RUN: FileCheck -check-prefix=PHDRS-FLAGS-HEX %s +# PHDRS-FLAGS-HEX: ProgramHeader { +# PHDRS-FLAGS-HEX: Type: PT_LOAD +# PHDRS-FLAGS-HEX: Flags [ (0x2) +# PHDRS-FLAGS-HEX-NEXT: PF_W (0x2) +# PHDRS-FLAGS-HEX-NEXT: ] + +# Check FLAGS attribute for header (OCT). +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS FLAGS(01); \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t +# RUN: llvm-readobj -program-headers %t | \ +# RUN: FileCheck -check-prefix=PHDRS-FLAGS-OCT %s +# PHDRS-FLAGS-OCT: ProgramHeader { +# PHDRS-FLAGS-OCT: Type: PT_LOAD +# PHDRS-FLAGS-OCT: Flags [ (0x1) +# PHDRS-FLAGS-OCT-NEXT: PF_X (0x1) +# PHDRS-FLAGS-OCT-NEXT: ] + +# Check FLAGS attribute for header (DEC). +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS FLAGS(7); \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :load \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t +# RUN: llvm-readobj -program-headers %t | \ +# RUN: FileCheck -check-prefix=PHDRS-FLAGS-DEC %s +# PHDRS-FLAGS-DEC: ProgramHeader { +# PHDRS-FLAGS-DEC: Type: PT_LOAD +# PHDRS-FLAGS-DEC: Flags [ (0x7) +# PHDRS-FLAGS-DEC-NEXT: PF_R (0x4) +# PHDRS-FLAGS-DEC-NEXT: PF_W (0x2) +# PHDRS-FLAGS-DEC-NEXT: PF_X (0x1) +# PHDRS-FLAGS-DEC-NEXT: ] + +.globl _start; +_start: + nop + +.section .data,"aw" +.quad 10, 10, 20, 20 +.section .bss,"",@nobits +.short 0 Index: test/ELF/linkerscript-phdrs-tls.s =================================================================== --- test/ELF/linkerscript-phdrs-tls.s +++ test/ELF/linkerscript-phdrs-tls.s @@ -0,0 +1,85 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t-tls + +# Map TLS sections to the specific header. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# RUN: tls PT_TLS; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .tdata : { *(.tdata) } :tls :load \ +# RUN: .tbss : { *(.tbss) } \ +# RUN: .text : { *(.text) } :load \ +# RUN: .data : { *(.data) } \ +# RUN: .bss : { *(.bss) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %ttls_1 --script %t.script %t-tls +# RUN: llvm-readobj -program-headers %ttls_1 | \ +# RUN: FileCheck -check-prefix=PHDRS-TLS %s +# RUN: llvm-objdump -section-headers %ttls_1 | \ +# RUN: FileCheck -check-prefix=SEC-TLS %s +# PHDRS-TLS: ProgramHeaders [ +# PHDRS-TLS-NEXT: ProgramHeader { +# PHDRS-TLS-NEXT: Type: PT_PHDR +# PHDRS-TLS-NEXT: Offset: 0x40 +# PHDRS-TLS-NEXT: VirtualAddress: 0x10040 +# PHDRS-TLS-NEXT: PhysicalAddress: 0x10040 +# PHDRS-TLS-NEXT: FileSize: 168 +# PHDRS-TLS-NEXT: MemSize: 168 +# PHDRS-TLS-NEXT: Flags [ +# PHDRS-TLS-NEXT: ] +# PHDRS-TLS-NEXT: Alignment: 8 +# PHDRS-TLS-NEXT: } +# PHDRS-TLS-NEXT: ProgramHeader { +# PHDRS-TLS-NEXT: Type: PT_LOAD +# PHDRS-TLS-NEXT: Offset: 0x0 +# PHDRS-TLS-NEXT: VirtualAddress: 0x10000 +# PHDRS-TLS-NEXT: PhysicalAddress: 0x10000 +# PHDRS-TLS-NEXT: FileSize: 297 +# PHDRS-TLS-NEXT: MemSize: 299 +# PHDRS-TLS-NEXT: Flags [ +# PHDRS-TLS-NEXT: PF_R +# PHDRS-TLS-NEXT: PF_W +# PHDRS-TLS-NEXT: PF_X +# PHDRS-TLS-NEXT: ] +# PHDRS-TLS-NEXT: Alignment: 4096 +# PHDRS-TLS-NEXT: } +# PHDRS-TLS-NEXT: ProgramHeader { +# PHDRS-TLS-NEXT: Type: PT_TLS +# PHDRS-TLS-NEXT: Offset: 0xE8 +# PHDRS-TLS-NEXT: VirtualAddress: 0x100E8 +# PHDRS-TLS-NEXT: PhysicalAddress: 0x100E8 +# PHDRS-TLS-NEXT: FileSize: 32 +# PHDRS-TLS-NEXT: MemSize: 34 +# PHDRS-TLS-NEXT: Flags [ +# PHDRS-TLS-NEXT: PF_R +# PHDRS-TLS-NEXT: PF_W +# PHDRS-TLS-NEXT: ] +# PHDRS-TLS-NEXT: Alignment: 1 +# PHDRS-TLS-NEXT: } +# PHDRS-TLS-NEXT: ] + +# Idx Name Size Address +# SEC-TLS: 0 00000000 0000000000000000 +# SEC-TLS-NEXT: 1 .tdata 00000020 00000000000100e8 DATA +# SEC-TLS-NEXT: 2 .tbss 00000002 0000000000010108 BSS +# SEC-TLS-NEXT: 3 .text 00000001 0000000000010108 TEXT DATA +# SEC-TLS-NEXT: 4 .data 00000020 0000000000010109 DATA +# SEC-TLS-NEXT: 5 .bss 00000002 0000000000010129 BSS +# SEC-TLS-NEXT: 6 .symtab 00000060 0000000000000000 +# SEC-TLS-NEXT: 7 .shstrtab 00000039 0000000000000000 +# SEC-TLS-NEXT: 8 .strtab 00000015 0000000000000000 + +.globl _start; +_start: + nop + +.section .data,"aw" +.quad 10, 10, 20, 20 +.section .bss,"",@nobits +.short 0 +.section .tbss,"awT",@nobits +.short 0 +.section .tdata,"awT" +.quad 20, 20, 10, 10 Index: test/ELF/linkerscript-phdrs.s =================================================================== --- test/ELF/linkerscript-phdrs.s +++ test/ELF/linkerscript-phdrs.s @@ -0,0 +1,585 @@ +# 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 -s -program-headers %t1 | \ +# RUN: FileCheck -check-prefix=PHDRS-DEFAULT %s +# PHDRS-DEFAULT: Sections [ +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 0 +# PHDRS-DEFAULT-NEXT: Name: (0) +# PHDRS-DEFAULT-NEXT: Type: SHT_NULL +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x0 +# PHDRS-DEFAULT-NEXT: Offset: 0x0 +# PHDRS-DEFAULT-NEXT: Size: 0 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 0 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 1 +# PHDRS-DEFAULT-NEXT: Name: .text +# PHDRS-DEFAULT-NEXT: Type: SHT_PROGBITS +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: SHF_ALLOC +# PHDRS-DEFAULT-NEXT: SHF_EXECINSTR +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x11000 +# PHDRS-DEFAULT-NEXT: Offset: 0x1000 +# PHDRS-DEFAULT-NEXT: Size: 14 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 4 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 2 +# PHDRS-DEFAULT-NEXT: Name: .data +# PHDRS-DEFAULT-NEXT: Type: SHT_PROGBITS +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: SHF_ALLOC +# PHDRS-DEFAULT-NEXT: SHF_WRITE +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x12000 +# PHDRS-DEFAULT-NEXT: Offset: 0x2000 +# PHDRS-DEFAULT-NEXT: Size: 32 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 1 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 3 +# PHDRS-DEFAULT-NEXT: Name: .bss +# PHDRS-DEFAULT-NEXT: Type: SHT_NOBITS +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: SHF_ALLOC +# PHDRS-DEFAULT-NEXT: SHF_WRITE +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x12020 +# PHDRS-DEFAULT-NEXT: Offset: 0x2020 +# PHDRS-DEFAULT-NEXT: Size: 2 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 1 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 4 +# PHDRS-DEFAULT-NEXT: Name: .symtab +# PHDRS-DEFAULT-NEXT: Type: SHT_SYMTAB +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x0 +# PHDRS-DEFAULT-NEXT: Offset: 0x2020 +# PHDRS-DEFAULT-NEXT: Size: 48 +# PHDRS-DEFAULT-NEXT: Link: 6 +# PHDRS-DEFAULT-NEXT: Info: 1 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 8 +# PHDRS-DEFAULT-NEXT: EntrySize: 24 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 5 +# PHDRS-DEFAULT-NEXT: Name: .shstrtab +# PHDRS-DEFAULT-NEXT: Type: SHT_STRTAB +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x0 +# PHDRS-DEFAULT-NEXT: Offset: 0x2050 +# PHDRS-DEFAULT-NEXT: Size: 44 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 1 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: Section { +# PHDRS-DEFAULT-NEXT: Index: 6 +# PHDRS-DEFAULT-NEXT: Name: .strtab +# PHDRS-DEFAULT-NEXT: Type: SHT_STRTAB +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Address: 0x0 +# PHDRS-DEFAULT-NEXT: Offset: 0x207C +# PHDRS-DEFAULT-NEXT: Size: 8 +# PHDRS-DEFAULT-NEXT: Link: 0 +# PHDRS-DEFAULT-NEXT: Info: 0 +# PHDRS-DEFAULT-NEXT: AddressAlignment: 1 +# PHDRS-DEFAULT-NEXT: EntrySize: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: ProgramHeaders [ +# PHDRS-DEFAULT-NEXT: ProgramHeader { +# PHDRS-DEFAULT-NEXT: Type: PT_PHDR +# PHDRS-DEFAULT-NEXT: Offset: 0x40 +# PHDRS-DEFAULT-NEXT: VirtualAddress: 0x10040 +# PHDRS-DEFAULT-NEXT: PhysicalAddress: 0x10040 +# PHDRS-DEFAULT-NEXT: FileSize: 280 +# PHDRS-DEFAULT-NEXT: MemSize: 280 +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: PF_R +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Alignment: 8 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ProgramHeader { +# PHDRS-DEFAULT-NEXT: Type: PT_LOAD +# PHDRS-DEFAULT-NEXT: Offset: 0x0 +# PHDRS-DEFAULT-NEXT: VirtualAddress: 0x10000 +# PHDRS-DEFAULT-NEXT: PhysicalAddress: 0x10000 +# PHDRS-DEFAULT-NEXT: FileSize: 344 +# PHDRS-DEFAULT-NEXT: MemSize: 344 +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: PF_R +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Alignment: 4096 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ProgramHeader { +# PHDRS-DEFAULT-NEXT: Type: PT_LOAD +# PHDRS-DEFAULT-NEXT: Offset: 0x1000 +# PHDRS-DEFAULT-NEXT: VirtualAddress: 0x11000 +# PHDRS-DEFAULT-NEXT: PhysicalAddress: 0x11000 +# PHDRS-DEFAULT-NEXT: FileSize: 14 +# PHDRS-DEFAULT-NEXT: MemSize: 14 +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: PF_R +# PHDRS-DEFAULT-NEXT: PF_X +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Alignment: 4096 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ProgramHeader { +# PHDRS-DEFAULT-NEXT: Type: PT_LOAD +# PHDRS-DEFAULT-NEXT: Offset: 0x2000 +# PHDRS-DEFAULT-NEXT: VirtualAddress: 0x12000 +# PHDRS-DEFAULT-NEXT: PhysicalAddress: 0x12000 +# PHDRS-DEFAULT-NEXT: FileSize: 32 +# PHDRS-DEFAULT-NEXT: MemSize: 34 +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: PF_R +# PHDRS-DEFAULT-NEXT: PF_W +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Alignment: 4096 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ProgramHeader { +# PHDRS-DEFAULT-NEXT: Type: PT_GNU_STACK +# PHDRS-DEFAULT-NEXT: Offset: 0x0 +# PHDRS-DEFAULT-NEXT: VirtualAddress: 0x0 +# PHDRS-DEFAULT-NEXT: PhysicalAddress: 0x0 +# PHDRS-DEFAULT-NEXT: FileSize: 0 +# PHDRS-DEFAULT-NEXT: MemSize: 0 +# PHDRS-DEFAULT-NEXT: Flags [ +# PHDRS-DEFAULT-NEXT: PF_R +# PHDRS-DEFAULT-NEXT: PF_W +# PHDRS-DEFAULT-NEXT: ] +# PHDRS-DEFAULT-NEXT: Alignment: 0 +# PHDRS-DEFAULT-NEXT: } +# PHDRS-DEFAULT-NEXT: ] + +# Map all sections to one header. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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_PHDR +# PHDRS-ONE-ALL-NEXT: Offset: 0x40 +# PHDRS-ONE-ALL-NEXT: VirtualAddress: 0x10040 +# PHDRS-ONE-ALL-NEXT: PhysicalAddress: 0x10040 +# PHDRS-ONE-ALL-NEXT: FileSize: 112 +# PHDRS-ONE-ALL-NEXT: MemSize: 112 +# PHDRS-ONE-ALL-NEXT: Flags [ +# PHDRS-ONE-ALL-NEXT: ] +# PHDRS-ONE-ALL-NEXT: Alignment: 8 +# PHDRS-ONE-ALL-NEXT: } +# PHDRS-ONE-ALL-NEXT: ProgramHeader { +# PHDRS-ONE-ALL-NEXT: Type: PT_LOAD +# PHDRS-ONE-ALL-NEXT: Offset: 0x0 +# PHDRS-ONE-ALL-NEXT: VirtualAddress: 0x10000 +# PHDRS-ONE-ALL-NEXT: PhysicalAddress: 0x10000 +# PHDRS-ONE-ALL-NEXT: FileSize: 222 +# PHDRS-ONE-ALL-NEXT: MemSize: 224 +# PHDRS-ONE-ALL-NEXT: Flags [ +# 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: 0 00000000 0000000000000000 +# SEC-ONE-ALL-NEXT: 1 .text 0000000e 00000000000100b0 TEXT DATA +# SEC-ONE-ALL-NEXT: 2 .data 00000020 00000000000100be DATA +# SEC-ONE-ALL-NEXT: 3 .bss 00000002 00000000000100de BSS +# SEC-ONE-ALL-NEXT: 4 .symtab 00000030 0000000000000000 +# SEC-ONE-ALL-NEXT: 5 .shstrtab 0000002c 0000000000000000 +# SEC-ONE-ALL-NEXT: 6 .strtab 00000008 0000000000000000 + +# Map all sections to one header, +# but separate the header name from the ':' sign. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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 sections to different headers explicitly. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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_PHDR +# PHDRS-DIFF-NEXT: Offset: 0x40 +# PHDRS-DIFF-NEXT: VirtualAddress: 0x10040 +# PHDRS-DIFF-NEXT: PhysicalAddress: 0x10040 +# PHDRS-DIFF-NEXT: FileSize: 168 +# PHDRS-DIFF-NEXT: MemSize: 168 +# PHDRS-DIFF-NEXT: Flags [ +# PHDRS-DIFF-NEXT: ] +# PHDRS-DIFF-NEXT: Alignment: 8 +# PHDRS-DIFF-NEXT: } +# PHDRS-DIFF-NEXT: ProgramHeader { +# PHDRS-DIFF-NEXT: Type: PT_LOAD +# PHDRS-DIFF-NEXT: Offset: 0x0 +# PHDRS-DIFF-NEXT: VirtualAddress: 0x10000 +# PHDRS-DIFF-NEXT: PhysicalAddress: 0x10000 +# PHDRS-DIFF-NEXT: FileSize: 278 +# PHDRS-DIFF-NEXT: MemSize: 278 +# PHDRS-DIFF-NEXT: Flags [ +# PHDRS-DIFF-NEXT: PF_R +# PHDRS-DIFF-NEXT: PF_W +# PHDRS-DIFF-NEXT: PF_X +# 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: 0x1000 +# PHDRS-DIFF-NEXT: VirtualAddress: 0x11000 +# PHDRS-DIFF-NEXT: PhysicalAddress: 0x11000 +# PHDRS-DIFF-NEXT: FileSize: 0 +# PHDRS-DIFF-NEXT: MemSize: 2 +# PHDRS-DIFF-NEXT: Flags [ +# PHDRS-DIFF-NEXT: PF_R +# PHDRS-DIFF-NEXT: PF_W +# PHDRS-DIFF-NEXT: ] +# PHDRS-DIFF-NEXT: Alignment: 4096 +# PHDRS-DIFF-NEXT: } +# PHDRS-DIFF-NEXT: ] +# SEC-DIFF: Idx Name Size Address Type +# SEC-DIFF-NEXT: 0 00000000 0000000000000000 +# SEC-DIFF-NEXT: 1 .text 0000000e 00000000000100e8 TEXT DATA +# SEC-DIFF-NEXT: 2 .data 00000020 00000000000100f6 DATA +# SEC-DIFF-NEXT: 3 .bss 00000002 0000000000011000 BSS +# SEC-DIFF-NEXT: 4 .symtab 00000030 0000000000000000 +# SEC-DIFF-NEXT: 5 .shstrtab 0000002c 0000000000000000 +# SEC-DIFF-NEXT: 6 .strtab 00000008 0000000000000000 + +# Map sections to different headers implicitly. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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: phdr PT_PHDR PHDRS; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# 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 + +# This shows that: +# 1) .interp is mapped to PT_INTERP segment. +# 2) Following sections like .text is an orphan section and not listed explicitely. +# They does not inherit any segment type other than PT_LOAD. +# That is reasonable behavior because otherwise PT_INTERP segment will pick up +# following orphan sections, which does not make sense. +# 3) .data is placed to data as specified. +# 4) .dynamic is placed both in dynamic and data segments. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: interp PT_INTERP; \ +# RUN: text PT_LOAD FILEHDR PHDRS; \ +# RUN: data PT_LOAD; \ +# RUN: dynamic PT_DYNAMIC; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .interp : { *(.interp) } :interp :text \ +# RUN: .data : { *(.data) } :data \ +# RUN: .dynamic : { *(.dynamic) } :data :dynamic \ +# RUN: }" > %t.script +# RUN: ld.lld -shared -o %t7.so %t +# RUN: ld.lld %t7.so -o %t7 -dynamic-linker /lib64/ld-linux-x86-64.so.2 --script %t.script %t +# RUN: llvm-readobj -program-headers %t7 | \ +# RUN: FileCheck -check-prefix=PHDRS-COMPLEX %s +# RUN: llvm-objdump -section-headers %t7 | \ +# RUN: FileCheck -check-prefix=SEC-COMPLEX %s +# PHDRS-COMPLEX: ProgramHeaders [ +# PHDRS-COMPLEX-NEXT: ProgramHeader { +# PHDRS-COMPLEX-NEXT: Type: PT_PHDR +# PHDRS-COMPLEX-NEXT: Offset: 0x40 +# PHDRS-COMPLEX-NEXT: VirtualAddress: 0x10040 +# PHDRS-COMPLEX-NEXT: PhysicalAddress: 0x10040 +# PHDRS-COMPLEX-NEXT: FileSize: 280 +# PHDRS-COMPLEX-NEXT: MemSize: 280 +# PHDRS-COMPLEX-NEXT: Flags [ +# PHDRS-COMPLEX-NEXT: ] +# PHDRS-COMPLEX-NEXT: Alignment: 8 +# PHDRS-COMPLEX-NEXT: } +# PHDRS-COMPLEX-NEXT: ProgramHeader { +# PHDRS-COMPLEX-NEXT: Type: PT_INTERP +# PHDRS-COMPLEX-NEXT: Offset: 0x158 +# PHDRS-COMPLEX-NEXT: VirtualAddress: 0x10158 +# PHDRS-COMPLEX-NEXT: PhysicalAddress: 0x10158 +# PHDRS-COMPLEX-NEXT: FileSize: 28 +# PHDRS-COMPLEX-NEXT: MemSize: 28 +# PHDRS-COMPLEX-NEXT: Flags [ +# PHDRS-COMPLEX-NEXT: PF_R +# PHDRS-COMPLEX-NEXT: ] +# PHDRS-COMPLEX-NEXT: Alignment: 1 +# PHDRS-COMPLEX-NEXT: } +# PHDRS-COMPLEX-NEXT: ProgramHeader { +# PHDRS-COMPLEX-NEXT: Type: PT_LOAD +# PHDRS-COMPLEX-NEXT: Offset: 0x0 +# PHDRS-COMPLEX-NEXT: VirtualAddress: 0x10000 +# PHDRS-COMPLEX-NEXT: PhysicalAddress: 0x10000 +# PHDRS-COMPLEX-NEXT: FileSize: 562 +# PHDRS-COMPLEX-NEXT: MemSize: 562 +# PHDRS-COMPLEX-NEXT: Flags [ +# PHDRS-COMPLEX-NEXT: PF_R +# PHDRS-COMPLEX-NEXT: PF_X +# PHDRS-COMPLEX-NEXT: ] +# PHDRS-COMPLEX-NEXT: Alignment: 4096 +# PHDRS-COMPLEX-NEXT: } +# PHDRS-COMPLEX-NEXT: ProgramHeader { +# PHDRS-COMPLEX-NEXT: Type: PT_LOAD +# PHDRS-COMPLEX-NEXT: Offset: 0x1000 +# PHDRS-COMPLEX-NEXT: VirtualAddress: 0x11000 +# PHDRS-COMPLEX-NEXT: PhysicalAddress: 0x11000 +# PHDRS-COMPLEX-NEXT: FileSize: 160 +# PHDRS-COMPLEX-NEXT: MemSize: 162 +# PHDRS-COMPLEX-NEXT: Flags [ +# PHDRS-COMPLEX-NEXT: PF_R +# PHDRS-COMPLEX-NEXT: PF_W +# PHDRS-COMPLEX-NEXT: ] +# PHDRS-COMPLEX-NEXT: Alignment: 4096 +# PHDRS-COMPLEX-NEXT: } +# PHDRS-COMPLEX-NEXT: ProgramHeader { +# PHDRS-COMPLEX-NEXT: Type: PT_DYNAMIC +# PHDRS-COMPLEX-NEXT: Offset: 0x1020 +# PHDRS-COMPLEX-NEXT: VirtualAddress: 0x11020 +# PHDRS-COMPLEX-NEXT: PhysicalAddress: 0x11020 +# PHDRS-COMPLEX-NEXT: FileSize: 128 +# PHDRS-COMPLEX-NEXT: MemSize: 128 +# PHDRS-COMPLEX-NEXT: Flags [ +# PHDRS-COMPLEX-NEXT: PF_R +# PHDRS-COMPLEX-NEXT: PF_W +# PHDRS-COMPLEX-NEXT: ] +# PHDRS-COMPLEX-NEXT: Alignment: 8 +# PHDRS-COMPLEX-NEXT: } +# PHDRS-COMPLEX-NEXT: ] +# SEC-COMPLEX: Sections: +# SEC-COMPLEX-NEXT: Idx Name Size Address Type +# SEC-COMPLEX-NEXT: 0 00000000 0000000000000000 +# SEC-COMPLEX-NEXT: 1 .interp 0000001c 0000000000010158 DATA +# SEC-COMPLEX-NEXT: 2 .dynsym 00000030 0000000000010178 +# SEC-COMPLEX-NEXT: 3 .hash 00000018 00000000000101a8 +# SEC-COMPLEX-NEXT: 4 .dynstr 00000061 00000000000101c0 +# SEC-COMPLEX-NEXT: 5 .text 0000000e 0000000000010224 TEXT DATA +# SEC-COMPLEX-NEXT: 6 .data 00000020 0000000000011000 DATA +# SEC-COMPLEX-NEXT: 7 .dynamic 00000080 0000000000011020 +# SEC-COMPLEX-NEXT: 8 .bss 00000002 00000000000110a0 BSS +# SEC-COMPLEX-NEXT: 9 .symtab 00000030 0000000000000000 +# SEC-COMPLEX-NEXT: 10 .shstrtab 00000053 0000000000000000 +# SEC-COMPLEX-NEXT: 11 .strtab 00000008 0000000000000000 + +# Check that all header types are allowed and all unused are present. +# RUN: echo "PHDRS { \ +# RUN: phdr PT_PHDR PHDRS; \ +# RUN: null PT_NULL; \ +# RUN: load PT_LOAD FILEHDR PHDRS; \ +# RUN: dynamic PT_DYNAMIC; \ +# RUN: interp PT_INTERP; \ +# RUN: note PT_NOTE; \ +# RUN: shlib PT_SHLIB; \ +# RUN: tls PT_TLS; \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .text : { *(.text) } :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-UNUSED %s +# PHDRS-UNUSED: ProgramHeaders [ +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_PHDR +# PHDRS-UNUSED-NEXT: Offset: 0x40 +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x10040 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x10040 +# PHDRS-UNUSED-NEXT: FileSize: 448 +# PHDRS-UNUSED-NEXT: MemSize: 448 +# PHDRS-UNUSED-NEXT: Flags [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 8 +# PHDRS-UNUSED-NEXT: } +# 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_LOAD +# PHDRS-UNUSED-NEXT: Offset: 0x0 +# PHDRS-UNUSED-NEXT: VirtualAddress: 0x10000 +# PHDRS-UNUSED-NEXT: PhysicalAddress: 0x10000 +# PHDRS-UNUSED-NEXT: FileSize: 558 +# PHDRS-UNUSED-NEXT: MemSize: 560 +# PHDRS-UNUSED-NEXT: Flags [ +# 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: 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_INTERP +# 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_NOTE +# 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_SHLIB +# 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# PHDRS-UNUSED-NEXT: } +# PHDRS-UNUSED-NEXT: ProgramHeader { +# PHDRS-UNUSED-NEXT: Type: PT_TLS +# 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 [ +# PHDRS-UNUSED-NEXT: ] +# PHDRS-UNUSED-NEXT: Alignment: 0 +# 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