diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 61da4a73a6fdbf424992c0412c4c6602fa243096..57736777e6ad07ce8e6a3df6de82b364aafa47a2 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 d4c2f9aa9489a527e8d4185b7638339f37a70128..60268a473657d8ecd2e33b794b9758e5b03d3fd0 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 f2fc99fe350c0b752357d2cc1883acafe2638a5a..dc4563d0764ba4ad418b51d4292fb567ed3e3c53 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 3b144648cf8f8cf1502af3f7b52c97686f4f14eb..fdc41e7503e6570d3da21e2e738bd80f1f5340b6 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 53af34ef208552d5d63c0ff062a6b47ff8c59409..277c57505bb2f920b51068b7def01c75081ad01c 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 b359c2e7bcea350f97db1d8ad123a31eec2a58c2..f298b83bda0e4f00b253c28a201d7a1b69a759a0 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; @@ -585,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, @@ -611,7 +651,12 @@ 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(). + 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 +670,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 987c0461ec071a54bb1574646ef85ba0b1eeb527..83a2bd7d34dfd0efd99cb12b442793d340dcfec8 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 14b1f53c6a819bce29f8470795626f42deb19289..5ec2d85f64e83b6e7f25bfa4c6f702657e91a979 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 04828e7b28b405a0e6110fa7b1eecbca84633fb7..426cc631c01053415edabe3f144ab832defd3fc7 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 ccf433c6a67556f758cc91002e3f944ce3090291..9836531ea3a3165f2dce7f0137e4cacba3f4612f 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 87ce8ede725039417c73fbef4e9536b23c6d3b00..a06380bd6719f79281de86c6c70999af44222c61 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 7cc27fc4222947e31b69c03376357a460c8ef211..fa31d21c16136c15bbbb77da4cf404d54296e58f 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 a567bd40d73efa2820b9985398009ccf31a2975f..d7f07e29a285f980fec41be7dbc4551d5c092b32 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 798e6c0af9340f703f6bf2ace33d3a286e71e741..4a70b895851f9e928e0b8991378f38a4b0ad0dc6 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 68b79c725d0c60ecfdf3388078d6fe7bc1987f8c..90f6a568fe38ee0ace387100b3b01e1901061278 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 6955d51e7aef6bddea13db9113f0f415ffdda780..c90c5b4c692c049cf890f9d994745ad8808e58d6 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 856fddb19c02566baac5c2fd646f50e894e3fd77..e6ff8021ff5a4159e2c4a2ac2e1e417b794953f3 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 436b34bb3a8028279fbf9cc00dc88ca8c736c293..109474c36df30a6cb9014c865a4f8737201949c2 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 e878189715fe250a27dbd19843ee7a19ad284aca..a3a12c9b01dd2e35ec9cd65253b11dbc1123f3af 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 2d4141143b12300d52f0d9594bf57646934b89ef..0a4bb2e515c2fab64ac0d136d764d65c7a458b55 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 f4fab9360428fc1ab48b6e11ba7d27bcc94d794e..0000000000000000000000000000000000000000 --- 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 49749201af99ae2cc21c7a3aa8a2ed9b45bf1c40..c907527201b9de3b44c173287041d81822297292 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 f4f5905d4bccd61cd6727c77ba95c62ae8590af7..a37eb5855f39dc194c44d18bfd293c4f9dc4698d 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 b18b64382b4122e24b21ef06cfd89db44f4d2c20..d8ad544cf1b11a0181b37c0825e3a328b1502356 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 8cf312191153962ca6491a7ebd2e2e8b3b01969f..4acbd4d1ac827b7eba510a01a9dddd19992bc7a4 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))