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
ArchHandler()25 ArchHandler::ArchHandler() {
26 }
27
~ArchHandler()28 ArchHandler::~ArchHandler() {
29 }
30
create(MachOLinkingContext::Arch arch)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
isLazyPointer(const Reference & ref)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
relocPattern(const Relocation & reloc)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
relocFromPattern(ArchHandler::RelocPattern pattern)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
appendReloc(normalized::Relocations & relocs,uint32_t offset,uint32_t symbol,uint32_t value,RelocPattern pattern)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
readS16(const uint8_t * addr,bool isBig)126 int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) {
127 return read16(addr, isBig);
128 }
129
readS32(const uint8_t * addr,bool isBig)130 int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) {
131 return read32(addr, isBig);
132 }
133
readU32(const uint8_t * addr,bool isBig)134 uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) {
135 return read32(addr, isBig);
136 }
137
readS64(const uint8_t * addr,bool isBig)138 int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) {
139 return read64(addr, isBig);
140 }
141
isDwarfCIE(bool isBig,const DefinedAtom * atom)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
fdeTargetFunction(const DefinedAtom * fde)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