diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /lld/ELF/InputSection.cpp | |
parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
download | src-c0981da47d5696fe36474fcf86b4ce03ae3ff818.tar.gz src-c0981da47d5696fe36474fcf86b4ce03ae3ff818.zip |
Diffstat (limited to 'lld/ELF/InputSection.cpp')
-rw-r--r-- | lld/ELF/InputSection.cpp | 152 |
1 files changed, 73 insertions, 79 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 1f9fa961fc26..74d4dd309c79 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -70,9 +70,6 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, if (sectionKind == SectionBase::Merge && rawData.size() > UINT32_MAX) error(toString(this) + ": section too large"); - numRelocations = 0; - areRelocsRela = false; - // The ELF spec states that a value of 0 means the section has // no alignment constraints. uint32_t v = std::max<uint32_t>(alignment, 1); @@ -88,7 +85,22 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, if (!zlib::isAvailable()) error(toString(file) + ": contains a compressed section, " + "but zlib is not available"); - parseCompressedHeader(); + switch (config->ekind) { + case ELF32LEKind: + parseCompressedHeader<ELF32LE>(); + break; + case ELF32BEKind: + parseCompressedHeader<ELF32BE>(); + break; + case ELF64LEKind: + parseCompressedHeader<ELF64LE>(); + break; + case ELF64BEKind: + parseCompressedHeader<ELF64BE>(); + break; + default: + llvm_unreachable("unknown ELFT"); + } } } @@ -102,32 +114,14 @@ static uint64_t getFlags(uint64_t flags) { return flags; } -// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of -// March 2017) fail to infer section types for sections starting with -// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of -// SHF_INIT_ARRAY. As a result, the following assembler directive -// creates ".init_array.100" with SHT_PROGBITS, for example. -// -// .section .init_array.100, "aw" -// -// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle -// incorrect inputs as if they were correct from the beginning. -static uint64_t getType(uint64_t type, StringRef name) { - if (type == SHT_PROGBITS && name.startswith(".init_array.")) - return SHT_INIT_ARRAY; - if (type == SHT_PROGBITS && name.startswith(".fini_array.")) - return SHT_FINI_ARRAY; - return type; -} - template <class ELFT> InputSectionBase::InputSectionBase(ObjFile<ELFT> &file, const typename ELFT::Shdr &hdr, StringRef name, Kind sectionKind) - : InputSectionBase(&file, getFlags(hdr.sh_flags), - getType(hdr.sh_type, name), hdr.sh_entsize, hdr.sh_link, - hdr.sh_info, hdr.sh_addralign, - getSectionContents(file, hdr), name, sectionKind) { + : InputSectionBase(&file, getFlags(hdr.sh_flags), hdr.sh_type, + hdr.sh_entsize, hdr.sh_link, hdr.sh_info, + hdr.sh_addralign, getSectionContents(file, hdr), name, + sectionKind) { // We reject object files having insanely large alignments even though // they are allowed by the spec. I think 4GB is a reasonable limitation. // We might want to relax this in the future. @@ -165,6 +159,25 @@ uint64_t InputSectionBase::getOffsetInFile() const { return secStart - fileStart; } +template <class ELFT> RelsOrRelas<ELFT> InputSectionBase::relsOrRelas() const { + if (relSecIdx == 0) + return {}; + RelsOrRelas<ELFT> ret; + const ELFFile<ELFT> obj = cast<ELFFileBase>(file)->getObj<ELFT>(); + typename ELFT::Shdr shdr = cantFail(obj.sections())[relSecIdx]; + if (shdr.sh_type == SHT_REL) { + ret.rels = makeArrayRef(reinterpret_cast<const typename ELFT::Rel *>( + obj.base() + shdr.sh_offset), + shdr.sh_size / sizeof(typename ELFT::Rel)); + } else { + assert(shdr.sh_type == SHT_RELA); + ret.relas = makeArrayRef(reinterpret_cast<const typename ELFT::Rela *>( + obj.base() + shdr.sh_offset), + shdr.sh_size / sizeof(typename ELFT::Rela)); + } + return ret; +} + uint64_t SectionBase::getOffset(uint64_t offset) const { switch (kind()) { case Output: { @@ -210,10 +223,7 @@ OutputSection *SectionBase::getOutputSection() { // When a section is compressed, `rawData` consists with a header followed // by zlib-compressed data. This function parses a header to initialize // `uncompressedSize` member and remove the header from `rawData`. -void InputSectionBase::parseCompressedHeader() { - using Chdr64 = typename ELF64LE::Chdr; - using Chdr32 = typename ELF32LE::Chdr; - +template <typename ELFT> void InputSectionBase::parseCompressedHeader() { // Old-style header if (name.startswith(".zdebug")) { if (!toStringRef(rawData).startswith("ZLIB")) { @@ -239,32 +249,13 @@ void InputSectionBase::parseCompressedHeader() { assert(flags & SHF_COMPRESSED); flags &= ~(uint64_t)SHF_COMPRESSED; - // New-style 64-bit header - if (config->is64) { - if (rawData.size() < sizeof(Chdr64)) { - error(toString(this) + ": corrupted compressed section"); - return; - } - - auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { - error(toString(this) + ": unsupported compression type"); - return; - } - - uncompressedSize = hdr->ch_size; - alignment = std::max<uint32_t>(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); - return; - } - - // New-style 32-bit header - if (rawData.size() < sizeof(Chdr32)) { + // New-style header + if (rawData.size() < sizeof(typename ELFT::Chdr)) { error(toString(this) + ": corrupted compressed section"); return; } - auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data()); + auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data()); if (hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; @@ -293,32 +284,21 @@ Defined *InputSectionBase::getEnclosingFunction(uint64_t offset) { return nullptr; } -// Returns a source location string. Used to construct an error message. +// Returns an object file location string. Used to construct an error message. template <class ELFT> std::string InputSectionBase::getLocation(uint64_t offset) { - std::string secAndOffset = (name + "+0x" + utohexstr(offset)).str(); + std::string secAndOffset = + (name + "+0x" + Twine::utohexstr(offset) + ")").str(); // We don't have file for synthetic sections. if (getFile<ELFT>() == nullptr) - return (config->outputFile + ":(" + secAndOffset + ")") - .str(); - - // First check if we can get desired values from debugging information. - if (Optional<DILineInfo> info = getFile<ELFT>()->getDILineInfo(this, offset)) - return info->FileName + ":" + std::to_string(info->Line) + ":(" + - secAndOffset + ")"; - - // 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 = std::string(getFile<ELFT>()->sourceFile); - if (srcFile.empty()) - srcFile = toString(file); + return (config->outputFile + ":(" + secAndOffset).str(); + std::string file = toString(getFile<ELFT>()); if (Defined *d = getEnclosingFunction<ELFT>(offset)) - return srcFile + ":(function " + toString(*d) + ": " + secAndOffset + ")"; + return file + ":(function " + toString(*d) + ": " + secAndOffset; - // If there's no symbol, print out the offset in the section. - return (srcFile + ":(" + secAndOffset + ")"); + return file + ":(" + secAndOffset; } // This function is intended to be used for constructing an error message. @@ -515,6 +495,7 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, switch (type) { // Unresolved branch relocations to weak references resolve to next // instruction, this will be either 2 or 4 bytes on from P. + case R_ARM_THM_JUMP8: case R_ARM_THM_JUMP11: return p + 2 + a; case R_ARM_CALL: @@ -802,6 +783,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_PLT_PC: case R_PPC64_CALL_PLT: return sym.getPltVA() + a - p; + case R_PLT_GOTPLT: + return sym.getPltVA() + a - in.gotPlt->getVA(); case R_PPC32_PLTREL: // R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30 // stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for @@ -836,7 +819,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, // --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() || sym.isLazy()) + if (sym.isUndefined()) return a; return getTlsTpOffset(sym) + a; case R_RELAX_TLS_GD_TO_LE_NEG: @@ -850,6 +833,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, return in.got->getGlobalDynAddr(sym) + a; case R_TLSDESC_PC: return in.got->getGlobalDynAddr(sym) + a - p; + case R_TLSDESC_GOTPLT: + return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA(); case R_AARCH64_TLSDESC_PAGE: return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) - getAArch64Page(p); @@ -1016,12 +1001,15 @@ void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) { } auto *sec = cast<InputSection>(this); - if (config->relocatable) + if (config->relocatable) { relocateNonAllocForRelocatable(sec, buf); - else if (sec->areRelocsRela) - sec->relocateNonAlloc<ELFT>(buf, sec->template relas<ELFT>()); - else - sec->relocateNonAlloc<ELFT>(buf, sec->template rels<ELFT>()); + } else { + const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>(); + if (rels.areRelocsRel()) + sec->relocateNonAlloc<ELFT>(buf, rels.rels); + else + sec->relocateNonAlloc<ELFT>(buf, rels.relas); + } } void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { @@ -1335,10 +1323,11 @@ static unsigned getReloc(IntTy begin, IntTy size, const ArrayRef<RelTy> &rels, // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. template <class ELFT> void EhInputSection::split() { - if (areRelocsRela) - split<ELFT>(relas<ELFT>()); + const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>(); + if (rels.areRelocsRel()) + split<ELFT>(rels.rels); else - split<ELFT>(rels<ELFT>()); + split<ELFT>(rels.relas); } template <class ELFT, class RelTy> @@ -1475,6 +1464,11 @@ template void InputSection::writeTo<ELF32BE>(uint8_t *); template void InputSection::writeTo<ELF64LE>(uint8_t *); template void InputSection::writeTo<ELF64BE>(uint8_t *); +template RelsOrRelas<ELF32LE> InputSectionBase::relsOrRelas<ELF32LE>() const; +template RelsOrRelas<ELF32BE> InputSectionBase::relsOrRelas<ELF32BE>() const; +template RelsOrRelas<ELF64LE> InputSectionBase::relsOrRelas<ELF64LE>() const; +template RelsOrRelas<ELF64BE> InputSectionBase::relsOrRelas<ELF64BE>() const; + template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &, StringRef); template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &, |