blob: 1594ba55f99474b9322769c32552547e04d40d67 [file] [log] [blame]
Rui Ueyama0ca149f2013-08-06 22:31:59 +00001//===- lib/ReaderWriter/MachO/MachOLinkingContext.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#include "lld/ReaderWriter/MachOLinkingContext.h"
11#include "GOTPass.hpp"
12#include "StubsPass.hpp"
13#include "ReferenceKinds.h"
14#include "MachOFormat.hpp"
15
16#include "lld/Core/PassManager.h"
17#include "lld/ReaderWriter/Reader.h"
18#include "lld/ReaderWriter/Writer.h"
19#include "lld/Passes/LayoutPass.h"
20
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/Triple.h"
23
24using lld::mach_o::KindHandler;
25
26namespace lld {
27
28MachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {
29 if (parse(str, *this))
30 llvm_unreachable("bad version string");
31}
32
33/// Construct 32-bit PackedVersion from string "X.Y.Z" where
34/// bits are xxxx.yy.zz. Largest number is 65535.255.255
35bool MachOLinkingContext::PackedVersion::parse(
36 StringRef str, MachOLinkingContext::PackedVersion &result) {
37 result._value = 0;
38
39 if (str.empty())
40 return false;
41
42 SmallVector<StringRef, 3> parts;
43 llvm::SplitString(str, parts, ".");
44
45 unsigned long long num;
46 if (llvm::getAsUnsignedInteger(parts[0], 10, num))
47 return true;
48 if (num > 65535)
49 return true;
50 result._value = num << 16;
51
52 if (parts.size() > 1) {
53 if (llvm::getAsUnsignedInteger(parts[1], 10, num))
54 return true;
55 if (num > 255)
56 return true;
57 result._value |= (num << 8);
58 }
59
60 if (parts.size() > 2) {
61 if (llvm::getAsUnsignedInteger(parts[2], 10, num))
62 return true;
63 if (num > 255)
64 return true;
65 result._value |= num;
66 }
67
68 return false;
69}
70
71bool MachOLinkingContext::PackedVersion::
72operator<(const PackedVersion &rhs) const {
73 return _value < rhs._value;
74}
75
76bool MachOLinkingContext::PackedVersion::
77operator>=(const PackedVersion &rhs) const {
78 return _value >= rhs._value;
79}
80
81bool MachOLinkingContext::PackedVersion::
82operator==(const PackedVersion &rhs) const {
83 return _value == rhs._value;
84}
85
86struct ArchInfo {
87 StringRef archName;
88 MachOLinkingContext::Arch arch;
89 uint32_t cputype;
90 uint32_t cpusubtype;
91};
92
93static ArchInfo archInfos[] = {
94 { "x86_64", MachOLinkingContext::arch_x86_64, mach_o::CPU_TYPE_X86_64,
95 mach_o::CPU_SUBTYPE_X86_64_ALL },
96 { "i386", MachOLinkingContext::arch_x86, mach_o::CPU_TYPE_I386,
97 mach_o::CPU_SUBTYPE_X86_ALL },
98 { "armv6", MachOLinkingContext::arch_armv6, mach_o::CPU_TYPE_ARM,
99 mach_o::CPU_SUBTYPE_ARM_V6 },
100 { "armv7", MachOLinkingContext::arch_armv7, mach_o::CPU_TYPE_ARM,
101 mach_o::CPU_SUBTYPE_ARM_V7 },
102 { "armv7s", MachOLinkingContext::arch_armv7s, mach_o::CPU_TYPE_ARM,
103 mach_o::CPU_SUBTYPE_ARM_V7S },
104 { StringRef(), MachOLinkingContext::arch_unknown, 0, 0 }
105};
106
107MachOLinkingContext::Arch
108MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
109 for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
110 if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype)) {
111 return info->arch;
112 }
113 }
114 return arch_unknown;
115}
116
117MachOLinkingContext::Arch
118MachOLinkingContext::archFromName(StringRef archName) {
119 for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
120 if (info->archName.equals(archName)) {
121 return info->arch;
122 }
123 }
124 return arch_unknown;
125}
126
127uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
128 assert(arch != arch_unknown);
129 for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
130 if (info->arch == arch) {
131 return info->cputype;
132 }
133 }
134 llvm_unreachable("Unknown arch type");
135}
136
137uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
138 assert(arch != arch_unknown);
139 for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
140 if (info->arch == arch) {
141 return info->cpusubtype;
142 }
143 }
144 llvm_unreachable("Unknown arch type");
145}
146
147MachOLinkingContext::MachOLinkingContext()
148 : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),
149 _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),
150 _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}
151
152MachOLinkingContext::~MachOLinkingContext() {}
153
154uint32_t MachOLinkingContext::getCPUType() const {
155 return cpuTypeFromArch(_arch);
156}
157
158uint32_t MachOLinkingContext::getCPUSubType() const {
159 return cpuSubtypeFromArch(_arch);
160}
161
162bool MachOLinkingContext::outputTypeHasEntry() const {
163 switch (_outputFileType) {
164 case mach_o::MH_EXECUTE:
165 case mach_o::MH_DYLINKER:
166 case mach_o::MH_PRELOAD:
167 return true;
168 default:
169 return false;
170 }
171}
172
173bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
174 switch (_os) {
175 case OS::macOSX:
176 return (_osMinVersion >= PackedVersion(mac));
177 case OS::iOS:
178 case OS::iOS_simulator:
179 return (_osMinVersion >= PackedVersion(iOS));
180 }
181 llvm_unreachable("target not configured for iOS or MacOSX");
182}
183
184bool MachOLinkingContext::addEntryPointLoadCommand() const {
185 if ((_outputFileType == mach_o::MH_EXECUTE) && !_outputFileTypeStatic) {
186 return minOS("10.8", "6.0");
187 }
188 return false;
189}
190
191bool MachOLinkingContext::addUnixThreadLoadCommand() const {
192 switch (_outputFileType) {
193 case mach_o::MH_EXECUTE:
194 if (_outputFileTypeStatic)
195 return true;
196 else
197 return !minOS("10.8", "6.0");
198 break;
199 case mach_o::MH_DYLINKER:
200 case mach_o::MH_PRELOAD:
201 return true;
202 default:
203 return false;
204 }
205}
206
207bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
208 if (_inputFiles.empty()) {
209 diagnostics << "no object files specified\n";
210 return true;
211 }
212
213 if ((_outputFileType == mach_o::MH_EXECUTE) && _entrySymbolName.empty()) {
214 if (_outputFileTypeStatic) {
215 _entrySymbolName = "start";
216 } else {
217 // If targeting newer OS, use _main
218 if (addEntryPointLoadCommand())
219 _entrySymbolName = "_main";
220
221 // If targeting older OS, use start (in crt1.o)
222 if (addUnixThreadLoadCommand())
223 _entrySymbolName = "start";
224 }
225 }
226
227 return false;
228}
229
230bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {
231 _os = os;
232 return PackedVersion::parse(minOSVersion, _osMinVersion);
233}
234
235void MachOLinkingContext::addPasses(PassManager &pm) const {
236 pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
237 pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
238 pm.add(std::unique_ptr<Pass>(new LayoutPass()));
239}
240
241error_code MachOLinkingContext::parseFile(
242 std::unique_ptr<MemoryBuffer> &mb,
243 std::vector<std::unique_ptr<File>> &result) const {
244 // if (!_machoReader)
245 // _machoReader = createReaderMachO(*this);
246 // error_code ec = _machoReader->parseFile(mb,result);
247 // if (ec) {
248 return _yamlReader->parseFile(mb, result);
249 // }
250
251 return error_code::success();
252}
253
254Writer &MachOLinkingContext::writer() const {
255 if (!_writer) {
256 _writer = createWriterMachO(*this);
257 }
258 return *_writer;
259}
260
261KindHandler &MachOLinkingContext::kindHandler() const {
262 if (!_kindHandler)
263 _kindHandler = KindHandler::create(_arch);
264 return *_kindHandler;
265}
266
267ErrorOr<Reference::Kind>
268MachOLinkingContext::relocKindFromString(StringRef str) const {
269 return kindHandler().stringToKind(str);
270}
271
272ErrorOr<std::string>
273MachOLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
274 return std::string(kindHandler().kindToString(kind));
275}
276
277} // end namespace lld