Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -748,19 +748,10 @@ } uintX_t HeaderSize = getHeaderSize(); - auto FirstPTLoad = - std::find_if(Phdrs.begin(), Phdrs.end(), - [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); - if (FirstPTLoad == Phdrs.end()) - return; - // If the linker script doesn't have PHDRS, add ElfHeader and ProgramHeaders // now that we know we have space. - if (HeaderSize <= MinVA && !hasPhdrsCommands()) { - FirstPTLoad->First = Out::ElfHeader; - if (!FirstPTLoad->Last) - FirstPTLoad->Last = Out::ProgramHeaders; - } + if (HeaderSize <= MinVA && !hasPhdrsCommands()) + allocateHeaders(Phdrs, *OutputSections); // ELF and Program headers need to be right before the first section in // memory. Set their addresses accordingly. Index: lld/ELF/Writer.h =================================================================== --- lld/ELF/Writer.h +++ lld/ELF/Writer.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_WRITER_H #define LLD_ELF_WRITER_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include #include @@ -48,6 +49,9 @@ llvm::StringRef getOutputSectionName(llvm::StringRef Name); +template +void allocateHeaders(llvm::MutableArrayRef Phdrs, + llvm::ArrayRef OutputSections); template void reportDiscarded(InputSectionBase *IS); template uint32_t getMipsEFlags(); Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -89,6 +89,7 @@ uintX_t FileSize; uintX_t SectionHeaderOff; + bool AllocateHeader = true; }; } // anonymous namespace @@ -192,15 +193,6 @@ if (Config->Relocatable) { assignFileOffsets(); } else { - // Binary output does not have PHDRS. - if (!Config->OFormatBinary) { - Phdrs = Script::X->hasPhdrsCommands() - ? Script::X->createPhdrs() - : createPhdrs(); - addPtArmExid(Phdrs); - fixHeaders(); - } - if (ScriptConfig->HasSections) { Script::X->assignAddresses(Phdrs); } else { @@ -527,6 +519,17 @@ if (!AIsAlloc) return false; + // We want to put section specified by -T option first, so we + // can start assigning VA starting from them later. + auto AAddrSetI = Config->SectionStartMap.find(A->getName()); + auto BAddrSetI = Config->SectionStartMap.find(B->getName()); + bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end(); + bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end(); + if (AHasAddrSet != BHasAddrSet) + return AHasAddrSet; + if (AHasAddrSet) + return AAddrSetI->second < BAddrSetI->second; + // We want the read only sections first so that they go in the PT_LOAD // covering the program headers at the start of the file. bool AIsWritable = A->Flags & SHF_WRITE; @@ -1032,6 +1035,16 @@ Sec->ShName = In::ShStrTab->addString(Sec->getName()); } + // Binary and relocatable output does not have PHDRS. + // The headers have to be created before finalize as that can influence the + // image base and the dynamic section on mips includes the image base. + if (!Config->Relocatable && !Config->OFormatBinary) { + Phdrs = Script::X->hasPhdrsCommands() ? Script::X->createPhdrs() + : createPhdrs(); + addPtArmExid(Phdrs); + fixHeaders(); + } + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. @@ -1153,10 +1166,6 @@ // Add the first PT_LOAD segment for regular output sections. uintX_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); - if (!ScriptConfig->HasSections) { - Load->add(Out::ElfHeader); - Load->add(Out::ProgramHeaders); - } PhdrEntry TlsHdr(PT_TLS, PF_R); PhdrEntry RelRo(PT_GNU_RELRO, PF_R); @@ -1264,7 +1273,7 @@ // have to be page aligned so that the dynamic linker can set the permissions. template void Writer::fixSectionAlignments() { for (const PhdrEntry &P : Phdrs) - if (P.p_type == PT_LOAD) + if (P.p_type == PT_LOAD && P.First) P.First->PageAlign = true; for (const PhdrEntry &P : Phdrs) { @@ -1282,6 +1291,23 @@ } } +template +void elf::allocateHeaders(MutableArrayRef Phdrs, + ArrayRef OutputSections) { + auto FirstPTLoad = + std::find_if(Phdrs.begin(), Phdrs.end(), + [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); + if (FirstPTLoad == Phdrs.end()) + return; + if (FirstPTLoad->First) + for (OutputSectionBase *Sec : OutputSections) + if (Sec->FirstInPtLoad == FirstPTLoad->First) + Sec->FirstInPtLoad = Out::ElfHeader; + FirstPTLoad->First = Out::ElfHeader; + if (!FirstPTLoad->Last) + FirstPTLoad->Last = Out::ProgramHeaders; +} + // We should set file offsets and VAs for elf header and program headers // sections. These are special, we do not include them into output sections // list, but have them to simplify the code. @@ -1290,6 +1316,25 @@ // If the script has SECTIONS, assignAddresses will compute the values. if (ScriptConfig->HasSections) return; + + uintX_t HeaderSize = getHeaderSize(); + // When -T
option is specified, lower the base to make room for those + // sections. + if (!Config->SectionStartMap.empty()) { + uint64_t Min = -1; + for (const auto &P : Config->SectionStartMap) + Min = std::min(Min, P.second); + if (HeaderSize < Min) + Min -= HeaderSize; + else + AllocateHeader = false; + if (Min < Config->ImageBase) + Config->ImageBase = alignDown(Min, Config->MaxPageSize); + } + + if (AllocateHeader) + allocateHeaders(Phdrs, OutputSections); + uintX_t BaseVA = Config->ImageBase; Out::ElfHeader->Addr = BaseVA; Out::ProgramHeaders->Addr = BaseVA + Out::ElfHeader->Size; @@ -1297,7 +1342,9 @@ // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { - uintX_t VA = Config->ImageBase + getHeaderSize(); + uintX_t VA = Config->ImageBase; + if (AllocateHeader) + VA += getHeaderSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->Addralign; @@ -1676,6 +1723,19 @@ template void elf::writeResult(); template void elf::writeResult(); +template void +elf::allocateHeaders(MutableArrayRef Phdrs, + ArrayRef OutputSections); +template void +elf::allocateHeaders(MutableArrayRef Phdrs, + ArrayRef OutputSections); +template void +elf::allocateHeaders(MutableArrayRef Phdrs, + ArrayRef OutputSections); +template void +elf::allocateHeaders(MutableArrayRef Phdrs, + ArrayRef OutputSections); + template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); Index: lld/test/ELF/ttext-tdata-tbss.s =================================================================== --- /dev/null +++ lld/test/ELF/ttext-tdata-tbss.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +## Show what regular output gives to us. +# RUN: ld.lld %t.o -o %t1 +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck %s +# CHECK: .rodata PROGBITS 0000000000200158 000158 000008 +# CHECK-NEXT: .text PROGBITS 0000000000201000 001000 000001 +# CHECK-NEXT: .aw PROGBITS 0000000000202000 002000 000008 +# CHECK-NEXT: .data PROGBITS 0000000000202008 002008 000008 +# CHECK-NEXT: .bss NOBITS 0000000000202010 002010 000008 +# CHECK: PHDR +# CHECK-NEXT: LOAD 0x000000 0x0000000000200000 + +## With .text at 0 there is no space to allocate the headers. +# RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2 +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s --check-prefix=USER1 +# USER1: .text PROGBITS 0000000000000000 001000 000001 +# USER1-NEXT: .data PROGBITS 0000000000004000 002000 000008 +# USER1-NEXT: .bss NOBITS 0000000000008000 002008 000008 +# USER1-NEXT: .rodata PROGBITS 0000000000009000 003000 000008 +# USER1-NEXT: .aw PROGBITS 000000000000a000 004000 000008 +# USER1: PHDR +# USER1-NEXT: LOAD 0x001000 0x0000000000000000 + +## With .text at 0x1000 there is space to allocate the headers. +# RUN: ld.lld -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3 +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck %s --check-prefix=USER2 +# USER2: .text PROGBITS 0000000000001000 001000 000001 +# USER2-NEXT: .data PROGBITS 0000000000004000 002000 000008 +# USER2-NEXT: .bss NOBITS 0000000000008000 002008 000008 +# USER2-NEXT: .rodata PROGBITS 0000000000009000 003000 000008 +# USER2-NEXT: .aw PROGBITS 000000000000a000 004000 000008 +# USER2: PHDR +# USER2-NEXT: LOAD 0x000000 0x0000000000000000 + +## With .text well above 200000 we don't need to change the image base +# RUN: ld.lld -Ttext 0x201000 %t.o -o %t4 +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t4 | FileCheck %s --check-prefix=USER3 +# USER3: .text PROGBITS 0000000000201000 001000 000001 +# USER3-NEX: .rodata PROGBITS 0000000000202000 002000 000008 +# USER3-NEX: .aw PROGBITS 0000000000203000 003000 000008 +# USER3-NEX: .data PROGBITS 0000000000203008 003008 000008 +# USER3-NEX: .bss NOBITS 0000000000203010 003010 000008 +# USER3: PHDR +# USER3-NEXT: LOAD 0x000000 0x0000000000200000 + +.text +.globl _start +_start: + nop + +.section .rodata,"a" + .quad 0 + +.section .aw,"aw" + .quad 0 + +.section .data,"aw" + .quad 0 + +.section .bss,"",@nobits + .quad 0