From a8fcdc748257a28def1cdac3e099d0284196275c Mon Sep 17 00:00:00 2001 From: Oleg Kupstov Date: Fri, 14 Apr 2023 09:28:20 +0300 Subject: [PATCH 1/2] [lld] Do not emit dynamic relocations for .eh_frame section Some targets (e.g. all mips-, mipsel-, mips64-, mips64el-, i386-linux-*) tend to use absolute-encoded pointers (for personality routine, FDE and LSDA) in the .eh_frame section. It results in absolute relocations in this section. In case of PIE, these relocations can be only resolved at dynamic link time since the base program address is not known until its execution. Such behavior is not desired as the .eh_frame section it usually located in a read-only text segment, which should not contain dynamic relocations. This patch introduces functionality which allows us to mimic the bfd linker behavior. It re-writes encodings for pointers inside .eh_frame so they become DW_EH_PE_pcrel instead of DW_EH_PE_absptr. After such re-write, dynamic relocations are not needed anymore. Signed-off-by: Oleg Kupstov --- lld/ELF/Arch/Mips.cpp | 21 ++ lld/ELF/Arch/X86.cpp | 16 + lld/ELF/EhFrame.cpp | 292 +++++++++--------- lld/ELF/EhFrame.h | 22 +- lld/ELF/Relocations.cpp | 25 ++ lld/ELF/SyntheticSections.cpp | 61 +++- lld/ELF/SyntheticSections.h | 14 +- lld/ELF/Target.h | 5 + lld/test/ELF/eh-frame-dyn-rel.s | 4 +- lld/test/ELF/invalid-eh-frame.s | 4 +- lld/test/ELF/invalid-eh-frame2.s | 4 +- lld/test/ELF/invalid-eh-frame3.s | 4 +- lld/test/ELF/invalid-eh-frame4.s | 4 +- lld/test/ELF/invalid-eh-frame5.s | 4 +- lld/test/ELF/invalid-eh-frame6.s | 8 +- lld/test/ELF/invalid-eh-frame7.s | 4 +- lld/test/ELF/invalid-eh-frame8.s | 4 +- lld/test/ELF/invalid-eh-frame9.s | 4 +- lld/test/ELF/invalid/eh-frame-hdr-no-out.s | 4 +- lld/test/ELF/mips-eh_frame-pic.s | 48 +-- lld/test/ELF/mips64-eh-abs-reloc.s | 38 --- .../llvm/DebugInfo/DWARF/DWARFDataExtractor.h | 13 + llvm/include/llvm/Support/DataExtractor.h | 22 +- .../DebugInfo/DWARF/DWARFDataExtractor.cpp | 67 ++-- llvm/lib/Support/DataExtractor.cpp | 16 +- 25 files changed, 460 insertions(+), 248 deletions(-) delete mode 100644 lld/test/ELF/mips64-eh-abs-reloc.s diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 61da4a73a6fd..57736777e6ad 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -29,6 +29,9 @@ public: const uint8_t *loc) const override; int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; RelType getDynRel(RelType type) const override; + // OHOS_LOCAL begin + bool convertAbsRelToPC(RelType &type) const override; + // OHOS_LOCAL end void writeGotPlt(uint8_t *buf, const Symbol &s) const override; void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, @@ -203,6 +206,24 @@ template RelType MIPS::getDynRel(RelType type) const { return R_MIPS_NONE; } +// OHOS_LOCAL begin + +template bool MIPS::convertAbsRelToPC(RelType &type) const { + switch (type) { + case R_MIPS_32: + type = R_MIPS_PC32; + return true; + // MIPS N64 ABI packs multiple relocations into the single relocation + // record. See comment in calculateMipsRelChain. + case R_MIPS_64: + type = (R_MIPS_NONE << 16) | (R_MIPS_64 << 8) | (R_MIPS_PC32 << 0); + return true; + } + return false; +} + +// OHOS_LOCAL end + template void MIPS::writeGotPlt(uint8_t *buf, const Symbol &) const { uint64_t va = in.plt->getVA(); diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index d4c2f9aa9489..60268a473657 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -28,6 +28,9 @@ public: int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; void writeGotPltHeader(uint8_t *buf) const override; RelType getDynRel(RelType type) const override; + // OHOS_LOCAL begin + bool convertAbsRelToPC(RelType &type) const override; + // OHOS_LOCAL end void writeGotPlt(uint8_t *buf, const Symbol &s) const override; void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; void writePltHeader(uint8_t *buf) const override; @@ -195,6 +198,19 @@ RelType X86::getDynRel(RelType type) const { return type; } +// OHOS_LOCAL begin + +bool X86::convertAbsRelToPC(RelType &type) const { + switch (type) { + case R_386_32: + type = R_386_PC32; + return true; + } + return false; +} + +// OHOS_LOCAL end + void X86::writePltHeader(uint8_t *buf) const { if (config->isPic) { const uint8_t v[] = { diff --git a/lld/ELF/EhFrame.cpp b/lld/ELF/EhFrame.cpp index f2fc99fe350c..dc4563d0764b 100644 --- a/lld/ELF/EhFrame.cpp +++ b/lld/ELF/EhFrame.cpp @@ -15,181 +15,191 @@ // //===----------------------------------------------------------------------===// +// OHOS_LOCAL begin + #include "EhFrame.h" #include "Config.h" #include "InputSection.h" -#include "Relocations.h" -#include "Target.h" #include "lld/Common/ErrorHandler.h" -#include "lld/Common/Strings.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/Object/ELF.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" using namespace llvm; -using namespace llvm::ELF; -using namespace llvm::dwarf; -using namespace llvm::object; -using namespace lld; -using namespace lld::elf; +namespace lld { +namespace elf { namespace { -class EhReader { + +// The reason for having a class for parsing a EH CIE frame instead of a single +// function is need for hasLSDA() used by ICF::handleLSDA(). We'd better +// parse each CIE only once but at this point the EhFrameSection::cieRecords +// vector is not filled yet (it's done in EhFrameSection::finalizeContents() +// later). So, to avoid parsing unneeded CIE parts, we split parsing into 2 +// phases, and use a class just to save internal parsing state between them. +class EhCieReader { public: - EhReader(InputSectionBase *s, ArrayRef d) : isec(s), d(d) {} - uint8_t getFdeEncoding(); + EhCieReader(const EhSectionPiece &cie); + bool hasLSDA(); + EhPointerEncodings getEhPointerEncodings(); private: - template void failOn(const P *loc, const Twine &msg) { - fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " + - isec->getObjMsg((const uint8_t *)loc - isec->rawData.data())); - } + void failOnCursorPos(const Twine &msg); - uint8_t readByte(); - void skipBytes(size_t count); - StringRef readString(); - void skipLeb128(); - void skipAugP(); - StringRef getAugmentation(); + void parseUntilAugmentationString(); + void parseAll(); - InputSectionBase *isec; - ArrayRef d; -}; -} + const EhSectionPiece &cie; + DWARFDataExtractor dataExtractor; + DWARFDataExtractor::Cursor cursor = DWARFDataExtractor::Cursor(0); -// Read a byte and advance D by one byte. -uint8_t EhReader::readByte() { - if (d.empty()) - failOn(d.data(), "unexpected end of CIE"); - uint8_t b = d.front(); - d = d.slice(1); - return b; -} + uint8_t version; + StringRef augmentationString; -void EhReader::skipBytes(size_t count) { - if (d.size() < count) - failOn(d.data(), "CIE is too small"); - d = d.slice(count); -} + EhPointerEncodings encodings; +}; -// Read a null-terminated string. -StringRef EhReader::readString() { - const uint8_t *end = llvm::find(d, '\0'); - if (end == d.end()) - failOn(d.data(), "corrupted CIE (failed to read string)"); - StringRef s = toStringRef(d.slice(0, end - d.begin())); - d = d.slice(s.size() + 1); - return s; -} +EhCieReader::EhCieReader(const EhSectionPiece &cie) + : cie(cie), dataExtractor( + /* Data = */ cie.data(), + /* IsLittleEndian = */ config->isLE, + /* AddressSize = */ config->wordsize) {} -// Skip an integer encoded in the LEB128 format. -// Actual number is not of interest because only the runtime needs it. -// But we need to be at least able to skip it so that we can read -// the field that follows a LEB128 number. -void EhReader::skipLeb128() { - const uint8_t *errPos = d.data(); - while (!d.empty()) { - uint8_t val = d.front(); - d = d.slice(1); - if ((val & 0x80) == 0) - return; - } - failOn(errPos, "corrupted CIE (failed to read LEB128)"); +bool EhCieReader::hasLSDA() { + parseUntilAugmentationString(); + return augmentationString.contains('L'); } -static size_t getAugPSize(unsigned enc) { - switch (enc & 0x0f) { - case DW_EH_PE_absptr: - case DW_EH_PE_signed: - return config->wordsize; - case DW_EH_PE_udata2: - case DW_EH_PE_sdata2: - return 2; - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - return 4; - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - return 8; - } - return 0; +EhPointerEncodings EhCieReader::getEhPointerEncodings() { + parseAll(); + return encodings; } -void EhReader::skipAugP() { - uint8_t enc = readByte(); - if ((enc & 0xf0) == DW_EH_PE_aligned) - failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported"); - size_t size = getAugPSize(enc); - if (size == 0) - failOn(d.data() - 1, "unknown FDE encoding"); - if (size >= d.size()) - failOn(d.data() - 1, "corrupted CIE"); - d = d.slice(size); +void EhCieReader::failOnCursorPos(const Twine &msg) { + fatal("malformed CIE in .eh_frame: " + msg + "\n>>> defined in " + + cie.sec->getObjMsg(cie.data().data() + cursor.tell() - + cie.sec->data().data())); } -uint8_t elf::getFdeEncoding(EhSectionPiece *p) { - return EhReader(p->sec, p->data()).getFdeEncoding(); -} +void EhCieReader::parseUntilAugmentationString() { + // Parsing is intended to be run only once. + assert(cursor.tell() == 0); -bool elf::hasLSDA(const EhSectionPiece &p) { - return EhReader(p.sec, p.data()).hasLSDA(); -} + /* length = */ dataExtractor.getU32(cursor); + uint32_t id = dataExtractor.getU32(cursor); + if (!cursor) + failOnCursorPos("corrupted length or id"); + + if (id != 0) + failOnCursorPos("id must be 0, got " + Twine(id)); -StringRef EhReader::getAugmentation() { - skipBytes(8); - int version = readByte(); + version = dataExtractor.getU8(cursor); + if (!cursor) + failOnCursorPos("corrupted version"); if (version != 1 && version != 3) - failOn(d.data() - 1, - "FDE version 1 or 3 expected, but got " + Twine(version)); + failOnCursorPos("version must be 1 or 3, got " + + Twine(static_cast(version))); + + augmentationString = dataExtractor.getCStrRef(cursor); + if (!cursor) + failOnCursorPos("corrupted augmentation string"); +} - StringRef aug = readString(); +void EhCieReader::parseAll() { + parseUntilAugmentationString(); - // Skip code and data alignment factors. - skipLeb128(); - skipLeb128(); + dataExtractor.getULEB128(cursor); + dataExtractor.getSLEB128(cursor); + if (!cursor) + failOnCursorPos("corrupted code or data align factor"); - // Skip the return address register. In CIE version 1 this is a single - // byte. In CIE version 3 this is an unsigned LEB128. + // Skip ret address reg if (version == 1) - readByte(); + dataExtractor.getU8(cursor); else - skipLeb128(); - return aug; -} + dataExtractor.getULEB128(cursor); + if (!cursor) + failOnCursorPos("corrupted ret address reg"); + + if (augmentationString.empty()) + return; + + uint64_t augmentationSectionBegin = 0; + uint64_t augmentationSectionExpectedSize; + if (augmentationString.front() == 'z') { + augmentationSectionExpectedSize = dataExtractor.getULEB128(cursor); + if (!cursor) + failOnCursorPos("corrupted augmentation section size"); + augmentationSectionBegin = cursor.tell(); + augmentationString = augmentationString.slice(1, StringRef::npos); + } -uint8_t EhReader::getFdeEncoding() { - // We only care about an 'R' value, but other records may precede an 'R' - // record. Unfortunately records are not in TLV (type-length-value) format, - // so we need to teach the linker how to skip records for each type. - StringRef aug = getAugmentation(); - for (char c : aug) { - if (c == 'R') - return readByte(); - if (c == 'z') - skipLeb128(); - else if (c == 'L') - readByte(); - else if (c == 'P') - skipAugP(); - else if (c != 'B' && c != 'S' && c != 'G') - failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug); + auto helper = [this](EhPointerEncoding &encoding, char c) { + if (encoding.offsetInCie != size_t(-1)) + failOnCursorPos("duplicate occurrance of " + Twine(c) + + " in augmentation string \"" + augmentationString + "\""); + encoding.offsetInCie = cursor.tell(); + encoding.encoding = dataExtractor.getU8(cursor); + }; + + for (char c : augmentationString) { + switch (c) { + case 'R': + helper(encodings.fdeEncoding, c); + break; + case 'L': + helper(encodings.lsdaEncoding, c); + break; + case 'P': + helper(encodings.personalityEncoding, c); + if (dataExtractor.getRawEncodedPointer( + cursor, encodings.personalityEncoding.encoding) == None) + failOnCursorPos( + "cannot get personality pointer for personality encoding " + + Twine(static_cast(encodings.personalityEncoding.encoding))); + if ((encodings.personalityEncoding.encoding & 0xf0) == + dwarf::DW_EH_PE_aligned) + failOnCursorPos( + "DW_EH_PE_aligned personality encoding is not supported"); + break; + case 'B': + // B-Key is used for signing functions associated with this + // augmentation string + case 'S': + // Current frame is a signal trampoline. + case 'G': + // This stack frame contains MTE tagged data, so needs to be + // untagged on unwind. + break; + default: + failOnCursorPos("unexpected character in CIE augmentation string: " + + augmentationString); + } + if (!cursor) + failOnCursorPos("corrupted CIE augmentation section"); } - return DW_EH_PE_absptr; + + uint64_t augmentationSectionActualSize = + cursor.tell() - augmentationSectionBegin; + + if (augmentationSectionBegin != 0 && + augmentationSectionActualSize != augmentationSectionExpectedSize) + failOnCursorPos("augmentation section size " + + Twine(augmentationSectionExpectedSize) + + "does not match the actual size " + + Twine(augmentationSectionActualSize)); } -bool EhReader::hasLSDA() { - StringRef aug = getAugmentation(); - for (char c : aug) { - if (c == 'L') - return true; - if (c == 'z') - skipLeb128(); - else if (c == 'P') - skipAugP(); - else if (c == 'R') - readByte(); - else if (c != 'B' && c != 'S' && c != 'G') - failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug); - } - return false; +} // namespace + +EhPointerEncodings getEhPointerEncodings(const EhSectionPiece &cie) { + return EhCieReader(cie).getEhPointerEncodings(); } + +bool hasLSDA(const EhSectionPiece &cie) { return EhCieReader(cie).hasLSDA(); } + +} // namespace elf +} // namespace lld + +// OHOS_LOCAL end diff --git a/lld/ELF/EhFrame.h b/lld/ELF/EhFrame.h index 3b144648cf8f..fdc41e7503e6 100644 --- a/lld/ELF/EhFrame.h +++ b/lld/ELF/EhFrame.h @@ -9,16 +9,32 @@ #ifndef LLD_ELF_EHFRAME_H #define LLD_ELF_EHFRAME_H +// OHOS_LOCAL begin + #include "lld/Common/LLVM.h" namespace lld { namespace elf { -class InputSectionBase; + struct EhSectionPiece; -uint8_t getFdeEncoding(EhSectionPiece *p); -bool hasLSDA(const EhSectionPiece &p); +struct EhPointerEncoding { + uint8_t encoding; + size_t offsetInCie = -1; +}; + +struct EhPointerEncodings { + EhPointerEncoding personalityEncoding; + EhPointerEncoding fdeEncoding; + EhPointerEncoding lsdaEncoding; +}; + +EhPointerEncodings getEhPointerEncodings(const EhSectionPiece &cie); +bool hasLSDA(const EhSectionPiece &cie); + } // namespace elf } // namespace lld +// OHOS_LOCAL end + #endif diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 53af34ef2085..277c57505bb2 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1440,6 +1440,31 @@ template void RelocationScanner::scanOne(RelTy *&i) { sym.hasDirectReloc = true; } + // OHOS_LOCAL begin + + // We convert R_ABS relocations in the .eh_frame section to R_PC to avoid + // creating dynamic relocations in the resulting .eh_frame section since it + // usually belongs to a non-writeable text segment. A dynamic relocation might + // be needed because the base address might not be known until the program + // start. We also change encoding of the pointers matching the converted + // relocations in the .eh_frame section from DW_EH_PE_absptr to + // DW_EH_PE_pcrel. For some architectures (e.g. Mips) compilers produce object + // files containing such absolute-encoded pointers in .eh_frame so the + // conversion is needed on the linker side. The bfd linker from GNU binutils + // does that, so we mimic this behavior as well. + if (config->isPic && isa(sec) && expr == R_ABS) { + expr = R_PC; + if (!target.convertAbsRelToPC(type)) { + fatal("relocation " + toString(type) + " cannot be used against " + + (sym.getName().empty() ? "local symbol " + : "symbol '" + toString(sym) + "' ") + + "in .eh_frame section; recompile with -fPIC" + + getLocation(sec, sym, offset)); + } + } + + // OHOS_LOCAL end + processAux(expr, type, offset, sym, addend); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index b359c2e7bcea..dae85afe3418 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -506,6 +506,27 @@ static void writeCieFde(uint8_t *buf, ArrayRef d) { write32(buf, aligned - 4); } +// OHOS_LOCAL begin + +// Change encoding of DW_EH_PE_absptr pointers in .eh_frame CIE records to +// DW_EH_PE_pcrel. See details in RelocationScanner::scanOne(). +static void convertCieAbsEncodingsToPcrel(CieRecord *rec) { + rec->encodings = getEhPointerEncodings(*rec->cie); + if (!config->isPic) + return; + + auto helper = [](EhPointerEncoding &encoding) { + if (encoding.offsetInCie != size_t(-1) && + (encoding.encoding & 0x70) == DW_EH_PE_absptr) + encoding.encoding |= DW_EH_PE_pcrel; + }; + helper(rec->encodings.personalityEncoding); + helper(rec->encodings.fdeEncoding); + helper(rec->encodings.lsdaEncoding); +} + +// OHOS_LOCAL end + void EhFrameSection::finalizeContents() { assert(!this->size); // Not finalized. @@ -535,6 +556,8 @@ void EhFrameSection::finalizeContents() { rec->cie->outputOff = off; off += alignToPowerOf2(rec->cie->size, config->wordsize); + convertCieAbsEncodingsToPcrel(rec); // OHOS_LOCAL + for (EhSectionPiece *fde : rec->fdes) { fde->outputOff = off; off += alignToPowerOf2(fde->size, config->wordsize); @@ -550,6 +573,25 @@ void EhFrameSection::finalizeContents() { this->size = off; } +// OHOS_LOCAL begin + +static uint8_t getFdeEncoding(const CieRecord &cie) { + if (cie.encodings.fdeEncoding.offsetInCie != size_t(-1)) + return cie.encodings.fdeEncoding.encoding; + if (config->emachine == EM_386 || config->emachine == EM_X86_64) { + // From System V Application Binary Interface for both i386 and AMD64: + // If 'R' is missing from the CIE Augmentation String, the field is an + // 8-byte absolute pointer. + return DW_EH_PE_udata8 | DW_EH_PE_absptr; + } + // TODO: reveal the default encoding for other architectures. Using just + // absptr with platform-native pointer size seemed to work fine for a while + // though. + return DW_EH_PE_absptr; +} + +// OHOS_LOCAL end + // Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get an FDE from an address to which FDE is applied. This function // returns a list of such pairs. @@ -559,7 +601,7 @@ SmallVector EhFrameSection::getFdeData() const { uint64_t va = getPartition().ehFrameHdr->getVA(); for (CieRecord *rec : cieRecords) { - uint8_t enc = getFdeEncoding(rec->cie); + uint8_t enc = getFdeEncoding(*rec); // // OHOS_LOCAL for (EhSectionPiece *fde : rec->fdes) { uint64_t pc = getFdePc(buf, fde->outputOff, enc); uint64_t fdeVA = getParent()->addr + fde->outputOff; @@ -612,6 +654,11 @@ uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, // stored at FDE + 8 byte. size_t off = fdeOff + 8; uint64_t addr = readFdeAddr(buf + off, enc & 0xf); + // OHOS_LOCAL begin + // We've converted DW_EH_PE_absptr to DW_EH_PE_pcrel earlier in + // convertCieAbsEncodingsToPcrel(). + assert(!config->isPic || (enc & 0x70) != DW_EH_PE_absptr); + // OHOS_LOCAL end if ((enc & 0x70) == DW_EH_PE_absptr) return addr; if ((enc & 0x70) == DW_EH_PE_pcrel) @@ -625,6 +672,18 @@ void EhFrameSection::writeTo(uint8_t *buf) { size_t cieOffset = rec->cie->outputOff; writeCieFde(buf + cieOffset, rec->cie->data()); + // OHOS_LOCAL begin + if (config->isPic) { + auto helper = [buf, cieOffset](EhPointerEncoding encoding) { + if (encoding.offsetInCie != size_t(-1)) + *(buf + cieOffset + encoding.offsetInCie) = encoding.encoding; + }; + helper(rec->encodings.personalityEncoding); + helper(rec->encodings.fdeEncoding); + helper(rec->encodings.lsdaEncoding); + } + // OHOS_LOCAL end + for (EhSectionPiece *fde : rec->fdes) { size_t off = fde->outputOff; writeCieFde(buf + off, fde->data()); diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 987c0461ec07..83a2bd7d34df 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -21,6 +21,7 @@ #define LLD_ELF_SYNTHETIC_SECTIONS_H #include "Config.h" +#include "EhFrame.h" // OHOS_LOCAL #include "InputSection.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" @@ -57,6 +58,7 @@ public: struct CieRecord { EhSectionPiece *cie = nullptr; + EhPointerEncodings encodings; // OHOS_LOCAL SmallVector fdes; }; @@ -514,7 +516,17 @@ public: /// Add a dynamic relocation without writing an addend to the output section. /// This overload can be used if the addends are written directly instead of /// using relocations on the input section (e.g. MipsGotSection::writeTo()). - void addReloc(const DynamicReloc &reloc) { relocs.push_back(reloc); } + void addReloc(const DynamicReloc &reloc) { + // OHOS_LOCAL begin + // We have already converted R_ABS relocations in the .eh_frame section to + // R_PC so they can be resolved statically. (see + // RelocationScanner::scanOne() for details). We are not supposed to create + // dynamic relocations in the .eh_frame section since it usually belongs to + // a read-only text segment. + assert(!isa(reloc.inputSec)); + // OHOS_LOCAL end + relocs.push_back(reloc); + } /// Add a dynamic relocation against \p sym with an optional addend. void addSymbolReloc(RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym, int64_t addend = 0, diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 14b1f53c6a81..5ec2d85f64e8 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -30,6 +30,11 @@ public: virtual RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const = 0; virtual RelType getDynRel(RelType type) const { return 0; } + // OHOS_LOCAL begin + // Returns true if a conversion was performed. See + // RelocationScanner::scanOne() for comments on motivation and details. + virtual bool convertAbsRelToPC(RelType &type) const { return false; } + // OHOS_LOCAL end virtual void writeGotPltHeader(uint8_t *buf) const {} virtual void writeGotHeader(uint8_t *buf) const {} virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {}; diff --git a/lld/test/ELF/eh-frame-dyn-rel.s b/lld/test/ELF/eh-frame-dyn-rel.s index 04828e7b28b4..426cc631c010 100644 --- a/lld/test/ELF/eh-frame-dyn-rel.s +++ b/lld/test/ELF/eh-frame-dyn-rel.s @@ -2,7 +2,9 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: not ld.lld %t.o %t.o -o /dev/null -shared 2>&1 | FileCheck %s -// CHECK: error: relocation R_X86_64_64 cannot be used against symbol 'foo'; recompile with -fPIC +// OHOS_LOCAL begin +// CHECK: error: relocation R_X86_64_64 cannot be used against symbol 'foo' in .eh_frame section; recompile with -fPIC +// OHOS_LOCAL end // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.eh_frame+0x12) diff --git a/lld/test/ELF/invalid-eh-frame.s b/lld/test/ELF/invalid-eh-frame.s index ccf433c6a675..9836531ea3a3 100644 --- a/lld/test/ELF/invalid-eh-frame.s +++ b/lld/test/ELF/invalid-eh-frame.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: unexpected end of CIE +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: corrupted version +# OHOS_LOCAL end # CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x8) .section .eh_frame,"a",@unwind diff --git a/lld/test/ELF/invalid-eh-frame2.s b/lld/test/ELF/invalid-eh-frame2.s index 87ce8ede7250..a06380bd6719 100644 --- a/lld/test/ELF/invalid-eh-frame2.s +++ b/lld/test/ELF/invalid-eh-frame2.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read string) +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: corrupted augmentation string +# OHOS_LOCAL end # CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x9) .section .eh_frame,"a",@unwind diff --git a/lld/test/ELF/invalid-eh-frame3.s b/lld/test/ELF/invalid-eh-frame3.s index 7cc27fc42229..fa31d21c1613 100644 --- a/lld/test/ELF/invalid-eh-frame3.s +++ b/lld/test/ELF/invalid-eh-frame3.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read LEB128) +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: corrupted code or data align factor +# OHOS_LOCAL end # CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xC) .section .eh_frame,"a",@unwind diff --git a/lld/test/ELF/invalid-eh-frame4.s b/lld/test/ELF/invalid-eh-frame4.s index a567bd40d73e..d7f07e29a285 100644 --- a/lld/test/ELF/invalid-eh-frame4.s +++ b/lld/test/ELF/invalid-eh-frame4.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string: +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: unexpected character in CIE augmentation string: +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x0E diff --git a/lld/test/ELF/invalid-eh-frame5.s b/lld/test/ELF/invalid-eh-frame5.s index 798e6c0af934..4a70b895851f 100644 --- a/lld/test/ELF/invalid-eh-frame5.s +++ b/lld/test/ELF/invalid-eh-frame5.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string: +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: unexpected character in CIE augmentation string: +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x0E diff --git a/lld/test/ELF/invalid-eh-frame6.s b/lld/test/ELF/invalid-eh-frame6.s index 68b79c725d0c..90f6a568fe38 100644 --- a/lld/test/ELF/invalid-eh-frame6.s +++ b/lld/test/ELF/invalid-eh-frame6.s @@ -3,8 +3,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: unknown FDE encoding -# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xE) +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: cannot get personality pointer for personality encoding 5 +# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xF) +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x0E @@ -25,7 +27,7 @@ .byte 0x01 # LEB128 .byte 0x01 # LEB128 - .byte 0x01 + .byte 0x05 # OHOS_LOCAL (now we support 0x01 encoding, so use 0x05 as invalid one for test) .byte 0x01 .byte 0x01 .byte 0x01 diff --git a/lld/test/ELF/invalid-eh-frame7.s b/lld/test/ELF/invalid-eh-frame7.s index 6955d51e7aef..c90c5b4c692c 100644 --- a/lld/test/ELF/invalid-eh-frame7.s +++ b/lld/test/ELF/invalid-eh-frame7.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: DW_EH_PE_aligned encoding is not supported +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: DW_EH_PE_aligned personality encoding is not supported +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x0E diff --git a/lld/test/ELF/invalid-eh-frame8.s b/lld/test/ELF/invalid-eh-frame8.s index 856fddb19c02..e6ff8021ff5a 100644 --- a/lld/test/ELF/invalid-eh-frame8.s +++ b/lld/test/ELF/invalid-eh-frame8.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: corrupted CIE +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: corrupted CIE augmentation section +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x0E diff --git a/lld/test/ELF/invalid-eh-frame9.s b/lld/test/ELF/invalid-eh-frame9.s index 436b34bb3a80..109474c36df3 100644 --- a/lld/test/ELF/invalid-eh-frame9.s +++ b/lld/test/ELF/invalid-eh-frame9.s @@ -3,7 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: corrupted .eh_frame: CIE is too small +# OHOS_LOCAL begin +# CHECK: error: malformed CIE in .eh_frame: corrupted length or id +# OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x03 diff --git a/lld/test/ELF/invalid/eh-frame-hdr-no-out.s b/lld/test/ELF/invalid/eh-frame-hdr-no-out.s index e878189715fe..a3a12c9b01dd 100644 --- a/lld/test/ELF/invalid/eh-frame-hdr-no-out.s +++ b/lld/test/ELF/invalid/eh-frame-hdr-no-out.s @@ -2,7 +2,9 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -// CHECK: error: corrupted .eh_frame: FDE version 1 or 3 expected, but got 2 +// OHOS_LOCAL begin +// CHECK: error: malformed CIE in .eh_frame: version must be 1 or 3, got 2 +// OHOS_LOCAL end .section .eh_frame,"a",@unwind .byte 0x08 diff --git a/lld/test/ELF/mips-eh_frame-pic.s b/lld/test/ELF/mips-eh_frame-pic.s index 2d4141143b12..0a4bb2e515c2 100644 --- a/lld/test/ELF/mips-eh_frame-pic.s +++ b/lld/test/ELF/mips-eh_frame-pic.s @@ -3,51 +3,61 @@ ## -z notext. This was not possible LLVM started emitting values using the ## DW_EH_PE_pcrel | DW_EH_PE_sdata4 encoding. -## It should not be possible to link code compiled without -fPIC: +## OHOS_LOCAL begin + +## MIPS64 + +## Without -fPIC, the object files produced by the compiler will have +## DW_EH_PE_absptr encoded pointers in .eh_frame section. The linker must +## convert them to DW_EH_PE_pcrel when linking a .so library since an absolute +## pointer would require emitting a dynamic relocation which is not desireable +## for a read-only .eh_frame section. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-nopic.o # RUN: llvm-dwarfdump --eh-frame %t-nopic.o | FileCheck %s --check-prefix=ABS64-EH-FRAME # RUN: llvm-readobj -r %t-nopic.o | FileCheck %s --check-prefixes=RELOCS,ABS64-RELOCS -# RUN: not ld.lld -shared %t-nopic.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC-ERR -## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use -## relative addressing. -# NOPIC-ERR: ld.lld: error: relocation R_MIPS_64 cannot be used against local symbol +# RUN: ld.lld -shared %t-nopic.o -o %t-nopic.so +# RUN: llvm-dwarfdump --eh-frame %t-nopic.so | FileCheck %s --check-prefix=PCREL64-EH-FRAME ## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values: # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux --position-independent %s -o %t-pic.o # RUN: llvm-readobj -r %t-pic.o | FileCheck %s --check-prefixes=RELOCS,PIC64-RELOCS # RUN: ld.lld -shared %t-pic.o -o %t-pic.so -# RUN: llvm-dwarfdump --eh-frame %t-pic.so | FileCheck %s --check-prefix=PIC-EH-FRAME +# RUN: llvm-dwarfdump --eh-frame %t-pic.so | FileCheck %s --check-prefix=PCREL32-EH-FRAME + +## MIPS32 -## Also check MIPS32: +## Without -fPIC (see detailed comments in MIPS64 section). +## Note: ld.bfd converts the R_MIPS_32 relocs to DW_EH_PE_pcrel | DW_EH_PE_sdata4 +## for MIPS32, we mimic this behavior. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-nopic32.o # RUN: llvm-dwarfdump --eh-frame %t-nopic32.o | FileCheck %s --check-prefix=ABS32-EH-FRAME # RUN: llvm-readobj -r %t-nopic32.o | FileCheck %s --check-prefixes=RELOCS,ABS32-RELOCS -# RUN: not ld.lld -shared %t-nopic32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC32-ERR -## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use -## relative addressing. -# NOPIC32-ERR: ld.lld: error: relocation R_MIPS_32 cannot be used against local symbol +# RUN: ld.lld -shared %t-nopic32.o -o %t-nopic32.so +# RUN: llvm-dwarfdump --eh-frame %t-nopic32.so | FileCheck %s --check-prefix=PCREL32-EH-FRAME ## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values: # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux --position-independent %s -o %t-pic32.o # RUN: llvm-readobj -r %t-pic32.o | FileCheck %s --check-prefixes=RELOCS,PIC32-RELOCS # RUN: ld.lld -shared %t-pic32.o -o %t-pic32.so -# RUN: llvm-dwarfdump --eh-frame %t-pic32.so | FileCheck %s --check-prefix=PIC-EH-FRAME +# RUN: llvm-dwarfdump --eh-frame %t-pic32.so | FileCheck %s --check-prefix=PCREL32-EH-FRAME # RELOCS: .rel{{a?}}.eh_frame { # ABS32-RELOCS-NEXT: 0x1C R_MIPS_32 .text # ABS64-RELOCS-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text -# PIC64-RELOCS-NEXT: 0x1C R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE - # PIC32-RELOCS-NEXT: 0x1C R_MIPS_PC32 - +# PIC64-RELOCS-NEXT: 0x1C R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE - # RELOCS-NEXT: } # ABS64-EH-FRAME: Augmentation data: 0C -## ^^ fde pointer encoding: DW_EH_PE_sdata8 +## ^^ fde pointer encoding: DW_EH_PE_absptr | DW_EH_PE_sdata8 # ABS32-EH-FRAME: Augmentation data: 0B -## ^^ fde pointer encoding: DW_EH_PE_sdata4 -# PIC-EH-FRAME: Augmentation data: 1B -## ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4 -## Note: ld.bfd converts the R_MIPS_64 relocs to DW_EH_PE_pcrel | DW_EH_PE_sdata8 -## for N64 ABI (and DW_EH_PE_pcrel | DW_EH_PE_sdata4 for MIPS32) +## ^^ fde pointer encoding: DW_EH_PE_absptr | DW_EH_PE_sdata4 +# PCREL64-EH-FRAME: Augmentation data: 1C +## ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata8 +# PCREL32-EH-FRAME: Augmentation data: 1B +## ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4 + +## OHOS_LOCAL end .ent func .global func diff --git a/lld/test/ELF/mips64-eh-abs-reloc.s b/lld/test/ELF/mips64-eh-abs-reloc.s deleted file mode 100644 index f4fab9360428..000000000000 --- a/lld/test/ELF/mips64-eh-abs-reloc.s +++ /dev/null @@ -1,38 +0,0 @@ -# REQUIRES: mips -# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD -# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o -# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ -# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o --no-check-dynamic-relocations -# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS - -# Linking this as a PIE executable would also previously crash -# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o -# -pie needs -z notext because of the R_MIPS_64 relocation -# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o --no-check-dynamic-relocations -# RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS - - -# OBJ: Section ({{.*}}) .rela.text { -# OBJ-NEXT: 0x0 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 foo 0x0 -# OBJ-NEXT: } -# OBJ-NEXT: Section ({{.*}}) .rela.eh_frame { -# OBJ-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0 -# OBJ-NEXT: } - -# PIC-RELOCS: Relocations [ -# PIC-RELOCS-NEXT: Section (7) .rel.dyn { -# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - -# PIC-RELOCS-NEXT: } -# PIC-RELOCS-NEXT:] - - -.globl foo - -bar: -.cfi_startproc -lui $11, %hi(%neg(%gp_rel(foo))) -.cfi_endproc - -.globl __start -__start: -b bar diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index 49749201af99..c907527201b9 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -77,6 +77,19 @@ public: &getError(C)); } + // OHOS_LOCAL begin + + /// Extracts a DWARF-encoded pointer in cursor \p C using \p Encoding without + /// a PC-relative adjustment. + Optional getRawEncodedPointer(Cursor &C, + uint8_t Encoding) const; + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding without a + /// PC-relative adjustment. + Optional getRawEncodedPointer(uint64_t *Offset, + uint8_t Encoding) const; + + // OHOS_LOCAL end + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. /// There is a DWARF encoding that uses a PC-relative adjustment. /// For these values, \p AbsPosOffset is used to fix them, which should diff --git a/llvm/include/llvm/Support/DataExtractor.h b/llvm/include/llvm/Support/DataExtractor.h index f4f5905d4bcc..a37eb5855f39 100644 --- a/llvm/include/llvm/Support/DataExtractor.h +++ b/llvm/include/llvm/Support/DataExtractor.h @@ -300,10 +300,30 @@ public: /// @param[in] size /// The size in bytes of the integer to extract. /// + // OHOS_LOCAL begin + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + // OHOS_LOCAL end /// @return /// The sign extended signed integer value that was extracted, /// or zero on failure. - int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const; + // OHOS_LOCAL begin + int64_t getSigned(uint64_t *offset_ptr, uint32_t size, + Error *Err = nullptr) const; + // OHOS_LOCAL end + + // OHOS_LOCAL begin + /// Extract a signed integer of the given size from the location given by + /// the cursor. In case of an extraction error, or if the cursor is already in + /// an error state, zero is returned. + int64_t getSigned(Cursor &C, uint32_t Size) const { + return getSigned(&C.Offset, Size, &C.Err); + } + // OHOS_LOCAL end //------------------------------------------------------------------ /// Extract an pointer from \a *offset_ptr. diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp index b18b64382b41..d8ad544cf1b1 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -68,61 +68,76 @@ uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, return R; } + +// OHOS_LOCAL begin + Optional -DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, - uint64_t PCRelOffset) const { +DWARFDataExtractor::getRawEncodedPointer(Cursor &C, uint8_t Encoding) const { if (Encoding == dwarf::DW_EH_PE_omit) return None; - uint64_t Result = 0; - uint64_t OldOffset = *Offset; - // First get value switch (Encoding & 0x0F) { case dwarf::DW_EH_PE_absptr: + case dwarf::DW_EH_PE_signed: switch (getAddressSize()) { case 2: case 4: case 8: - Result = getUnsigned(Offset, getAddressSize()); - break; + return dwarf::DW_EH_PE_absptr == (Encoding & 0x0F) + ? getUnsigned(C, getAddressSize()) + : getSigned(C, getAddressSize()); default: return None; } - break; case dwarf::DW_EH_PE_uleb128: - Result = getULEB128(Offset); - break; + return getULEB128(C); case dwarf::DW_EH_PE_sleb128: - Result = getSLEB128(Offset); - break; + return getSLEB128(C); case dwarf::DW_EH_PE_udata2: - Result = getUnsigned(Offset, 2); - break; + return getUnsigned(C, 2); case dwarf::DW_EH_PE_udata4: - Result = getUnsigned(Offset, 4); - break; + return getUnsigned(C, 4); case dwarf::DW_EH_PE_udata8: - Result = getUnsigned(Offset, 8); - break; + return getUnsigned(C, 8); case dwarf::DW_EH_PE_sdata2: - Result = getSigned(Offset, 2); - break; + return getSigned(C, 2); case dwarf::DW_EH_PE_sdata4: - Result = SignExtend64<32>(getRelocatedValue(4, Offset)); - break; + return SignExtend64<32>(getRelocatedValue(C, 4)); case dwarf::DW_EH_PE_sdata8: - Result = getRelocatedValue(8, Offset); - break; + return getRelocatedValue(C, 8); default: return None; } +} + +Optional +DWARFDataExtractor::getRawEncodedPointer(uint64_t *Offset, + uint8_t Encoding) const { + DWARFDataExtractor::Cursor C(*Offset); + Optional Ret = getRawEncodedPointer(C, Encoding); + if (!C) + return None; + *Offset = C.tell(); + return Ret; +} + +Optional +DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, + uint64_t PCRelOffset) const { + uint64_t OldOffset = *Offset; + + // First get value + Optional Result = getRawEncodedPointer(Offset, Encoding); + if (Result == None) + return None; + // Then add relative offset, if required switch (Encoding & 0x70) { case dwarf::DW_EH_PE_absptr: // do nothing break; case dwarf::DW_EH_PE_pcrel: - Result += PCRelOffset; + *Result += PCRelOffset; break; case dwarf::DW_EH_PE_datarel: case dwarf::DW_EH_PE_textrel: @@ -135,3 +150,5 @@ DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, return Result; } + +// OHOS_LOCAL end diff --git a/llvm/lib/Support/DataExtractor.cpp b/llvm/lib/Support/DataExtractor.cpp index 8cf312191153..4acbd4d1ac82 100644 --- a/llvm/lib/Support/DataExtractor.cpp +++ b/llvm/lib/Support/DataExtractor.cpp @@ -137,21 +137,25 @@ uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, llvm_unreachable("getUnsigned unhandled case!"); } -int64_t -DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const { +// OHOS_LOCAL begin + +int64_t DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size, + llvm::Error *Err) const { switch (byte_size) { case 1: - return (int8_t)getU8(offset_ptr); + return (int8_t)getU8(offset_ptr, Err); case 2: - return (int16_t)getU16(offset_ptr); + return (int16_t)getU16(offset_ptr, Err); case 4: - return (int32_t)getU32(offset_ptr); + return (int32_t)getU32(offset_ptr, Err); case 8: - return (int64_t)getU64(offset_ptr); + return (int64_t)getU64(offset_ptr, Err); } llvm_unreachable("getSigned unhandled case!"); } +// OHOS_LOCAL end + StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const { ErrorAsOutParameter ErrAsOut(Err); if (isError(Err)) -- Gitee From 0ffc1b3f30a2138b7ded48bee6597930ce16ada6 Mon Sep 17 00:00:00 2001 From: Oleg Kupstov Date: Fri, 14 Apr 2023 09:31:19 +0300 Subject: [PATCH 2/2] [lld] Refactor `readFdeAddr` to avoid code duplication Previously, extraction of a DW_EH_PE-encoded pointer (e.g. the FDE address) was implemented in several places with slight differences. This patch introduces usage of `llvm::DWARFDataExtractor` in `readFdeAddr` so the logic is not duplicated anymore. Signed-off-by: Oleg Kupstov --- lld/ELF/SyntheticSections.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index dae85afe3418..f298b83bda0e 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -627,25 +627,23 @@ SmallVector EhFrameSection::getFdeData() const { return ret; } -static uint64_t readFdeAddr(uint8_t *buf, int size) { - switch (size) { - case DW_EH_PE_udata2: - return read16(buf); - case DW_EH_PE_sdata2: - return (int16_t)read16(buf); - case DW_EH_PE_udata4: - return read32(buf); - case DW_EH_PE_sdata4: - return (int32_t)read32(buf); - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - return read64(buf); - case DW_EH_PE_absptr: - return readUint(buf); - } - fatal("unknown FDE size encoding"); +// OHOS_LOCAL begin + +static uint64_t readFdeAddr(uint8_t *buf, uint8_t enc) { + DWARFDataExtractor dataExtractor(/* Data = */ ArrayRef(buf, + size_t(-1)), + /* IsLittleEndian = */ config->isLE, + /* AddressSize = */ config->wordsize); + uint64_t offset = 0; + Optional fdeAddr = + dataExtractor.getRawEncodedPointer(&offset, enc); + if (fdeAddr == None) + fatal("unknown FDE size encoding"); + return *fdeAddr; } +// OHOS_LOCAL end + // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. // We need it to create .eh_frame_hdr section. uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, @@ -653,7 +651,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t off = fdeOff + 8; - uint64_t addr = readFdeAddr(buf + off, enc & 0xf); + uint64_t addr = readFdeAddr(buf + off, enc); // OHOS_LOCAL // OHOS_LOCAL begin // We've converted DW_EH_PE_absptr to DW_EH_PE_pcrel earlier in // convertCieAbsEncodingsToPcrel(). -- Gitee