diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index b99ddd7dfd68..53daaa6743d9 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -748,19 +748,10 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { } 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. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index be3a070d082d..9dfb907c3c11 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -89,6 +89,7 @@ private: uintX_t FileSize; uintX_t SectionHeaderOff; + bool AllocateHeader = true; }; } // anonymous namespace @@ -192,15 +193,6 @@ template void Writer::run() { 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 { @@ -533,6 +525,17 @@ static bool compareSectionsNonScript(const OutputSectionBase *A, 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; @@ -1038,6 +1041,16 @@ template void Writer::finalizeSections() { 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. @@ -1159,10 +1172,6 @@ template std::vector Writer::createPhdrs() { // 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); @@ -1270,7 +1279,7 @@ void Writer::addPtArmExid(std::vector &Phdrs) { // 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) { @@ -1288,6 +1297,23 @@ template void Writer::fixSectionAlignments() { } } +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. @@ -1296,6 +1322,25 @@ template void Writer::fixHeaders() { // 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; @@ -1303,7 +1348,9 @@ template void Writer::fixHeaders() { // 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; @@ -1682,6 +1729,15 @@ template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); +template void elf::allocateHeaders(MutableArrayRef, + ArrayRef); +template void elf::allocateHeaders(MutableArrayRef, + ArrayRef); +template void elf::allocateHeaders(MutableArrayRef, + ArrayRef); +template void elf::allocateHeaders(MutableArrayRef, + ArrayRef); + template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h index 94d707ff4c57..96dd70b109d5 100644 --- a/lld/ELF/Writer.h +++ b/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 @@ struct PhdrEntry { llvm::StringRef getOutputSectionName(llvm::StringRef Name); +template +void allocateHeaders(llvm::MutableArrayRef, + llvm::ArrayRef); template void reportDiscarded(InputSectionBase *IS); template uint32_t getMipsEFlags(); diff --git a/lld/test/ELF/ttext-tdata-tbss.s b/lld/test/ELF/ttext-tdata-tbss.s new file mode 100644 index 000000000000..c31c56e75692 --- /dev/null +++ b/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