1 //===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 10 #include "ArchHandler.h" 11 #include "Atoms.h" 12 #include "MachONormalizedFileBinaryUtils.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/StringSwitch.h" 15 #include "llvm/ADT/Triple.h" 16 #include "llvm/Support/ErrorHandling.h" 17 18 using namespace llvm::MachO; 19 using namespace lld::mach_o::normalized; 20 21 namespace lld { 22 namespace mach_o { 23 24 25 ArchHandler::ArchHandler() { 26 } 27 28 ArchHandler::~ArchHandler() { 29 } 30 31 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create( 32 MachOLinkingContext::Arch arch) { 33 switch (arch) { 34 case MachOLinkingContext::arch_x86_64: 35 return create_x86_64(); 36 case MachOLinkingContext::arch_x86: 37 return create_x86(); 38 case MachOLinkingContext::arch_armv6: 39 case MachOLinkingContext::arch_armv7: 40 case MachOLinkingContext::arch_armv7s: 41 return create_arm(); 42 case MachOLinkingContext::arch_arm64: 43 return create_arm64(); 44 default: 45 llvm_unreachable("Unknown arch"); 46 } 47 } 48 49 50 bool ArchHandler::isLazyPointer(const Reference &ref) { 51 // A lazy bind entry is needed for a lazy pointer. 52 const StubInfo &info = stubInfo(); 53 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 54 return false; 55 if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch) 56 return false; 57 return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind); 58 } 59 60 61 ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) { 62 assert((reloc.type & 0xFFF0) == 0); 63 uint16_t result = reloc.type; 64 if (reloc.scattered) 65 result |= rScattered; 66 if (reloc.pcRel) 67 result |= rPcRel; 68 if (reloc.isExtern) 69 result |= rExtern; 70 switch(reloc.length) { 71 case 0: 72 break; 73 case 1: 74 result |= rLength2; 75 break; 76 case 2: 77 result |= rLength4; 78 break; 79 case 3: 80 result |= rLength8; 81 break; 82 default: 83 llvm_unreachable("bad r_length"); 84 } 85 return result; 86 } 87 88 normalized::Relocation 89 ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) { 90 normalized::Relocation result; 91 result.offset = 0; 92 result.scattered = (pattern & rScattered); 93 result.type = (RelocationInfoType)(pattern & 0xF); 94 result.pcRel = (pattern & rPcRel); 95 result.isExtern = (pattern & rExtern); 96 result.value = 0; 97 result.symbol = 0; 98 switch (pattern & 0x300) { 99 case rLength1: 100 result.length = 0; 101 break; 102 case rLength2: 103 result.length = 1; 104 break; 105 case rLength4: 106 result.length = 2; 107 break; 108 case rLength8: 109 result.length = 3; 110 break; 111 } 112 return result; 113 } 114 115 void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset, 116 uint32_t symbol, uint32_t value, 117 RelocPattern pattern) { 118 normalized::Relocation reloc = relocFromPattern(pattern); 119 reloc.offset = offset; 120 reloc.symbol = symbol; 121 reloc.value = value; 122 relocs.push_back(reloc); 123 } 124 125 126 int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) { 127 return read16(addr, isBig); 128 } 129 130 int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) { 131 return read32(addr, isBig); 132 } 133 134 uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) { 135 return read32(addr, isBig); 136 } 137 138 int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) { 139 return read64(addr, isBig); 140 } 141 142 bool ArchHandler::isDwarfCIE(bool isBig, const DefinedAtom *atom) { 143 assert(atom->contentType() == DefinedAtom::typeCFI); 144 if (atom->rawContent().size() < sizeof(uint32_t)) 145 return false; 146 uint32_t size = read32(atom->rawContent().data(), isBig); 147 148 uint32_t idOffset = sizeof(uint32_t); 149 if (size == 0xffffffffU) 150 idOffset += sizeof(uint64_t); 151 152 return read32(atom->rawContent().data() + idOffset, isBig) == 0; 153 } 154 155 const Atom *ArchHandler::fdeTargetFunction(const DefinedAtom *fde) { 156 for (auto ref : *fde) { 157 if (ref->kindNamespace() == Reference::KindNamespace::mach_o && 158 ref->kindValue() == unwindRefToFunctionKind()) { 159 assert(ref->kindArch() == kindArch() && "unexpected Reference arch"); 160 return ref->target(); 161 } 162 } 163 164 return nullptr; 165 } 166 167 } // namespace mach_o 168 } // namespace lld 169 170 171 172