diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lld/ELF/InputSection.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) | |
download | src-cfca06d7963fa0909f90483b42a6d7d194d01e08.tar.gz src-cfca06d7963fa0909f90483b42a6d7d194d01e08.zip |
Vendor import of llvm-project master 2e10b7a39b9, the last commit beforevendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9vendor/llvm-project/master
the llvmorg-12-init tag, from which release/11.x was branched.
Notes
Notes:
svn path=/vendor/llvm-project/master/; revision=363578
svn path=/vendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9/; revision=363579; tag=vendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9
Diffstat (limited to 'lld/ELF/InputSection.cpp')
-rw-r--r-- | lld/ELF/InputSection.cpp | 166 |
1 files changed, 127 insertions, 39 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index aab272f53a73..7a7ebd974909 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -36,16 +36,17 @@ using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace llvm::sys; +using namespace lld; +using namespace lld::elf; + +std::vector<InputSectionBase *> elf::inputSections; +DenseSet<std::pair<const Symbol *, uint64_t>> elf::ppc64noTocRelax; -namespace lld { // Returns a string to construct an error message. -std::string toString(const elf::InputSectionBase *sec) { +std::string lld::toString(const InputSectionBase *sec) { return (toString(sec->file) + ":(" + sec->name + ")").str(); } -namespace elf { -std::vector<InputSectionBase *> inputSections; - template <class ELFT> static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &file, const typename ELFT::Shdr &hdr) { @@ -138,7 +139,7 @@ size_t InputSectionBase::getSize() const { return s->getSize(); if (uncompressedSize >= 0) return uncompressedSize; - return rawData.size(); + return rawData.size() - bytesDropped; } void InputSectionBase::uncompress() const { @@ -307,7 +308,7 @@ std::string InputSectionBase::getLocation(uint64_t offset) { // File->sourceFile contains STT_FILE symbol that contains a // source file name. If it's missing, we use an object file name. - std::string srcFile = getFile<ELFT>()->sourceFile; + std::string srcFile = std::string(getFile<ELFT>()->sourceFile); if (srcFile.empty()) srcFile = toString(file); @@ -338,7 +339,7 @@ std::string InputSectionBase::getSrcMsg(const Symbol &sym, uint64_t offset) { // // path/to/foo.o:(function bar) in archive path/to/bar.a std::string InputSectionBase::getObjMsg(uint64_t off) { - std::string filename = file->getName(); + std::string filename = std::string(file->getName()); std::string archive; if (!file->archiveName.empty()) @@ -438,12 +439,12 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) { // hopefully creates a frame that is ignored at runtime. Also, don't warn // on .gcc_except_table and debug sections. // - // See the comment in maybeReportUndefined for PPC64 .toc . + // See the comment in maybeReportUndefined for PPC32 .got2 and PPC64 .toc auto *d = dyn_cast<Defined>(&sym); if (!d) { - if (!sec->name.startswith(".debug") && - !sec->name.startswith(".zdebug") && sec->name != ".eh_frame" && - sec->name != ".gcc_except_table" && sec->name != ".toc") { + if (!isDebugSection(*sec) && sec->name != ".eh_frame" && + sec->name != ".gcc_except_table" && sec->name != ".got2" && + sec->name != ".toc") { uint32_t secIdx = cast<Undefined>(sym).discardedSecIdx; Elf_Shdr_Impl<ELFT> sec = CHECK(file->getObj().sections(), file)[secIdx]; @@ -465,7 +466,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) { if (!RelTy::IsRela) addend = target->getImplicitAddend(bufLoc, type); - if (config->emachine == EM_MIPS && config->relocatable && + if (config->emachine == EM_MIPS && target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) { // Some MIPS relocations depend on "gp" value. By default, // this value has 0x7ff0 offset from a .got section. But @@ -485,6 +486,14 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) { p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; else if (config->relocatable && type != target->noneRel) sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); + } else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 && + p->r_addend >= 0x8000) { + // Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24 + // indicates that r30 is relative to the input section .got2 + // (r_addend>=0x8000), after linking, r30 should be relative to the output + // section .got2 . To compensate for the shift, adjust r_addend by + // ppc32Got2OutSecOff. + p->r_addend += sec->file->ppc32Got2OutSecOff; } } } @@ -518,9 +527,14 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: case R_ARM_REL32: + case R_ARM_THM_ALU_PREL_11_0: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: + case R_ARM_THM_PC12: return p + a; + // p + a is unrepresentable as negative immediates can't be encoded. + case R_ARM_THM_PC8: + return p; } llvm_unreachable("ARM pc-relative relocation expected\n"); } @@ -542,6 +556,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_PLT32: return p + a; } llvm_unreachable("AArch64 pc-relative relocation expected\n"); @@ -637,6 +652,7 @@ static int64_t getTlsTpOffset(const Symbol &s) { // Variant 2. case EM_HEXAGON: + case EM_SPARCV9: case EM_386: case EM_X86_64: return s.getVA(0) - tls->p_memsz - @@ -646,8 +662,9 @@ static int64_t getTlsTpOffset(const Symbol &s) { } } -static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, - uint64_t p, const Symbol &sym, RelExpr expr) { +uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, + int64_t a, uint64_t p, + const Symbol &sym, RelExpr expr) { switch (expr) { case R_ABS: case R_DTPREL: @@ -695,7 +712,7 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf // microMIPS variants of these relocations use slightly different // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() - // to correctly handle less-sugnificant bit of the microMIPS symbol. + // to correctly handle less-significant bit of the microMIPS symbol. uint64_t v = in.mipsGot->getGp(file) + a - p; if (type == R_MIPS_LO16 || type == R_MICROMIPS_LO16) v += 4; @@ -732,8 +749,12 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, *hiRel->sym, hiRel->expr); return 0; } - case R_PC: { + case R_PC: + case R_ARM_PCA: { uint64_t dest; + if (expr == R_ARM_PCA) + // Some PC relative ARM (Thumb) relocations align down the place. + p = p & 0xfffffffc; if (sym.isUndefWeak()) { // On ARM and AArch64 a branch to an undefined weak resolves to the // next instruction, otherwise the place. @@ -788,7 +809,7 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // --noinhibit-exec, even a non-weak undefined reference may reach here. // Just return A, which matches R_ABS, and the behavior of some dynamic // loaders. - if (sym.isUndefined()) + if (sym.isUndefined() || sym.isLazy()) return a; return getTlsTpOffset(sym) + a; case R_RELAX_TLS_GD_TO_LE_NEG: @@ -832,6 +853,16 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, template <class ELFT, class RelTy> void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { const unsigned bits = sizeof(typename ELFT::uint) * 8; + const bool isDebug = isDebugSection(*this); + const bool isDebugLocOrRanges = + isDebug && (name == ".debug_loc" || name == ".debug_ranges"); + const bool isDebugLine = isDebug && name == ".debug_line"; + Optional<uint64_t> tombstone; + for (const auto &patAndValue : llvm::reverse(config->deadRelocInNonAlloc)) + if (patAndValue.first.match(this->name)) { + tombstone = patAndValue.second; + break; + } for (const RelTy &rel : rels) { RelType type = rel.getType(config->isMips64EL); @@ -854,11 +885,17 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { if (expr == R_NONE) continue; + if (expr == R_SIZE) { + target->relocateNoSym(bufLoc, type, + SignExtend64<bits>(sym.getSize() + addend)); + continue; + } + if (expr != R_ABS && expr != R_DTPREL && expr != R_RISCV_ADD) { std::string msg = getLocation<ELFT>(offset) + ": has non-ABS relocation " + toString(type) + " against symbol '" + toString(sym) + "'"; - if (expr != R_PC) { + if (expr != R_PC && expr != R_ARM_PCA) { error(msg); return; } @@ -871,15 +908,49 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { // address 0. For bug-compatibilty, we accept them with warnings. We // know Steel Bank Common Lisp as of 2018 have this bug. warn(msg); - target->relocateOne(bufLoc, type, - SignExtend64<bits>(sym.getVA(addend - offset))); + target->relocateNoSym(bufLoc, type, + SignExtend64<bits>(sym.getVA(addend - offset))); continue; } - if (sym.isTls() && !Out::tlsPhdr) - target->relocateOne(bufLoc, type, 0); - else - target->relocateOne(bufLoc, type, SignExtend64<bits>(sym.getVA(addend))); + if (tombstone || + (isDebug && (type == target->symbolicRel || expr == R_DTPREL))) { + // Resolve relocations in .debug_* referencing (discarded symbols or ICF + // folded section symbols) to a tombstone value. Resolving to addend is + // unsatisfactory because the result address range may collide with a + // valid range of low address, or leave multiple CUs claiming ownership of + // the same range of code, which may confuse consumers. + // + // To address the problems, we use -1 as a tombstone value for most + // .debug_* sections. We have to ignore the addend because we don't want + // to resolve an address attribute (which may have a non-zero addend) to + // -1+addend (wrap around to a low address). + // + // R_DTPREL type relocations represent an offset into the dynamic thread + // vector. The computed value is st_value plus a non-negative offset. + // Negative values are invalid, so -1 can be used as the tombstone value. + // + // If the referenced symbol is discarded (made Undefined), or the + // section defining the referenced symbol is garbage collected, + // sym.getOutputSection() is nullptr. `ds->section->repl != ds->section` + // catches the ICF folded case. However, resolving a relocation in + // .debug_line to -1 would stop debugger users from setting breakpoints on + // the folded-in function, so exclude .debug_line. + // + // For pre-DWARF-v5 .debug_loc and .debug_ranges, -1 is a reserved value + // (base address selection entry), so -2 is used. + auto *ds = dyn_cast<Defined>(&sym); + if (!sym.getOutputSection() || + (ds && ds->section->repl != ds->section && !isDebugLine)) { + // If -z dead-reloc-in-nonalloc= is specified, respect it. + const uint64_t value = + tombstone ? SignExtend64<bits>(*tombstone) + : (isDebugLocOrRanges ? UINT64_MAX - 1 : UINT64_MAX); + target->relocateNoSym(bufLoc, type, value); + continue; + } + } + target->relocateNoSym(bufLoc, type, SignExtend64<bits>(sym.getVA(addend))); } } @@ -896,7 +967,7 @@ static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) { assert(rel.expr == R_ABS); uint8_t *bufLoc = buf + rel.offset + sec->outSecOff; uint64_t targetVA = SignExtend64(rel.sym->getVA(rel.addend), bits); - target->relocateOne(bufLoc, rel.type, targetVA); + target->relocate(bufLoc, rel, targetVA); } } @@ -924,6 +995,8 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { const unsigned bits = config->wordsize * 8; for (const Relocation &rel : relocations) { + if (rel.expr == R_NONE) + continue; uint64_t offset = rel.offset; if (auto *sec = dyn_cast<InputSection>(this)) offset += sec->outSecOff; @@ -939,29 +1012,35 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { switch (expr) { case R_RELAX_GOT_PC: case R_RELAX_GOT_PC_NOPIC: - target->relaxGot(bufLoc, type, targetVA); + target->relaxGot(bufLoc, rel, targetVA); break; case R_PPC64_RELAX_TOC: - if (!tryRelaxPPC64TocIndirection(type, rel, bufLoc)) - target->relocateOne(bufLoc, type, targetVA); + // rel.sym refers to the STT_SECTION symbol associated to the .toc input + // section. If an R_PPC64_TOC16_LO (.toc + addend) references the TOC + // entry, there may be R_PPC64_TOC16_HA not paired with + // R_PPC64_TOC16_LO_DS. Don't relax. This loses some relaxation + // opportunities but is safe. + if (ppc64noTocRelax.count({rel.sym, rel.addend}) || + !tryRelaxPPC64TocIndirection(rel, bufLoc)) + target->relocate(bufLoc, rel, targetVA); break; case R_RELAX_TLS_IE_TO_LE: - target->relaxTlsIeToLe(bufLoc, type, targetVA); + target->relaxTlsIeToLe(bufLoc, rel, targetVA); break; case R_RELAX_TLS_LD_TO_LE: case R_RELAX_TLS_LD_TO_LE_ABS: - target->relaxTlsLdToLe(bufLoc, type, targetVA); + target->relaxTlsLdToLe(bufLoc, rel, targetVA); break; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_GD_TO_LE_NEG: - target->relaxTlsGdToLe(bufLoc, type, targetVA); + target->relaxTlsGdToLe(bufLoc, rel, targetVA); break; case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_RELAX_TLS_GD_TO_IE: case R_RELAX_TLS_GD_TO_IE_ABS: case R_RELAX_TLS_GD_TO_IE_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_GOTPLT: - target->relaxTlsGdToIe(bufLoc, type, targetVA); + target->relaxTlsGdToIe(bufLoc, rel, targetVA); break; case R_PPC64_CALL: // If this is a call to __tls_get_addr, it may be part of a TLS @@ -986,13 +1065,25 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { } write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) } - target->relocateOne(bufLoc, type, targetVA); + target->relocate(bufLoc, rel, targetVA); break; default: - target->relocateOne(bufLoc, type, targetVA); + target->relocate(bufLoc, rel, targetVA); break; } } + + // Apply jumpInstrMods. jumpInstrMods are created when the opcode of + // a jmp insn must be modified to shrink the jmp insn or to flip the jmp + // insn. This is primarily used to relax and optimize jumps created with + // basic block sections. + if (auto *sec = dyn_cast<InputSection>(this)) { + for (const JumpInstrMod &jumpMod : jumpInstrMods) { + uint64_t offset = jumpMod.offset + sec->outSecOff; + uint8_t *bufLoc = buf + offset; + target->applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size); + } + } } // For each function-defining prologue, find any calls to __morestack, @@ -1090,7 +1181,7 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf, end, f->stOther)) continue; if (!getFile<ELFT>()->someNoSplitStack) - error(toString(this) + ": " + f->getName() + + error(lld::toString(this) + ": " + f->getName() + " (with -fsplit-stack) calls " + rel.sym->getName() + " (without -fsplit-stack), but couldn't adjust its prologue"); } @@ -1353,6 +1444,3 @@ template void EhInputSection::split<ELF32LE>(); template void EhInputSection::split<ELF32BE>(); template void EhInputSection::split<ELF64LE>(); template void EhInputSection::split<ELF64BE>(); - -} // namespace elf -} // namespace lld |