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