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.
This commit is contained in:
Dimitry Andric 2020-01-29 16:57:55 +00:00
parent ae55765309
commit b9f5806c25
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang1000-import/; revision=357259
2 changed files with 27 additions and 19 deletions

View File

@ -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<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();

View File

@ -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