diff options
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 13 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 21 | ||||
-rw-r--r-- | lld/test/ELF/linkerscript-phdr-check.s | 15 |
3 files changed, 39 insertions, 10 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 0bc7dd6d7f9..d10fc5bc629 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -21,6 +21,7 @@ #include "ScriptParser.h" #include "Strings.h" #include "SymbolTable.h" +#include "Target.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" @@ -220,7 +221,8 @@ void LinkerScript<ELFT>::assignAddresses( } // Assign addresses as instructed by linker script SECTIONS sub-commands. - Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize(); + Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize(); + uintX_t MinVA = std::numeric_limits<uintX_t>::max(); uintX_t ThreadBssOffset = 0; for (SectionsCommand &Cmd : Opt.Commands) { @@ -247,11 +249,20 @@ void LinkerScript<ELFT>::assignAddresses( if (Sec->getFlags() & SHF_ALLOC) { Dot = alignTo(Dot, Sec->getAlignment()); Sec->setVA(Dot); + MinVA = std::min(MinVA, Dot); Dot += Sec->getSize(); continue; } } } + + // ELF and Program headers need to be right before the first section in memory. + // Set their addresses accordingly. + MinVA = alignDown(MinVA - Out<ELFT>::ElfHeader->getSize() - + Out<ELFT>::ProgramHeaders->getSize(), + Target->PageSize); + Out<ELFT>::ElfHeader->setVA(MinVA); + Out<ELFT>::ProgramHeaders->setVA(Out<ELFT>::ElfHeader->getSize() + MinVA); } template <class ELFT> diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 28036d3dbeb..799580d9a27 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1131,11 +1131,9 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { // list, but have them to simplify the code. template <class ELFT> void Writer<ELFT>::fixHeaders() { uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Target->getVAStart(); - Out<ELFT>::ElfHeader->setVA(BaseVA); - Out<ELFT>::ElfHeader->setFileOffset(0); + Out<ELFT>::ElfHeader->setVA(BaseVA); uintX_t Off = Out<ELFT>::ElfHeader->getSize(); - Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA); - Out<ELFT>::ProgramHeaders->setFileOffset(Off); + Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA); } // Assign VAs (addresses at run-time) to output sections. @@ -1183,19 +1181,24 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) { // Assign file offsets to output sections. template <class ELFT> void Writer<ELFT>::assignFileOffsets() { - uintX_t Off = - Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize(); + uintX_t Off = 0; - for (OutputSectionBase<ELFT> *Sec : OutputSections) { + auto Set = [&](OutputSectionBase<ELFT> *Sec) { if (Sec->getType() == SHT_NOBITS) { Sec->setFileOffset(Off); - continue; + return; } Off = getFileAlignment<ELFT>(Off, Sec); Sec->setFileOffset(Off); Off += Sec->getSize(); - } + }; + + Set(Out<ELFT>::ElfHeader); + Set(Out<ELFT>::ProgramHeaders); + for (OutputSectionBase<ELFT> *Sec : OutputSections) + Set(Sec); + SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); } diff --git a/lld/test/ELF/linkerscript-phdr-check.s b/lld/test/ELF/linkerscript-phdr-check.s new file mode 100644 index 00000000000..c7229ed3312 --- /dev/null +++ b/lld/test/ELF/linkerscript-phdr-check.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_PHDR (0x6) +# CHECK-NEXT: Offset: 0x40 +# CHECK-NEXT: VirtualAddress: 0xFFFF040 + +.global _start +_start: + nop |