blob: faabffaf5ca89546bb48983dbee1cf66d91bca40 [file] [log] [blame]
Nick Kledzik2458bec2014-07-16 19:49:02 +00001//===- lib/FileFormat/MachO/ArchHandler_x86.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 "ArchHandler.h"
11#include "Atoms.h"
12#include "MachONormalizedFileBinaryUtils.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000013#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/StringSwitch.h"
15#include "llvm/ADT/Triple.h"
Tim Northover40d3ad32014-10-27 22:48:35 +000016#include "llvm/Support/Endian.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000017#include "llvm/Support/ErrorHandling.h"
18
19using namespace llvm::MachO;
20using namespace lld::mach_o::normalized;
21
22namespace lld {
23namespace mach_o {
24
Tim Northover40d3ad32014-10-27 22:48:35 +000025using llvm::support::ulittle16_t;
26using llvm::support::ulittle32_t;
27
28using llvm::support::little16_t;
29using llvm::support::little32_t;
30
Nick Kledzik2458bec2014-07-16 19:49:02 +000031class ArchHandler_x86 : public ArchHandler {
32public:
Rui Ueyama9071e4a2015-09-10 18:51:36 +000033 ArchHandler_x86() = default;
34 ~ArchHandler_x86() override = default;
Nick Kledzik2458bec2014-07-16 19:49:02 +000035
36 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
37
38 Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
39
40 const StubInfo &stubInfo() override { return _sStubInfo; }
41 bool isCallSite(const Reference &) override;
Nick Kledzik4121bce2014-10-14 01:51:42 +000042 bool isNonCallBranch(const Reference &) override {
43 return false;
44 }
45
Nick Kledzik2458bec2014-07-16 19:49:02 +000046 bool isPointer(const Reference &) override;
47 bool isPairedReloc(const normalized::Relocation &) override;
Tim Northovercf78d372014-09-30 21:29:54 +000048
49 bool needsCompactUnwind() override {
50 return false;
51 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000052
Tim Northovercf78d372014-09-30 21:29:54 +000053 Reference::KindValue imageOffsetKind() override {
54 return invalid;
55 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000056
Tim Northovercf78d372014-09-30 21:29:54 +000057 Reference::KindValue imageOffsetKindIndirect() override {
58 return invalid;
59 }
60
Pete Cooperebecd6c2016-03-15 21:33:10 +000061 Reference::KindValue unwindRefToPersonalityFunctionKind() override {
62 return invalid;
63 }
64
Tim Northover995abe32014-10-15 20:26:24 +000065 Reference::KindValue unwindRefToCIEKind() override {
66 return negDelta32;
67 }
68
Tim Northovera6a6ab92014-10-15 18:19:31 +000069 Reference::KindValue unwindRefToFunctionKind() override{
70 return delta32;
71 }
72
Tim Northover1cc4fb72014-10-15 19:32:21 +000073 Reference::KindValue unwindRefToEhFrameKind() override {
74 return invalid;
75 }
76
Pete Cooper1a6098b2016-02-02 00:02:50 +000077 Reference::KindValue pointerKind() override {
78 return invalid;
79 }
80
Tim Northover1cc4fb72014-10-15 19:32:21 +000081 uint32_t dwarfCompactUnwindType() override {
82 return 0x04000000U;
83 }
84
Nick Kledzik2458bec2014-07-16 19:49:02 +000085 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
86 const DefinedAtom *inAtom,
87 uint32_t offsetInAtom,
88 uint64_t fixupAddress, bool swap,
89 FindAtomBySectionAndAddress atomFromAddress,
90 FindAtomBySymbolIndex atomFromSymbolIndex,
91 Reference::KindValue *kind,
92 const lld::Atom **target,
93 Reference::Addend *addend) override;
94 std::error_code
95 getPairReferenceInfo(const normalized::Relocation &reloc1,
96 const normalized::Relocation &reloc2,
97 const DefinedAtom *inAtom,
98 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +000099 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000100 FindAtomBySectionAndAddress atomFromAddress,
101 FindAtomBySymbolIndex atomFromSymbolIndex,
102 Reference::KindValue *kind,
103 const lld::Atom **target,
104 Reference::Addend *addend) override;
105
Nick Kledzik2d432352014-07-17 23:16:21 +0000106 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
107 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000108 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000109 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +0000110 uint8_t *atomContentBuffer) override;
111
112 void appendSectionRelocations(const DefinedAtom &atom,
113 uint64_t atomSectionOffset,
114 const Reference &ref,
115 FindSymbolIndexForAtom symbolIndexForAtom,
116 FindSectionIndexForAtom sectionIndexForAtom,
117 FindAddressForAtom addressForAtom,
118 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000119
Nick Kledzik21921372014-07-24 23:06:56 +0000120 bool isDataInCodeTransition(Reference::KindValue refKind) override {
121 switch (refKind) {
122 case modeCode:
123 case modeData:
124 return true;
125 default:
126 return false;
127 break;
128 }
129 }
130
131 Reference::KindValue dataInCodeTransitionStart(
132 const MachODefinedAtom &atom) override {
133 return modeData;
134 }
135
136 Reference::KindValue dataInCodeTransitionEnd(
137 const MachODefinedAtom &atom) override {
138 return modeCode;
139 }
140
Nick Kledzik2458bec2014-07-16 19:49:02 +0000141private:
142 static const Registry::KindStrings _sKindStrings[];
143 static const StubInfo _sStubInfo;
144
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000145 enum X86Kind : Reference::KindValue {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000146 invalid, /// for error condition
147
Nick Kledzik21921372014-07-24 23:06:56 +0000148 modeCode, /// Content starting at this offset is code.
149 modeData, /// Content starting at this offset is data.
150
Nick Kledzik2458bec2014-07-16 19:49:02 +0000151 // Kinds found in mach-o .o files:
152 branch32, /// ex: call _foo
153 branch16, /// ex: callw _foo
154 abs32, /// ex: movl _foo, %eax
155 funcRel32, /// ex: movl _foo-L1(%eax), %eax
156 pointer32, /// ex: .long _foo
157 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000158 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000159
160 // Kinds introduced by Passes:
161 lazyPointer, /// Location contains a lazy pointer.
162 lazyImmediateLocation, /// Location contains immediate value used in stub.
163 };
Shankar Easwarana1d36372015-02-22 23:54:38 +0000164
Nick Kledzik2d432352014-07-17 23:16:21 +0000165 static bool useExternalRelocationTo(const Atom &target);
166
167 void applyFixupFinal(const Reference &ref, uint8_t *location,
168 uint64_t fixupAddress, uint64_t targetAddress,
169 uint64_t inAtomAddress);
170
171 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
172 uint64_t fixupAddress,
173 uint64_t targetAddress,
174 uint64_t inAtomAddress);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000175};
176
177//===----------------------------------------------------------------------===//
178// ArchHandler_x86
179//===----------------------------------------------------------------------===//
180
Nick Kledzik2458bec2014-07-16 19:49:02 +0000181const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
182 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000183 LLD_KIND_STRING_ENTRY(modeCode),
184 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000185 LLD_KIND_STRING_ENTRY(branch32),
186 LLD_KIND_STRING_ENTRY(branch16),
187 LLD_KIND_STRING_ENTRY(abs32),
188 LLD_KIND_STRING_ENTRY(funcRel32),
189 LLD_KIND_STRING_ENTRY(pointer32),
190 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000191 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000192 LLD_KIND_STRING_ENTRY(lazyPointer),
193 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
194 LLD_KIND_STRING_END
195};
196
197const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
198 "dyld_stub_binder",
199
Shankar Easwarana1d36372015-02-22 23:54:38 +0000200 // Lazy pointer references
Nick Kledzik2458bec2014-07-16 19:49:02 +0000201 { Reference::KindArch::x86, pointer32, 0, 0 },
202 { Reference::KindArch::x86, lazyPointer, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000203
Nick Kledzik2458bec2014-07-16 19:49:02 +0000204 // GOT pointer to dyld_stub_binder
205 { Reference::KindArch::x86, pointer32, 0, 0 },
206
207 // x86 code alignment
Shankar Easwarana1d36372015-02-22 23:54:38 +0000208 1,
209
Nick Kledzik2458bec2014-07-16 19:49:02 +0000210 // Stub size and code
Shankar Easwarana1d36372015-02-22 23:54:38 +0000211 6,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000212 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
213 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000214 { false, 0, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000215
Nick Kledzik2458bec2014-07-16 19:49:02 +0000216 // Stub Helper size and code
217 10,
218 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
219 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
220 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
221 { Reference::KindArch::x86, branch32, 6, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000222
Pete Coopere8d9df42016-02-09 20:11:17 +0000223 // Stub helper image cache content type
224 DefinedAtom::typeNonLazyPointer,
225
Nick Kledzik2458bec2014-07-16 19:49:02 +0000226 // Stub Helper-Common size and code
227 12,
Pete Cooper35c33182016-02-09 18:56:37 +0000228 // Stub helper alignment
229 2,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000230 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
231 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
232 0x90 }, // nop
233 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000234 { false, 0, 0, 0 },
235 { Reference::KindArch::x86, abs32, 7, 0 },
236 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000237};
238
239bool ArchHandler_x86::isCallSite(const Reference &ref) {
240 return (ref.kindValue() == branch32);
241}
242
243bool ArchHandler_x86::isPointer(const Reference &ref) {
244 return (ref.kindValue() == pointer32);
245}
246
247bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
248 if (!reloc.scattered)
249 return false;
250 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
251 (reloc.type == GENERIC_RELOC_SECTDIFF);
252}
253
254std::error_code
255ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
256 const DefinedAtom *inAtom,
257 uint32_t offsetInAtom,
258 uint64_t fixupAddress, bool swap,
259 FindAtomBySectionAndAddress atomFromAddress,
260 FindAtomBySymbolIndex atomFromSymbolIndex,
261 Reference::KindValue *kind,
262 const lld::Atom **target,
263 Reference::Addend *addend) {
264 typedef std::error_code E;
265 DefinedAtom::ContentPermissions perms;
266 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
267 uint64_t targetAddress;
268 switch (relocPattern(reloc)) {
269 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
270 // ex: call _foo (and _foo undefined)
271 *kind = branch32;
272 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
273 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000274 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000275 break;
276 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
277 // ex: call _foo (and _foo defined)
278 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000279 targetAddress =
280 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000281 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
282 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000283 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
284 // ex: call _foo+n (and _foo defined)
285 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000286 targetAddress =
287 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000288 if (E ec = atomFromAddress(0, reloc.value, target, addend))
289 return ec;
290 *addend = targetAddress - reloc.value;
291 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000292 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
293 // ex: callw _foo (and _foo undefined)
294 *kind = branch16;
295 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
296 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000297 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000298 break;
299 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
300 // ex: callw _foo (and _foo defined)
301 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000302 targetAddress =
303 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000304 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
305 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000306 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
307 // ex: callw _foo+n (and _foo defined)
308 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000309 targetAddress =
310 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000311 if (E ec = atomFromAddress(0, reloc.value, target, addend))
312 return ec;
313 *addend = targetAddress - reloc.value;
314 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000315 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
316 // ex: movl _foo, %eax (and _foo undefined)
317 // ex: .long _foo (and _foo undefined)
318 perms = inAtom->permissions();
319 *kind =
320 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
321 : pointer32;
322 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
323 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000324 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000325 break;
326 case GENERIC_RELOC_VANILLA | rLength4:
327 // ex: movl _foo, %eax (and _foo defined)
328 // ex: .long _foo (and _foo defined)
329 perms = inAtom->permissions();
330 *kind =
331 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
332 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000333 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000334 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
335 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000336 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
337 // ex: .long _foo+n (and _foo defined)
338 perms = inAtom->permissions();
339 *kind =
340 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
341 : pointer32;
342 if (E ec = atomFromAddress(0, reloc.value, target, addend))
343 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000344 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000345 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000346 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000347 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000348 }
349 return std::error_code();
350}
351
352std::error_code
353ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
354 const normalized::Relocation &reloc2,
355 const DefinedAtom *inAtom,
356 uint32_t offsetInAtom,
357 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000358 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000359 FindAtomBySectionAndAddress atomFromAddr,
360 FindAtomBySymbolIndex atomFromSymbolIndex,
361 Reference::KindValue *kind,
362 const lld::Atom **target,
363 Reference::Addend *addend) {
364 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
365 std::error_code ec;
366 DefinedAtom::ContentPermissions perms = inAtom->permissions();
367 uint32_t fromAddress;
368 uint32_t toAddress;
369 uint32_t value;
370 const lld::Atom *fromTarget;
371 Reference::Addend offsetInTo;
372 Reference::Addend offsetInFrom;
373 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000374 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
375 GENERIC_RELOC_PAIR | rScattered | rLength4):
376 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
377 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000378 toAddress = reloc1.value;
379 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000380 value = *(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000381 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
382 if (ec)
383 return ec;
384 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
385 if (ec)
386 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000387 if (fromTarget != inAtom) {
Shankar Easwarana1d36372015-02-22 23:54:38 +0000388 if (*target != inAtom)
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000389 return make_dynamic_error_code(
390 "SECTDIFF relocation where neither target is in atom");
Nick Kledzik03e16f22014-07-21 22:06:57 +0000391 *kind = negDelta32;
392 *addend = toAddress - value - fromAddress;
393 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000394 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000395 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
396 // SECTDIFF relocations are used in i386 codegen where the function
397 // prolog does a CALL to the next instruction which POPs the return
398 // address into EBX which becomes the pic-base register. The POP
399 // instruction is label the used for the subtrahend in expressions.
400 // The funcRel32 kind represents the 32-bit delta to some symbol from
401 // the start of the function (atom) containing the funcRel32.
402 *kind = funcRel32;
403 uint32_t ta = fromAddress + value - toAddress;
404 *addend = ta - offsetInFrom;
405 } else {
406 *kind = delta32;
407 *addend = fromAddress + value - toAddress;
408 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000409 }
410 return std::error_code();
411 break;
412 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000413 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000414 }
415}
416
Nick Kledzik2d432352014-07-17 23:16:21 +0000417void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000418 bool relocatable,
419 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000420 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000421 uint64_t imageBaseAddress,
422 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000423 // Copy raw bytes.
424 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
425 // Apply fix-ups.
426 for (const Reference *ref : atom) {
427 uint32_t offset = ref->offsetInAtom();
428 const Atom *target = ref->target();
429 uint64_t targetAddress = 0;
430 if (isa<DefinedAtom>(target))
431 targetAddress = findAddress(*target);
432 uint64_t atomAddress = findAddress(atom);
433 uint64_t fixupAddress = atomAddress + offset;
434 if (relocatable) {
435 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
436 fixupAddress, targetAddress,
437 atomAddress);
438 } else {
439 applyFixupFinal(*ref, &atomContentBuffer[offset],
440 fixupAddress, targetAddress,
441 atomAddress);
442 }
443 }
444}
445
Tim Northover40d3ad32014-10-27 22:48:35 +0000446void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000447 uint64_t fixupAddress,
448 uint64_t targetAddress,
449 uint64_t inAtomAddress) {
450 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000451 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000452 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000453 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000454 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000455 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000456 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000457 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000458 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000459 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000460 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000461 case pointer32:
462 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000463 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000464 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000465 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000466 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000467 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000468 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000469 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000470 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000471 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000472 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000473 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000474 case modeCode:
475 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000476 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000477 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000478 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000479 case lazyImmediateLocation:
480 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000481 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000482 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000483 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000484 break;
485 }
486}
487
Nick Kledzik2d432352014-07-17 23:16:21 +0000488void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000489 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000490 uint64_t fixupAddress,
491 uint64_t targetAddress,
492 uint64_t inAtomAddress) {
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000493 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
494 return;
495 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000496 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000497 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
498 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000499 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000500 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000501 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000502 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000503 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000504 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000505 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000506 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000507 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000508 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000509 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000510 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000511 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000512 case pointer32:
513 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000514 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000515 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000516 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000517 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000518 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000519 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000520 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000521 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000522 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000523 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000524 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000525 case modeCode:
526 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000527 case lazyPointer:
528 case lazyImmediateLocation:
529 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000530 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000531 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000532 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000533 break;
534 }
535}
536
537bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
538 // Undefined symbols are referenced via external relocations.
539 if (isa<UndefinedAtom>(&target))
540 return true;
541 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
542 switch (defAtom->merge()) {
543 case DefinedAtom::mergeAsTentative:
544 // Tentative definitions are referenced via external relocations.
545 return true;
546 case DefinedAtom::mergeAsWeak:
547 case DefinedAtom::mergeAsWeakAndAddressUsed:
548 // Global weak-defs are referenced via external relocations.
549 return (defAtom->scope() == DefinedAtom::scopeGlobal);
550 default:
551 break;
552 }
553 }
554 // Everything else is reference via an internal relocation.
555 return false;
556}
557
Nick Kledzik2d432352014-07-17 23:16:21 +0000558void ArchHandler_x86::appendSectionRelocations(
559 const DefinedAtom &atom,
560 uint64_t atomSectionOffset,
561 const Reference &ref,
562 FindSymbolIndexForAtom symbolIndexForAtom,
563 FindSectionIndexForAtom sectionIndexForAtom,
564 FindAddressForAtom addressForAtom,
565 normalized::Relocations &relocs) {
566 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
567 return;
568 assert(ref.kindArch() == Reference::KindArch::x86);
569 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
570 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000571 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik21921372014-07-24 23:06:56 +0000572 case modeCode:
573 case modeData:
574 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000575 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000576 if (useExternalReloc) {
577 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
578 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
579 } else {
580 if (ref.addend() != 0)
581 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
582 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
583 else
584 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
585 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
586 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000587 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000588 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000589 if (useExternalReloc) {
590 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
591 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
592 } else {
593 if (ref.addend() != 0)
594 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
595 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
596 else
597 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
598 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
599 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000600 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000601 case pointer32:
602 case abs32:
603 if (useExternalReloc)
604 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000605 GENERIC_RELOC_VANILLA | rExtern | rLength4);
606 else {
607 if (ref.addend() != 0)
608 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
609 GENERIC_RELOC_VANILLA | rScattered | rLength4);
610 else
611 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000612 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000613 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000614 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000615 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000616 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
617 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
618 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
619 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000620 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000621 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000622 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
623 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
624 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
625 ref.offsetInAtom(),
626 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000627 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000628 case negDelta32:
629 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
630 ref.offsetInAtom(),
631 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
632 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
633 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000634 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000635 case lazyPointer:
636 case lazyImmediateLocation:
637 llvm_unreachable("lazy reference kind implies Stubs pass was run");
638 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000639 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000640 llvm_unreachable("unknown x86 Reference Kind");
641 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000642 }
643}
644
Nick Kledzik2458bec2014-07-16 19:49:02 +0000645std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
646 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
647}
648
649} // namespace mach_o
650} // namespace lld