diff --git a/contrib/llvm-project/lld/ELF/LinkerScript.cpp b/contrib/llvm-project/lld/ELF/LinkerScript.cpp index 57e0e1e8acbf..9da1e807b103 100644 --- a/contrib/llvm-project/lld/ELF/LinkerScript.cpp +++ b/contrib/llvm-project/lld/ELF/LinkerScript.cpp @@ -1020,13 +1020,17 @@ static uint64_t computeBase(uint64_t min, bool allocateHeaders) { return alignDown(min, config->maxPageSize); } -// When the SECTIONS command is used, try to find an address for the file and -// program headers output sections, which can be added to the first PT_LOAD -// segment when program headers are created. +// Try to find an address for the file and program headers output sections, +// which were unconditionally added to the first PT_LOAD segment earlier. // -// We check if the headers fit below the first allocated section. If there isn't -// enough space for these sections, we'll remove them from the PT_LOAD segment, -// and we'll also remove the PT_PHDR segment. +// When using the default layout, we check if the headers fit below the first +// allocated section. When using a linker script, we also check if the headers +// are covered by the output section. This allows omitting the headers by not +// leaving enough space for them in the linker script; this pattern is common +// in embedded systems. +// +// If there isn't enough space for these sections, we'll remove them from the +// PT_LOAD segment, and we'll also remove the PT_PHDR segment. void LinkerScript::allocateHeaders(std::vector &phdrs) { uint64_t min = std::numeric_limits::max(); for (OutputSection *sec : outputSections) @@ -1072,23 +1076,28 @@ LinkerScript::AddressState::AddressState() { } } +static uint64_t getInitialDot() { + // By default linker scripts use an initial value of 0 for '.', + // but prefer -image-base if set. + if (script->hasSectionsCommand) + return config->imageBase ? *config->imageBase : 0; + + uint64_t startAddr = UINT64_MAX; + // The sections with -T
have been sorted in order of ascending + // address. We must lower startAddr if the lowest -T
as + // calls to setDot() must be monotonically increasing. + for (auto &kv : config->sectionStartMap) + startAddr = std::min(startAddr, kv.second); + return std::min(startAddr, target->getImageBase() + elf::getHeaderSize()); +} + // Here we assign addresses as instructed by linker script SECTIONS // sub-commands. Doing that allows us to use final VA values, so here // we also handle rest commands like symbol assignments and ASSERTs. // Returns a symbol that has changed its section or value, or nullptr if no // symbol has changed. const Defined *LinkerScript::assignAddresses() { - if (script->hasSectionsCommand) { - // With a linker script, assignment of addresses to headers is covered by - // allocateHeaders(). - dot = config->imageBase.getValueOr(0); - } else { - // Assign addresses to headers right now. - dot = target->getImageBase(); - Out::elfHeader->addr = dot; - Out::programHeaders->addr = dot + Out::elfHeader->size; - dot += getHeaderSize(); - } + dot = getInitialDot(); auto deleter = std::make_unique(); ctx = deleter.get(); diff --git a/contrib/llvm-project/lld/ELF/Writer.cpp b/contrib/llvm-project/lld/ELF/Writer.cpp index ac332de2a057..2434dc5fb5d8 100644 --- a/contrib/llvm-project/lld/ELF/Writer.cpp +++ b/contrib/llvm-project/lld/ELF/Writer.cpp @@ -569,8 +569,7 @@ template void Writer::run() { for (OutputSection *sec : outputSections) sec->maybeCompress(); - if (script->hasSectionsCommand) - script->allocateHeaders(mainPart->phdrs); + script->allocateHeaders(mainPart->phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses