From 72e7abe0f833cb77fa49a25c144bcfcacf3f6397 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 22 Mar 2019 02:43:11 +0000 Subject: [PATCH] [DWARF] Refactor RelocVisitor and fix computation of SHT_RELA-typed relocation entries Summary: getRelocatedValue may compute incorrect value for SHT_RELA-typed relocation entries. // DWARFDataExtractor.cpp uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off, ... // This formula is correct for REL, but may be incorrect for RELA if the value // stored in the location (getUnsigned(Off, Size)) is not zero. return getUnsigned(Off, Size) + Rel->Value; In this patch, we * refactor these visit* functions to include a new parameter `uint64_t A`. Since these visit* functions are no longer used as visitors, rename them to resolve*. + REL: A is used as the addend. A is the value stored in the location where the relocation applies: getUnsigned(Off, Size) + RELA: The addend encoded in RelocationRef is used, e.g. getELFAddend(R) * and add another set of supports* functions to check if a given relocation type is handled. DWARFObjInMemory uses them to fail early. Reviewers: echristo, dblaikie Reviewed By: echristo Subscribers: mgorny, aprantl, aheejin, fedor.sergeev, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57939 llvm-svn: 356729 --- include/llvm/DebugInfo/DWARF/DWARFRelocMap.h | 5 +- include/llvm/Object/RelocVisitor.h | 362 -------------- include/llvm/Object/RelocationResolver.h | 42 ++ lib/DebugInfo/DWARF/DWARFContext.cpp | 20 +- lib/DebugInfo/DWARF/DWARFDataExtractor.cpp | 11 +- lib/Object/CMakeLists.txt | 1 + lib/Object/RelocationResolver.cpp | 497 +++++++++++++++++++ test/Object/invalid.test | 2 +- 8 files changed, 564 insertions(+), 376 deletions(-) delete mode 100644 include/llvm/Object/RelocVisitor.h create mode 100644 include/llvm/Object/RelocationResolver.h create mode 100644 lib/Object/RelocationResolver.cpp diff --git a/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h b/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h index a8f5b2840c6..cd022e7882c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h +++ b/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h @@ -10,6 +10,7 @@ #define LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H #include "llvm/ADT/DenseMap.h" +#include "llvm/Object/RelocationResolver.h" #include namespace llvm { @@ -18,7 +19,9 @@ namespace llvm { /// Section index is -1LL if relocation points to absolute symbol. struct RelocAddrEntry { uint64_t SectionIndex; - uint64_t Value; + object::RelocationRef Reloc; + object::RelocationResolver Resolver; + uint64_t SymbolValue; }; /// In place of applying the relocations to the data we've read from disk we use diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h deleted file mode 100644 index 76f3fab2feb..00000000000 --- a/include/llvm/Object/RelocVisitor.h +++ /dev/null @@ -1,362 +0,0 @@ -//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides a wrapper around all the different types of relocations -// in different file formats, such that a client can handle them in a unified -// manner by only implementing a minimal number of functions. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_OBJECT_RELOCVISITOR_H -#define LLVM_OBJECT_RELOCVISITOR_H - -#include "llvm/ADT/Triple.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/Wasm.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/ErrorHandling.h" -#include -#include - -namespace llvm { -namespace object { - -/// Base class for object file relocation visitors. -class RelocVisitor { -public: - explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {} - - // TODO: Should handle multiple applied relocations via either passing in the - // previously computed value or just count paired relocations as a single - // visit. - uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) { - if (isa(ObjToVisit)) - return visitELF(Rel, R, Value); - if (isa(ObjToVisit)) - return visitCOFF(Rel, R, Value); - if (isa(ObjToVisit)) - return visitMachO(Rel, R, Value); - if (isa(ObjToVisit)) - return visitWasm(Rel, R, Value); - - HasError = true; - return 0; - } - - bool error() { return HasError; } - -private: - const ObjectFile &ObjToVisit; - bool HasError = false; - - uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file - switch (ObjToVisit.getArch()) { - case Triple::x86_64: - return visitX86_64(Rel, R, Value); - case Triple::aarch64: - case Triple::aarch64_be: - return visitAarch64(Rel, R, Value); - case Triple::bpfel: - case Triple::bpfeb: - return visitBpf(Rel, R, Value); - case Triple::mips64el: - case Triple::mips64: - return visitMips64(Rel, R, Value); - case Triple::ppc64le: - case Triple::ppc64: - return visitPPC64(Rel, R, Value); - case Triple::systemz: - return visitSystemz(Rel, R, Value); - case Triple::sparcv9: - return visitSparc64(Rel, R, Value); - case Triple::amdgcn: - return visitAmdgpu(Rel, R, Value); - default: - HasError = true; - return 0; - } - } - - // 32-bit object file - assert(ObjToVisit.getBytesInAddress() == 4 && - "Invalid word size in object file"); - - switch (ObjToVisit.getArch()) { - case Triple::x86: - return visitX86(Rel, R, Value); - case Triple::ppc: - return visitPPC32(Rel, R, Value); - case Triple::arm: - case Triple::armeb: - return visitARM(Rel, R, Value); - case Triple::avr: - return visitAVR(Rel, R, Value); - case Triple::lanai: - return visitLanai(Rel, R, Value); - case Triple::mipsel: - case Triple::mips: - return visitMips32(Rel, R, Value); - case Triple::sparc: - return visitSparc32(Rel, R, Value); - case Triple::hexagon: - return visitHexagon(Rel, R, Value); - default: - HasError = true; - return 0; - } - } - - int64_t getELFAddend(RelocationRef R) { - Expected AddendOrErr = ELFRelocationRef(R).getAddend(); - handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) { - report_fatal_error(EI.message()); - }); - return *AddendOrErr; - } - - uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_X86_64_NONE: - return 0; - case ELF::R_X86_64_64: - case ELF::R_X86_64_DTPOFF32: - case ELF::R_X86_64_DTPOFF64: - return Value + getELFAddend(R); - case ELF::R_X86_64_PC32: - return Value + getELFAddend(R) - R.getOffset(); - case ELF::R_X86_64_32: - case ELF::R_X86_64_32S: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - } - HasError = true; - return 0; - } - - uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_AARCH64_ABS32: { - int64_t Res = Value + getELFAddend(R); - if (Res < INT32_MIN || Res > UINT32_MAX) - HasError = true; - return static_cast(Res); - } - case ELF::R_AARCH64_ABS64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_BPF_64_32: - return Value & 0xFFFFFFFF; - case ELF::R_BPF_64_64: - return Value; - } - HasError = true; - return 0; - } - - uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_MIPS_32: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_MIPS_64: - return Value + getELFAddend(R); - case ELF::R_MIPS_TLS_DTPREL64: - return Value + getELFAddend(R) - 0x8000; - } - HasError = true; - return 0; - } - - uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_PPC64_ADDR32: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_PPC64_ADDR64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_390_32: { - int64_t Res = Value + getELFAddend(R); - if (Res < INT32_MIN || Res > UINT32_MAX) - HasError = true; - return static_cast(Res); - } - case ELF::R_390_64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_SPARC_32: - case ELF::R_SPARC_64: - case ELF::R_SPARC_UA32: - case ELF::R_SPARC_UA64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_AMDGPU_ABS32: - case ELF::R_AMDGPU_ABS64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_386_NONE: - return 0; - case ELF::R_386_32: - return Value; - case ELF::R_386_PC32: - return Value - R.getOffset(); - } - HasError = true; - return 0; - } - - uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_PPC_ADDR32) - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_ARM_ABS32) { - if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX) - HasError = true; - return static_cast(Value); - } - HasError = true; - return 0; - } - - uint64_t visitAVR(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_AVR_16) { - return (Value + getELFAddend(R)) & 0xFFFF; - } else if (Rel == ELF::R_AVR_32) { - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - } - HasError = true; - return 0; - } - - uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_LANAI_32) - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) { - // FIXME: Take in account implicit addends to get correct results. - if (Rel == ELF::R_MIPS_32) - return Value & 0xFFFFFFFF; - if (Rel == ELF::R_MIPS_TLS_DTPREL32) - return Value & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32) - return Value + getELFAddend(R); - HasError = true; - return 0; - } - - uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_HEX_32) - return Value + getELFAddend(R); - HasError = true; - return 0; - } - - uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (ObjToVisit.getArch()) { - case Triple::x86: - switch (Rel) { - case COFF::IMAGE_REL_I386_SECREL: - case COFF::IMAGE_REL_I386_DIR32: - return static_cast(Value); - } - break; - case Triple::x86_64: - switch (Rel) { - case COFF::IMAGE_REL_AMD64_SECREL: - return static_cast(Value); - case COFF::IMAGE_REL_AMD64_ADDR64: - return Value; - } - break; - default: - break; - } - HasError = true; - return 0; - } - - uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getArch() == Triple::x86_64 && - Rel == MachO::X86_64_RELOC_UNSIGNED) - return Value; - HasError = true; - return 0; - } - - uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getArch() == Triple::wasm32) { - switch (Rel) { - case wasm::R_WASM_FUNCTION_INDEX_LEB: - case wasm::R_WASM_TABLE_INDEX_SLEB: - case wasm::R_WASM_TABLE_INDEX_I32: - case wasm::R_WASM_MEMORY_ADDR_LEB: - case wasm::R_WASM_MEMORY_ADDR_SLEB: - case wasm::R_WASM_MEMORY_ADDR_I32: - case wasm::R_WASM_TYPE_INDEX_LEB: - case wasm::R_WASM_GLOBAL_INDEX_LEB: - case wasm::R_WASM_FUNCTION_OFFSET_I32: - case wasm::R_WASM_SECTION_OFFSET_I32: - case wasm::R_WASM_EVENT_INDEX_LEB: - // For wasm section, its offset at 0 -- ignoring Value - return 0; - } - } - HasError = true; - return 0; - } -}; - -} // end namespace object -} // end namespace llvm - -#endif // LLVM_OBJECT_RELOCVISITOR_H diff --git a/include/llvm/Object/RelocationResolver.h b/include/llvm/Object/RelocationResolver.h new file mode 100644 index 00000000000..1246dcc5ec7 --- /dev/null +++ b/include/llvm/Object/RelocationResolver.h @@ -0,0 +1,42 @@ +//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a wrapper around all the different types of relocations +// in different file formats, such that a client can handle them in a unified +// manner by only implementing a minimal number of functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_RELOCVISITOR_H +#define LLVM_OBJECT_RELOCVISITOR_H + +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include + +namespace llvm { +namespace object { + +using RelocationResolver = uint64_t (*)(RelocationRef R, uint64_t S, uint64_t A); + +std::pair +getRelocationResolver(const ObjectFile &Obj); + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_RELOCVISITOR_H diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index dc0539f4634..789874f5cbd 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -36,7 +36,7 @@ #include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/RelocVisitor.h" +#include "llvm/Object/RelocationResolver.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Error.h" @@ -1500,6 +1500,9 @@ public: // Symbol to [address, section index] cache mapping. std::map AddrCache; + bool (*Supports)(uint64_t); + RelocationResolver Resolver; + std::tie(Supports, Resolver) = getRelocationResolver(Obj); for (const RelocationRef &Reloc : Section.relocations()) { // FIXME: it's not clear how to correctly handle scattered // relocations. @@ -1514,9 +1517,15 @@ public: continue; } - object::RelocVisitor V(Obj); - uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address); - if (V.error()) { + // Check if Resolver can handle this relocation type early so as not to + // handle invalid cases in DWARFDataExtractor. + // + // TODO Don't store Resolver in every RelocAddrEntry. + if (Supports && Supports(Reloc.getType())) { + Map->try_emplace(Reloc.getOffset(), + RelocAddrEntry{SymInfoOrErr->SectionIndex, Reloc, + Resolver, SymInfoOrErr->Address}); + } else { SmallString<32> Type; Reloc.getTypeName(Type); ErrorPolicy EP = HandleError( @@ -1524,10 +1533,7 @@ public: errorCodeToError(object_error::parse_failed))); if (EP == ErrorPolicy::Halt) return; - continue; } - RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; - Map->insert({Reloc.getOffset(), Rel}); } } diff --git a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp index bd8c23765e4..6f2f992f53e 100644 --- a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -18,12 +18,13 @@ uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off, *SecNdx = object::SectionedAddress::UndefSection; if (!Section) return getUnsigned(Off, Size); - Optional Rel = Obj->find(*Section, *Off); - if (!Rel) - return getUnsigned(Off, Size); + Optional E = Obj->find(*Section, *Off); + uint64_t A = getUnsigned(Off, Size); + if (!E) + return A; if (SecNdx) - *SecNdx = Rel->SectionIndex; - return getUnsigned(Off, Size) + Rel->Value; + *SecNdx = E->SectionIndex; + return E->Resolver(E->Reloc, E->SymbolValue, A); } Optional diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index a0ac0046c0b..c9f7da93ed3 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_library(LLVMObject Object.cpp ObjectFile.cpp RecordStreamer.cpp + RelocationResolver.cpp SymbolicFile.cpp SymbolSize.cpp WasmObjectFile.cpp diff --git a/lib/Object/RelocationResolver.cpp b/lib/Object/RelocationResolver.cpp new file mode 100644 index 00000000000..414165c58b6 --- /dev/null +++ b/lib/Object/RelocationResolver.cpp @@ -0,0 +1,497 @@ +//===- RelocationResolver.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines utilities to resolve relocations in object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/RelocationResolver.h" + +namespace llvm { +namespace object { + +static int64_t getELFAddend(RelocationRef R) { + Expected AddendOrErr = ELFRelocationRef(R).getAddend(); + handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) { + report_fatal_error(EI.message()); + }); + return *AddendOrErr; +} + +static bool supportsX86_64(uint64_t Type) { + switch (Type) { + case ELF::R_X86_64_NONE: + case ELF::R_X86_64_64: + case ELF::R_X86_64_DTPOFF32: + case ELF::R_X86_64_DTPOFF64: + case ELF::R_X86_64_PC32: + case ELF::R_X86_64_32: + case ELF::R_X86_64_32S: + return true; + default: + return false; + } +} + +static uint64_t resolveX86_64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_X86_64_NONE: + return A; + case ELF::R_X86_64_64: + case ELF::R_X86_64_DTPOFF32: + case ELF::R_X86_64_DTPOFF64: + return S + getELFAddend(R); + case ELF::R_X86_64_PC32: + return S + getELFAddend(R) - R.getOffset(); + case ELF::R_X86_64_32: + case ELF::R_X86_64_32S: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsAArch64(uint64_t Type) { + switch (Type) { + case ELF::R_AARCH64_ABS32: + case ELF::R_AARCH64_ABS64: + return true; + default: + return false; + } +} + +static uint64_t resolveAArch64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AARCH64_ABS32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_AARCH64_ABS64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsBPF(uint64_t Type) { + switch (Type) { + case ELF::R_BPF_64_32: + case ELF::R_BPF_64_64: + return true; + default: + return false; + } +} + +static uint64_t resolveBPF(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_BPF_64_32: + return S & 0xFFFFFFFF; + case ELF::R_BPF_64_64: + return S; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsMips64(uint64_t Type) { + switch (Type) { + case ELF::R_MIPS_32: + case ELF::R_MIPS_64: + case ELF::R_MIPS_TLS_DTPREL64: + return true; + default: + return false; + } +} + +static uint64_t resolveMips64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_MIPS_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_MIPS_64: + return S + getELFAddend(R); + case ELF::R_MIPS_TLS_DTPREL64: + return S + getELFAddend(R) - 0x8000; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsPPC64(uint64_t Type) { + switch (Type) { + case ELF::R_PPC64_ADDR32: + case ELF::R_PPC64_ADDR64: + return true; + default: + return false; + } +} + +static uint64_t resolvePPC64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_PPC64_ADDR32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_PPC64_ADDR64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsSystemZ(uint64_t Type) { + switch (Type) { + case ELF::R_390_32: + case ELF::R_390_64: + return true; + default: + return false; + } +} + +static uint64_t resolveSystemZ(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_390_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_390_64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsSparc64(uint64_t Type) { + switch (Type) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_64: + case ELF::R_SPARC_UA32: + case ELF::R_SPARC_UA64: + return true; + default: + return false; + } +} + +static uint64_t resolveSparc64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_64: + case ELF::R_SPARC_UA32: + case ELF::R_SPARC_UA64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsAmdgpu(uint64_t Type) { + switch (Type) { + case ELF::R_AMDGPU_ABS32: + case ELF::R_AMDGPU_ABS64: + return true; + default: + return false; + } +} + +static uint64_t resolveAmdgpu(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AMDGPU_ABS32: + case ELF::R_AMDGPU_ABS64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsX86(uint64_t Type) { + switch (Type) { + case ELF::R_386_NONE: + case ELF::R_386_32: + case ELF::R_386_PC32: + return true; + default: + return false; + } +} + +static uint64_t resolveX86(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_386_NONE: + return A; + case ELF::R_386_32: + return S + A; + case ELF::R_386_PC32: + return S - R.getOffset() + A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsPPC32(uint64_t Type) { + return Type == ELF::R_PPC_ADDR32; +} + +static uint64_t resolvePPC32(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_PPC_ADDR32) + return (S + getELFAddend(R)) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsARM(uint64_t Type) { + return Type == ELF::R_ARM_ABS32; +} + +static uint64_t resolveARM(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_ARM_ABS32) + return (S + A) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsAVR(uint64_t Type) { + switch (Type) { + case ELF::R_AVR_16: + case ELF::R_AVR_32: + return true; + default: + return false; + } +} + +static uint64_t resolveAVR(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AVR_16: + return (S + getELFAddend(R)) & 0xFFFF; + case ELF::R_AVR_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsLanai(uint64_t Type) { + return Type == ELF::R_LANAI_32; +} + +static uint64_t resolveLanai(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_LANAI_32) + return (S + getELFAddend(R)) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsMips32(uint64_t Type) { + switch (Type) { + case ELF::R_MIPS_32: + case ELF::R_MIPS_TLS_DTPREL32: + return true; + default: + return false; + } +} + +static uint64_t resolveMips32(RelocationRef R, uint64_t S, uint64_t A) { + // FIXME: Take in account implicit addends to get correct results. + uint32_t Rel = R.getType(); + if (Rel == ELF::R_MIPS_32) + return (S + A) & 0xFFFFFFFF; + if (Rel == ELF::R_MIPS_TLS_DTPREL32) + return (S + A) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsSparc32(uint64_t Type) { + switch (Type) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_UA32: + return true; + default: + return false; + } +} + +static uint64_t resolveSparc32(RelocationRef R, uint64_t S, uint64_t A) { + uint32_t Rel = R.getType(); + if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32) + return S + getELFAddend(R); + return A; +} + +static bool supportsHexagon(uint64_t Type) { + return Type == ELF::R_HEX_32; +} + +static uint64_t resolveHexagon(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_HEX_32) + return S + getELFAddend(R); + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsCOFFX86(uint64_t Type) { + switch (Type) { + case COFF::IMAGE_REL_I386_SECREL: + case COFF::IMAGE_REL_I386_DIR32: + return true; + default: + return false; + } +} + +static uint64_t resolveCOFFX86(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case COFF::IMAGE_REL_I386_SECREL: + case COFF::IMAGE_REL_I386_DIR32: + return (S + A) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsCOFFX86_64(uint64_t Type) { + switch (Type) { + case COFF::IMAGE_REL_AMD64_SECREL: + case COFF::IMAGE_REL_AMD64_ADDR64: + return true; + default: + return false; + } +} + +static uint64_t resolveCOFFX86_64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case COFF::IMAGE_REL_AMD64_SECREL: + return (S + A) & 0xFFFFFFFF; + case COFF::IMAGE_REL_AMD64_ADDR64: + return S + A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsMachOX86_64(uint64_t Type) { + return Type == MachO::X86_64_RELOC_UNSIGNED; +} + +static uint64_t resolveMachOX86_64(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == MachO::X86_64_RELOC_UNSIGNED) + return S; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsWasm32(uint64_t Type) { + switch (Type) { + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_TYPE_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + case wasm::R_WASM_EVENT_INDEX_LEB: + return true; + default: + return false; + } +} + +static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_TYPE_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + case wasm::R_WASM_EVENT_INDEX_LEB: + // For wasm section, its offset at 0 -- ignoring Value + return A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +std::pair +getRelocationResolver(const ObjectFile &Obj) { + if (Obj.isCOFF()) { + if (Obj.getBytesInAddress() == 8) + return {supportsCOFFX86_64, resolveCOFFX86_64}; + return {supportsCOFFX86, resolveCOFFX86}; + } else if (Obj.isELF()) { + if (Obj.getBytesInAddress() == 8) { + switch (Obj.getArch()) { + case Triple::x86_64: + return {supportsX86_64, resolveX86_64}; + case Triple::aarch64: + case Triple::aarch64_be: + return {supportsAArch64, resolveAArch64}; + case Triple::bpfel: + case Triple::bpfeb: + return {supportsBPF, resolveBPF}; + case Triple::mips64el: + case Triple::mips64: + return {supportsMips64, resolveMips64}; + case Triple::ppc64le: + case Triple::ppc64: + return {supportsPPC64, resolvePPC64}; + case Triple::systemz: + return {supportsSystemZ, resolveSystemZ}; + case Triple::sparcv9: + return {supportsSparc64, resolveSparc64}; + case Triple::amdgcn: + return {supportsAmdgpu, resolveAmdgpu}; + default: + return {nullptr, nullptr}; + } + } + + // 32-bit object file + assert(Obj.getBytesInAddress() == 4 && + "Invalid word size in object file"); + + switch (Obj.getArch()) { + case Triple::x86: + return {supportsX86, resolveX86}; + case Triple::ppc: + return {supportsPPC32, resolvePPC32}; + case Triple::arm: + case Triple::armeb: + return {supportsARM, resolveARM}; + case Triple::avr: + return {supportsAVR, resolveAVR}; + case Triple::lanai: + return {supportsLanai, resolveLanai}; + case Triple::mipsel: + case Triple::mips: + return {supportsMips32, resolveMips32}; + case Triple::sparc: + return {supportsSparc32, resolveSparc32}; + case Triple::hexagon: + return {supportsHexagon, resolveHexagon}; + default: + return {nullptr, nullptr}; + } + } else if (Obj.isMachO()) { + if (Obj.getArch() == Triple::x86_64) + return {supportsMachOX86_64, resolveMachOX86_64}; + return {nullptr, nullptr}; + } else if (Obj.isWasm()) { + if (Obj.getArch() == Triple::wasm32) + return {supportsWasm32, resolveWasm32}; + return {nullptr, nullptr}; + } + + llvm_unreachable("Invalid object file"); +} + +} // namespace object +} // namespace llvm diff --git a/test/Object/invalid.test b/test/Object/invalid.test index 6f3ab2a1762..a2650b88335 100644 --- a/test/Object/invalid.test +++ b/test/Object/invalid.test @@ -3,7 +3,7 @@ RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-size.elf 2>&1 | FileCheck %s RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-zero-size.elf 2>&1 | FileCheck %s CHECK: Invalid data was encountered while parsing the file -RUN: not llvm-dwarfdump %p/Inputs/invalid-bad-rel-type.elf 2>&1 | FileCheck --check-prefix=RELA %s +RUN: not llvm-dwarfdump -debug-line %p/Inputs/invalid-bad-rel-type.elf 2>&1 | FileCheck --check-prefix=RELA %s RELA: Section is not SHT_RELA RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-non-null.elf 2>&1 | FileCheck --check-prefix=NON-NULL %s