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