blob: 4530621f8fcd02d37c0f486308dc89d1d5fcf109 [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:
33 ArchHandler_x86();
34 virtual ~ArchHandler_x86();
35
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 }
52 Reference::KindValue imageOffsetKind() override {
53 return invalid;
54 }
55 Reference::KindValue imageOffsetKindIndirect() override {
56 return invalid;
57 }
58
Tim Northover995abe32014-10-15 20:26:24 +000059 Reference::KindValue unwindRefToCIEKind() override {
60 return negDelta32;
61 }
62
Tim Northovera6a6ab92014-10-15 18:19:31 +000063 Reference::KindValue unwindRefToFunctionKind() override{
64 return delta32;
65 }
66
Tim Northover1cc4fb72014-10-15 19:32:21 +000067 Reference::KindValue unwindRefToEhFrameKind() override {
68 return invalid;
69 }
70
71
72 uint32_t dwarfCompactUnwindType() override {
73 return 0x04000000U;
74 }
75
Nick Kledzik2458bec2014-07-16 19:49:02 +000076 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
77 const DefinedAtom *inAtom,
78 uint32_t offsetInAtom,
79 uint64_t fixupAddress, bool swap,
80 FindAtomBySectionAndAddress atomFromAddress,
81 FindAtomBySymbolIndex atomFromSymbolIndex,
82 Reference::KindValue *kind,
83 const lld::Atom **target,
84 Reference::Addend *addend) override;
85 std::error_code
86 getPairReferenceInfo(const normalized::Relocation &reloc1,
87 const normalized::Relocation &reloc2,
88 const DefinedAtom *inAtom,
89 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +000090 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +000091 FindAtomBySectionAndAddress atomFromAddress,
92 FindAtomBySymbolIndex atomFromSymbolIndex,
93 Reference::KindValue *kind,
94 const lld::Atom **target,
95 Reference::Addend *addend) override;
96
Nick Kledzik2d432352014-07-17 23:16:21 +000097 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
98 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +000099 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000100 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +0000101 uint8_t *atomContentBuffer) override;
102
103 void appendSectionRelocations(const DefinedAtom &atom,
104 uint64_t atomSectionOffset,
105 const Reference &ref,
106 FindSymbolIndexForAtom symbolIndexForAtom,
107 FindSectionIndexForAtom sectionIndexForAtom,
108 FindAddressForAtom addressForAtom,
109 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000110
Nick Kledzik21921372014-07-24 23:06:56 +0000111 bool isDataInCodeTransition(Reference::KindValue refKind) override {
112 switch (refKind) {
113 case modeCode:
114 case modeData:
115 return true;
116 default:
117 return false;
118 break;
119 }
120 }
121
122 Reference::KindValue dataInCodeTransitionStart(
123 const MachODefinedAtom &atom) override {
124 return modeData;
125 }
126
127 Reference::KindValue dataInCodeTransitionEnd(
128 const MachODefinedAtom &atom) override {
129 return modeCode;
130 }
131
Nick Kledzik2458bec2014-07-16 19:49:02 +0000132private:
133 static const Registry::KindStrings _sKindStrings[];
134 static const StubInfo _sStubInfo;
135
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000136 enum : Reference::KindValue {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000137 invalid, /// for error condition
138
Nick Kledzik21921372014-07-24 23:06:56 +0000139 modeCode, /// Content starting at this offset is code.
140 modeData, /// Content starting at this offset is data.
141
Nick Kledzik2458bec2014-07-16 19:49:02 +0000142 // Kinds found in mach-o .o files:
143 branch32, /// ex: call _foo
144 branch16, /// ex: callw _foo
145 abs32, /// ex: movl _foo, %eax
146 funcRel32, /// ex: movl _foo-L1(%eax), %eax
147 pointer32, /// ex: .long _foo
148 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000149 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000150
151 // Kinds introduced by Passes:
152 lazyPointer, /// Location contains a lazy pointer.
153 lazyImmediateLocation, /// Location contains immediate value used in stub.
154 };
155
Nick Kledzik2d432352014-07-17 23:16:21 +0000156 static bool useExternalRelocationTo(const Atom &target);
157
158 void applyFixupFinal(const Reference &ref, uint8_t *location,
159 uint64_t fixupAddress, uint64_t targetAddress,
160 uint64_t inAtomAddress);
161
162 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
163 uint64_t fixupAddress,
164 uint64_t targetAddress,
165 uint64_t inAtomAddress);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000166};
167
168//===----------------------------------------------------------------------===//
169// ArchHandler_x86
170//===----------------------------------------------------------------------===//
171
Tim Northover40d3ad32014-10-27 22:48:35 +0000172ArchHandler_x86::ArchHandler_x86() {}
Nick Kledzik2458bec2014-07-16 19:49:02 +0000173
174ArchHandler_x86::~ArchHandler_x86() { }
175
176const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
177 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000178 LLD_KIND_STRING_ENTRY(modeCode),
179 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000180 LLD_KIND_STRING_ENTRY(branch32),
181 LLD_KIND_STRING_ENTRY(branch16),
182 LLD_KIND_STRING_ENTRY(abs32),
183 LLD_KIND_STRING_ENTRY(funcRel32),
184 LLD_KIND_STRING_ENTRY(pointer32),
185 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000186 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000187 LLD_KIND_STRING_ENTRY(lazyPointer),
188 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
189 LLD_KIND_STRING_END
190};
191
192const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
193 "dyld_stub_binder",
194
195 // Lazy pointer references
196 { Reference::KindArch::x86, pointer32, 0, 0 },
197 { Reference::KindArch::x86, lazyPointer, 0, 0 },
198
199 // GOT pointer to dyld_stub_binder
200 { Reference::KindArch::x86, pointer32, 0, 0 },
201
202 // x86 code alignment
203 1,
204
205 // Stub size and code
206 6,
207 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
208 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000209 { false, 0, 0, 0 },
Nick Kledzik2458bec2014-07-16 19:49:02 +0000210
211 // Stub Helper size and code
212 10,
213 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
214 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
215 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
216 { Reference::KindArch::x86, branch32, 6, 0 },
217
218 // Stub Helper-Common size and code
219 12,
220 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
221 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
222 0x90 }, // nop
223 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000224 { false, 0, 0, 0 },
225 { Reference::KindArch::x86, abs32, 7, 0 },
226 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000227};
228
229bool ArchHandler_x86::isCallSite(const Reference &ref) {
230 return (ref.kindValue() == branch32);
231}
232
233bool ArchHandler_x86::isPointer(const Reference &ref) {
234 return (ref.kindValue() == pointer32);
235}
236
237bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
238 if (!reloc.scattered)
239 return false;
240 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
241 (reloc.type == GENERIC_RELOC_SECTDIFF);
242}
243
244std::error_code
245ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
246 const DefinedAtom *inAtom,
247 uint32_t offsetInAtom,
248 uint64_t fixupAddress, bool swap,
249 FindAtomBySectionAndAddress atomFromAddress,
250 FindAtomBySymbolIndex atomFromSymbolIndex,
251 Reference::KindValue *kind,
252 const lld::Atom **target,
253 Reference::Addend *addend) {
254 typedef std::error_code E;
255 DefinedAtom::ContentPermissions perms;
256 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
257 uint64_t targetAddress;
258 switch (relocPattern(reloc)) {
259 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
260 // ex: call _foo (and _foo undefined)
261 *kind = branch32;
262 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
263 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000264 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000265 break;
266 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
267 // ex: call _foo (and _foo defined)
268 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000269 targetAddress =
270 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000271 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
272 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000273 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
274 // ex: call _foo+n (and _foo defined)
275 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000276 targetAddress =
277 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000278 if (E ec = atomFromAddress(0, reloc.value, target, addend))
279 return ec;
280 *addend = targetAddress - reloc.value;
281 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000282 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
283 // ex: callw _foo (and _foo undefined)
284 *kind = branch16;
285 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
286 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000287 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000288 break;
289 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
290 // ex: callw _foo (and _foo defined)
291 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000292 targetAddress =
293 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000294 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
295 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000296 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
297 // ex: callw _foo+n (and _foo defined)
298 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000299 targetAddress =
300 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000301 if (E ec = atomFromAddress(0, reloc.value, target, addend))
302 return ec;
303 *addend = targetAddress - reloc.value;
304 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000305 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
306 // ex: movl _foo, %eax (and _foo undefined)
307 // ex: .long _foo (and _foo undefined)
308 perms = inAtom->permissions();
309 *kind =
310 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
311 : pointer32;
312 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
313 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000314 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000315 break;
316 case GENERIC_RELOC_VANILLA | rLength4:
317 // ex: movl _foo, %eax (and _foo defined)
318 // ex: .long _foo (and _foo defined)
319 perms = inAtom->permissions();
320 *kind =
321 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
322 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000323 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000324 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
325 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000326 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
327 // ex: .long _foo+n (and _foo defined)
328 perms = inAtom->permissions();
329 *kind =
330 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
331 : pointer32;
332 if (E ec = atomFromAddress(0, reloc.value, target, addend))
333 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000334 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000335 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000336 default:
337 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
338 }
339 return std::error_code();
340}
341
342std::error_code
343ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
344 const normalized::Relocation &reloc2,
345 const DefinedAtom *inAtom,
346 uint32_t offsetInAtom,
347 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000348 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000349 FindAtomBySectionAndAddress atomFromAddr,
350 FindAtomBySymbolIndex atomFromSymbolIndex,
351 Reference::KindValue *kind,
352 const lld::Atom **target,
353 Reference::Addend *addend) {
354 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
355 std::error_code ec;
356 DefinedAtom::ContentPermissions perms = inAtom->permissions();
357 uint32_t fromAddress;
358 uint32_t toAddress;
359 uint32_t value;
360 const lld::Atom *fromTarget;
361 Reference::Addend offsetInTo;
362 Reference::Addend offsetInFrom;
363 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000364 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
365 GENERIC_RELOC_PAIR | rScattered | rLength4):
366 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
367 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000368 toAddress = reloc1.value;
369 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000370 value = *(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000371 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
372 if (ec)
373 return ec;
374 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
375 if (ec)
376 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000377 if (fromTarget != inAtom) {
378 if (*target != inAtom)
379 return make_dynamic_error_code(Twine("SECTDIFF relocation where "
380 "neither target is in atom"));
381 *kind = negDelta32;
382 *addend = toAddress - value - fromAddress;
383 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000384 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000385 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
386 // SECTDIFF relocations are used in i386 codegen where the function
387 // prolog does a CALL to the next instruction which POPs the return
388 // address into EBX which becomes the pic-base register. The POP
389 // instruction is label the used for the subtrahend in expressions.
390 // The funcRel32 kind represents the 32-bit delta to some symbol from
391 // the start of the function (atom) containing the funcRel32.
392 *kind = funcRel32;
393 uint32_t ta = fromAddress + value - toAddress;
394 *addend = ta - offsetInFrom;
395 } else {
396 *kind = delta32;
397 *addend = fromAddress + value - toAddress;
398 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000399 }
400 return std::error_code();
401 break;
402 default:
403 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
404 }
405}
406
Nick Kledzik2d432352014-07-17 23:16:21 +0000407void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000408 bool relocatable,
409 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000410 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000411 uint64_t imageBaseAddress,
412 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000413 // Copy raw bytes.
414 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
415 // Apply fix-ups.
416 for (const Reference *ref : atom) {
417 uint32_t offset = ref->offsetInAtom();
418 const Atom *target = ref->target();
419 uint64_t targetAddress = 0;
420 if (isa<DefinedAtom>(target))
421 targetAddress = findAddress(*target);
422 uint64_t atomAddress = findAddress(atom);
423 uint64_t fixupAddress = atomAddress + offset;
424 if (relocatable) {
425 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
426 fixupAddress, targetAddress,
427 atomAddress);
428 } else {
429 applyFixupFinal(*ref, &atomContentBuffer[offset],
430 fixupAddress, targetAddress,
431 atomAddress);
432 }
433 }
434}
435
Tim Northover40d3ad32014-10-27 22:48:35 +0000436void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000437 uint64_t fixupAddress,
438 uint64_t targetAddress,
439 uint64_t inAtomAddress) {
440 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000441 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000442 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000443 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000444 switch (ref.kindValue()) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000445 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000446 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000447 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000448 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000449 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000450 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000451 case pointer32:
452 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000453 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000454 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000455 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000456 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000457 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000458 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000459 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000460 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000461 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000462 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000463 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000464 case modeCode:
465 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000466 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000467 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000468 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000469 case lazyImmediateLocation:
470 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000471 break;
472 default:
473 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000474 break;
475 }
476}
477
Nick Kledzik2d432352014-07-17 23:16:21 +0000478void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000479 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000480 uint64_t fixupAddress,
481 uint64_t targetAddress,
482 uint64_t inAtomAddress) {
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000483 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000484 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
485 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000486 switch (ref.kindValue()) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000487 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000488 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000489 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000490 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000491 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000492 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000493 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000494 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000495 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000496 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000497 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000498 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000499 case pointer32:
500 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000501 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000502 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000503 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000504 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000505 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000506 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000507 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000508 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000509 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000510 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000511 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000512 case modeCode:
513 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000514 case lazyPointer:
515 case lazyImmediateLocation:
516 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000517 break;
518 default:
519 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000520 break;
521 }
522}
523
524bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
525 // Undefined symbols are referenced via external relocations.
526 if (isa<UndefinedAtom>(&target))
527 return true;
528 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
529 switch (defAtom->merge()) {
530 case DefinedAtom::mergeAsTentative:
531 // Tentative definitions are referenced via external relocations.
532 return true;
533 case DefinedAtom::mergeAsWeak:
534 case DefinedAtom::mergeAsWeakAndAddressUsed:
535 // Global weak-defs are referenced via external relocations.
536 return (defAtom->scope() == DefinedAtom::scopeGlobal);
537 default:
538 break;
539 }
540 }
541 // Everything else is reference via an internal relocation.
542 return false;
543}
544
545
546void ArchHandler_x86::appendSectionRelocations(
547 const DefinedAtom &atom,
548 uint64_t atomSectionOffset,
549 const Reference &ref,
550 FindSymbolIndexForAtom symbolIndexForAtom,
551 FindSectionIndexForAtom sectionIndexForAtom,
552 FindAddressForAtom addressForAtom,
553 normalized::Relocations &relocs) {
554 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
555 return;
556 assert(ref.kindArch() == Reference::KindArch::x86);
557 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
558 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000559 switch (ref.kindValue()) {
Nick Kledzik21921372014-07-24 23:06:56 +0000560 case modeCode:
561 case modeData:
562 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000563 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000564 if (useExternalReloc) {
565 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
566 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
567 } else {
568 if (ref.addend() != 0)
569 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
570 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
571 else
572 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
573 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
574 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000575 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000576 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000577 if (useExternalReloc) {
578 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
579 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
580 } else {
581 if (ref.addend() != 0)
582 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
583 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
584 else
585 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
586 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
587 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000588 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000589 case pointer32:
590 case abs32:
591 if (useExternalReloc)
592 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000593 GENERIC_RELOC_VANILLA | rExtern | rLength4);
594 else {
595 if (ref.addend() != 0)
596 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
597 GENERIC_RELOC_VANILLA | rScattered | rLength4);
598 else
599 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000600 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000601 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000602 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000603 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000604 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
605 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
606 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
607 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000608 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000609 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000610 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
611 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
612 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
613 ref.offsetInAtom(),
614 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000615 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000616 case negDelta32:
617 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
618 ref.offsetInAtom(),
619 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
620 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
621 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000622 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000623 case lazyPointer:
624 case lazyImmediateLocation:
625 llvm_unreachable("lazy reference kind implies Stubs pass was run");
626 break;
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000627 default:
628 llvm_unreachable("unknown x86 Reference Kind");
629 break;
630
Nick Kledzik2d432352014-07-17 23:16:21 +0000631 }
632}
633
634
Nick Kledzik2458bec2014-07-16 19:49:02 +0000635std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
636 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
637}
638
639} // namespace mach_o
640} // namespace lld