svn commit: r357259 - projects/clang1000-import/contrib/llvm-project/lld/ELF
Dimitry Andric
dim at FreeBSD.org
Wed Jan 29 16:57:56 UTC 2020
Author: dim
Date: Wed Jan 29 16:57:55 2020
New Revision: 357259
URL: https://svnweb.freebsd.org/changeset/base/357259
Log:
Revert upstream lld r371957 (git commit 06bb7dfbd) by Fangrui Song:
[ELF] Map the ELF header at imageBase
If there is no readonly section, we map:
* The ELF header at imageBase+maxPageSize
* Program headers at imageBase+maxPageSize+sizeof(Ehdr)
* The first section .text at imageBase+maxPageSize+sizeof(Ehdr)+sizeof(program headers)
Due to the interaction between Writer<ELFT>::fixSectionAlignments and
LinkerScript::allocateHeaders,
`alignDown(p_vaddr(R PT_LOAD)) = alignDown(p_vaddr(RX PT_LOAD))`.
The RX PT_LOAD will override the R PT_LOAD at runtime, which is not ideal:
```
// PHDR at 0x401034, should be 0x400034
PHDR 0x000034 0x00401034 0x00401034 0x000a0 0x000a0 R 0x4
// R PT_LOAD contains just Ehdr and program headers.
// At 0x401000, should be 0x400000
LOAD 0x000000 0x00401000 0x00401000 0x000d4 0x000d4 R 0x1000
LOAD 0x0000d4 0x004010d4 0x004010d4 0x00001 0x00001 R E 0x1000
```
* createPhdrs allocates the headers to the R PT_LOAD.
* fixSectionAlignments assigns `imageBase+maxPageSize+sizeof(Ehdr)+sizeof(program headers)` (formula: `alignTo(dot, maxPageSize) + dot % config->maxPageSize`) to addrExpr of .text
* allocateHeaders computes the minimum address among SHF_ALLOC sections, i.e. addr(.text)
* allocateHeaders sets address of ELF header to `addr(.text)-sizeof(Ehdr)-sizeof(program headers) = imageBase+maxPageSize`
The main observation is that when the SECTIONS command is not used, we
don't have to call allocateHeaders. This requires an assumption that
the presence of PT_PHDR and addresses of headers can be decided
regardless of address information.
This may seem natural because dot is not manipulated by a linker script.
The other thing is that we have to drop the special rule for -T<section>
in `getInitialDot`. If -Ttext is smaller than the image base, the headers
will not be allocated with the old behavior (allocateHeaders is called)
but always allocated with the new behavior.
The behavior change is not a problem. Whether and where headers are
allocated can vary among linkers, or ld.bfd across different versions
(--enable-separate-code or not). It is thus advised to use a linker
script with the PHDRS command to have a consistent behavior across
linkers. If PT_PHDR is needed, an explicit --image-base can be a simpler
alternative.
Differential Revision: https://reviews.llvm.org/D67325
llvm-svn: 371957
This causes "ld: error: output file too large: 18446744073707016908
bytes" when linking our loader_4th and loader_lua. Clearly, something
is wrong when using -Ttext 0x0: I will file an upstream bug report for
this.
Modified:
projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp
projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp
Modified: projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp
==============================================================================
--- projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp Wed Jan 29 16:52:12 2020 (r357258)
+++ projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp Wed Jan 29 16:57:55 2020 (r357259)
@@ -1020,13 +1020,17 @@ static uint64_t computeBase(uint64_t min, bool allocat
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<PhdrEntry *> &phdrs) {
uint64_t min = std::numeric_limits<uint64_t>::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<section> have been sorted in order of ascending
+ // address. We must lower startAddr if the lowest -T<section address> 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<AddressState>();
ctx = deleter.get();
Modified: projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp
==============================================================================
--- projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp Wed Jan 29 16:52:12 2020 (r357258)
+++ projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp Wed Jan 29 16:57:55 2020 (r357259)
@@ -569,8 +569,7 @@ template <class ELFT> void Writer<ELFT>::run() {
for (OutputSection *sec : outputSections)
sec->maybeCompress<ELFT>();
- 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
More information about the svn-src-projects
mailing list