blob: 0fba555e3e641565eadb3217e312dbad4b252487 [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
Tim Northover995abe32014-10-15 20:26:24 +000061 Reference::KindValue unwindRefToCIEKind() override {
62 return negDelta32;
63 }
64
Tim Northovera6a6ab92014-10-15 18:19:31 +000065 Reference::KindValue unwindRefToFunctionKind() override{
66 return delta32;
67 }
68
Tim Northover1cc4fb72014-10-15 19:32:21 +000069 Reference::KindValue unwindRefToEhFrameKind() override {
70 return invalid;
71 }
72
Pete Cooper1a6098b2016-02-02 00:02:50 +000073 Reference::KindValue pointerKind() override {
74 return invalid;
75 }
76
Tim Northover1cc4fb72014-10-15 19:32:21 +000077 uint32_t dwarfCompactUnwindType() override {
78 return 0x04000000U;
79 }
80
Nick Kledzik2458bec2014-07-16 19:49:02 +000081 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
82 const DefinedAtom *inAtom,
83 uint32_t offsetInAtom,
84 uint64_t fixupAddress, bool swap,
85 FindAtomBySectionAndAddress atomFromAddress,
86 FindAtomBySymbolIndex atomFromSymbolIndex,
87 Reference::KindValue *kind,
88 const lld::Atom **target,
89 Reference::Addend *addend) override;
90 std::error_code
91 getPairReferenceInfo(const normalized::Relocation &reloc1,
92 const normalized::Relocation &reloc2,
93 const DefinedAtom *inAtom,
94 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +000095 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +000096 FindAtomBySectionAndAddress atomFromAddress,
97 FindAtomBySymbolIndex atomFromSymbolIndex,
98 Reference::KindValue *kind,
99 const lld::Atom **target,
100 Reference::Addend *addend) override;
101
Nick Kledzik2d432352014-07-17 23:16:21 +0000102 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
103 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000104 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000105 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +0000106 uint8_t *atomContentBuffer) override;
107
108 void appendSectionRelocations(const DefinedAtom &atom,
109 uint64_t atomSectionOffset,
110 const Reference &ref,
111 FindSymbolIndexForAtom symbolIndexForAtom,
112 FindSectionIndexForAtom sectionIndexForAtom,
113 FindAddressForAtom addressForAtom,
114 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000115
Nick Kledzik21921372014-07-24 23:06:56 +0000116 bool isDataInCodeTransition(Reference::KindValue refKind) override {
117 switch (refKind) {
118 case modeCode:
119 case modeData:
120 return true;
121 default:
122 return false;
123 break;
124 }
125 }
126
127 Reference::KindValue dataInCodeTransitionStart(
128 const MachODefinedAtom &atom) override {
129 return modeData;
130 }
131
132 Reference::KindValue dataInCodeTransitionEnd(
133 const MachODefinedAtom &atom) override {
134 return modeCode;
135 }
136
Nick Kledzik2458bec2014-07-16 19:49:02 +0000137private:
138 static const Registry::KindStrings _sKindStrings[];
139 static const StubInfo _sStubInfo;
140
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000141 enum X86Kind : Reference::KindValue {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000142 invalid, /// for error condition
143
Nick Kledzik21921372014-07-24 23:06:56 +0000144 modeCode, /// Content starting at this offset is code.
145 modeData, /// Content starting at this offset is data.
146
Nick Kledzik2458bec2014-07-16 19:49:02 +0000147 // Kinds found in mach-o .o files:
148 branch32, /// ex: call _foo
149 branch16, /// ex: callw _foo
150 abs32, /// ex: movl _foo, %eax
151 funcRel32, /// ex: movl _foo-L1(%eax), %eax
152 pointer32, /// ex: .long _foo
153 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000154 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000155
156 // Kinds introduced by Passes:
157 lazyPointer, /// Location contains a lazy pointer.
158 lazyImmediateLocation, /// Location contains immediate value used in stub.
159 };
Shankar Easwarana1d36372015-02-22 23:54:38 +0000160
Nick Kledzik2d432352014-07-17 23:16:21 +0000161 static bool useExternalRelocationTo(const Atom &target);
162
163 void applyFixupFinal(const Reference &ref, uint8_t *location,
164 uint64_t fixupAddress, uint64_t targetAddress,
165 uint64_t inAtomAddress);
166
167 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
168 uint64_t fixupAddress,
169 uint64_t targetAddress,
170 uint64_t inAtomAddress);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000171};
172
173//===----------------------------------------------------------------------===//
174// ArchHandler_x86
175//===----------------------------------------------------------------------===//
176
Nick Kledzik2458bec2014-07-16 19:49:02 +0000177const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
178 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000179 LLD_KIND_STRING_ENTRY(modeCode),
180 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000181 LLD_KIND_STRING_ENTRY(branch32),
182 LLD_KIND_STRING_ENTRY(branch16),
183 LLD_KIND_STRING_ENTRY(abs32),
184 LLD_KIND_STRING_ENTRY(funcRel32),
185 LLD_KIND_STRING_ENTRY(pointer32),
186 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000187 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000188 LLD_KIND_STRING_ENTRY(lazyPointer),
189 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
190 LLD_KIND_STRING_END
191};
192
193const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
194 "dyld_stub_binder",
195
Shankar Easwarana1d36372015-02-22 23:54:38 +0000196 // Lazy pointer references
Nick Kledzik2458bec2014-07-16 19:49:02 +0000197 { Reference::KindArch::x86, pointer32, 0, 0 },
198 { Reference::KindArch::x86, lazyPointer, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000199
Nick Kledzik2458bec2014-07-16 19:49:02 +0000200 // GOT pointer to dyld_stub_binder
201 { Reference::KindArch::x86, pointer32, 0, 0 },
202
203 // x86 code alignment
Shankar Easwarana1d36372015-02-22 23:54:38 +0000204 1,
205
Nick Kledzik2458bec2014-07-16 19:49:02 +0000206 // Stub size and code
Shankar Easwarana1d36372015-02-22 23:54:38 +0000207 6,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000208 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
209 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000210 { false, 0, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000211
Nick Kledzik2458bec2014-07-16 19:49:02 +0000212 // Stub Helper size and code
213 10,
214 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
215 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
216 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
217 { Reference::KindArch::x86, branch32, 6, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000218
Nick Kledzik2458bec2014-07-16 19:49:02 +0000219 // Stub Helper-Common size and code
220 12,
221 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
222 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
223 0x90 }, // nop
224 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000225 { false, 0, 0, 0 },
226 { Reference::KindArch::x86, abs32, 7, 0 },
227 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000228};
229
230bool ArchHandler_x86::isCallSite(const Reference &ref) {
231 return (ref.kindValue() == branch32);
232}
233
234bool ArchHandler_x86::isPointer(const Reference &ref) {
235 return (ref.kindValue() == pointer32);
236}
237
238bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
239 if (!reloc.scattered)
240 return false;
241 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
242 (reloc.type == GENERIC_RELOC_SECTDIFF);
243}
244
245std::error_code
246ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
247 const DefinedAtom *inAtom,
248 uint32_t offsetInAtom,
249 uint64_t fixupAddress, bool swap,
250 FindAtomBySectionAndAddress atomFromAddress,
251 FindAtomBySymbolIndex atomFromSymbolIndex,
252 Reference::KindValue *kind,
253 const lld::Atom **target,
254 Reference::Addend *addend) {
255 typedef std::error_code E;
256 DefinedAtom::ContentPermissions perms;
257 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
258 uint64_t targetAddress;
259 switch (relocPattern(reloc)) {
260 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
261 // ex: call _foo (and _foo undefined)
262 *kind = branch32;
263 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
264 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000265 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000266 break;
267 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
268 // ex: call _foo (and _foo defined)
269 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000270 targetAddress =
271 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000272 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
273 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000274 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
275 // ex: call _foo+n (and _foo defined)
276 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000277 targetAddress =
278 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000279 if (E ec = atomFromAddress(0, reloc.value, target, addend))
280 return ec;
281 *addend = targetAddress - reloc.value;
282 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000283 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
284 // ex: callw _foo (and _foo undefined)
285 *kind = branch16;
286 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
287 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000288 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000289 break;
290 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
291 // ex: callw _foo (and _foo defined)
292 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000293 targetAddress =
294 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000295 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
296 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000297 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
298 // ex: callw _foo+n (and _foo defined)
299 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000300 targetAddress =
301 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000302 if (E ec = atomFromAddress(0, reloc.value, target, addend))
303 return ec;
304 *addend = targetAddress - reloc.value;
305 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000306 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
307 // ex: movl _foo, %eax (and _foo undefined)
308 // ex: .long _foo (and _foo undefined)
309 perms = inAtom->permissions();
310 *kind =
311 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
312 : pointer32;
313 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
314 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000315 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000316 break;
317 case GENERIC_RELOC_VANILLA | rLength4:
318 // ex: movl _foo, %eax (and _foo defined)
319 // ex: .long _foo (and _foo defined)
320 perms = inAtom->permissions();
321 *kind =
322 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
323 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000324 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000325 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
326 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000327 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
328 // ex: .long _foo+n (and _foo defined)
329 perms = inAtom->permissions();
330 *kind =
331 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
332 : pointer32;
333 if (E ec = atomFromAddress(0, reloc.value, target, addend))
334 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000335 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000336 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000337 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000338 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000339 }
340 return std::error_code();
341}
342
343std::error_code
344ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
345 const normalized::Relocation &reloc2,
346 const DefinedAtom *inAtom,
347 uint32_t offsetInAtom,
348 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000349 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000350 FindAtomBySectionAndAddress atomFromAddr,
351 FindAtomBySymbolIndex atomFromSymbolIndex,
352 Reference::KindValue *kind,
353 const lld::Atom **target,
354 Reference::Addend *addend) {
355 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
356 std::error_code ec;
357 DefinedAtom::ContentPermissions perms = inAtom->permissions();
358 uint32_t fromAddress;
359 uint32_t toAddress;
360 uint32_t value;
361 const lld::Atom *fromTarget;
362 Reference::Addend offsetInTo;
363 Reference::Addend offsetInFrom;
364 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000365 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
366 GENERIC_RELOC_PAIR | rScattered | rLength4):
367 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
368 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000369 toAddress = reloc1.value;
370 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000371 value = *(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000372 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
373 if (ec)
374 return ec;
375 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
376 if (ec)
377 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000378 if (fromTarget != inAtom) {
Shankar Easwarana1d36372015-02-22 23:54:38 +0000379 if (*target != inAtom)
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000380 return make_dynamic_error_code(
381 "SECTDIFF relocation where neither target is in atom");
Nick Kledzik03e16f22014-07-21 22:06:57 +0000382 *kind = negDelta32;
383 *addend = toAddress - value - fromAddress;
384 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000385 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000386 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
387 // SECTDIFF relocations are used in i386 codegen where the function
388 // prolog does a CALL to the next instruction which POPs the return
389 // address into EBX which becomes the pic-base register. The POP
390 // instruction is label the used for the subtrahend in expressions.
391 // The funcRel32 kind represents the 32-bit delta to some symbol from
392 // the start of the function (atom) containing the funcRel32.
393 *kind = funcRel32;
394 uint32_t ta = fromAddress + value - toAddress;
395 *addend = ta - offsetInFrom;
396 } else {
397 *kind = delta32;
398 *addend = fromAddress + value - toAddress;
399 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000400 }
401 return std::error_code();
402 break;
403 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000404 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000405 }
406}
407
Nick Kledzik2d432352014-07-17 23:16:21 +0000408void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000409 bool relocatable,
410 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000411 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000412 uint64_t imageBaseAddress,
413 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000414 // Copy raw bytes.
415 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
416 // Apply fix-ups.
417 for (const Reference *ref : atom) {
418 uint32_t offset = ref->offsetInAtom();
419 const Atom *target = ref->target();
420 uint64_t targetAddress = 0;
421 if (isa<DefinedAtom>(target))
422 targetAddress = findAddress(*target);
423 uint64_t atomAddress = findAddress(atom);
424 uint64_t fixupAddress = atomAddress + offset;
425 if (relocatable) {
426 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
427 fixupAddress, targetAddress,
428 atomAddress);
429 } else {
430 applyFixupFinal(*ref, &atomContentBuffer[offset],
431 fixupAddress, targetAddress,
432 atomAddress);
433 }
434 }
435}
436
Tim Northover40d3ad32014-10-27 22:48:35 +0000437void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000438 uint64_t fixupAddress,
439 uint64_t targetAddress,
440 uint64_t inAtomAddress) {
441 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000442 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000443 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000444 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000445 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000446 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000447 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000448 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000449 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000450 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000451 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000452 case pointer32:
453 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000454 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000455 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000456 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000457 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000458 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000459 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000460 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000461 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000462 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000463 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000464 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000465 case modeCode:
466 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000467 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000468 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000469 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000470 case lazyImmediateLocation:
471 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000472 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000473 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000474 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000475 break;
476 }
477}
478
Nick Kledzik2d432352014-07-17 23:16:21 +0000479void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000480 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000481 uint64_t fixupAddress,
482 uint64_t targetAddress,
483 uint64_t inAtomAddress) {
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000484 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
485 return;
486 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000487 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000488 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
489 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000490 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000491 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000492 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000493 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000494 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000495 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000496 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000497 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000498 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000499 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000500 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000501 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000502 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000503 case pointer32:
504 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000505 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000506 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000507 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000508 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000509 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000510 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000511 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000512 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000513 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000514 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000515 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000516 case modeCode:
517 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000518 case lazyPointer:
519 case lazyImmediateLocation:
520 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000521 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000522 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000523 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000524 break;
525 }
526}
527
528bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
529 // Undefined symbols are referenced via external relocations.
530 if (isa<UndefinedAtom>(&target))
531 return true;
532 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
533 switch (defAtom->merge()) {
534 case DefinedAtom::mergeAsTentative:
535 // Tentative definitions are referenced via external relocations.
536 return true;
537 case DefinedAtom::mergeAsWeak:
538 case DefinedAtom::mergeAsWeakAndAddressUsed:
539 // Global weak-defs are referenced via external relocations.
540 return (defAtom->scope() == DefinedAtom::scopeGlobal);
541 default:
542 break;
543 }
544 }
545 // Everything else is reference via an internal relocation.
546 return false;
547}
548
Nick Kledzik2d432352014-07-17 23:16:21 +0000549void ArchHandler_x86::appendSectionRelocations(
550 const DefinedAtom &atom,
551 uint64_t atomSectionOffset,
552 const Reference &ref,
553 FindSymbolIndexForAtom symbolIndexForAtom,
554 FindSectionIndexForAtom sectionIndexForAtom,
555 FindAddressForAtom addressForAtom,
556 normalized::Relocations &relocs) {
557 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
558 return;
559 assert(ref.kindArch() == Reference::KindArch::x86);
560 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
561 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000562 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik21921372014-07-24 23:06:56 +0000563 case modeCode:
564 case modeData:
565 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000566 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000567 if (useExternalReloc) {
568 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
569 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
570 } else {
571 if (ref.addend() != 0)
572 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
573 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
574 else
575 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
576 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
577 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000578 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000579 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000580 if (useExternalReloc) {
581 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
582 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
583 } else {
584 if (ref.addend() != 0)
585 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
586 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
587 else
588 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
589 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
590 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000591 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000592 case pointer32:
593 case abs32:
594 if (useExternalReloc)
595 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000596 GENERIC_RELOC_VANILLA | rExtern | rLength4);
597 else {
598 if (ref.addend() != 0)
599 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
600 GENERIC_RELOC_VANILLA | rScattered | rLength4);
601 else
602 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000603 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000604 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000605 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000606 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000607 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
608 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
609 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
610 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000611 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000612 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000613 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
614 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
615 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
616 ref.offsetInAtom(),
617 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000618 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000619 case negDelta32:
620 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
621 ref.offsetInAtom(),
622 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
623 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
624 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000625 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000626 case lazyPointer:
627 case lazyImmediateLocation:
628 llvm_unreachable("lazy reference kind implies Stubs pass was run");
629 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000630 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000631 llvm_unreachable("unknown x86 Reference Kind");
632 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000633 }
634}
635
Nick Kledzik2458bec2014-07-16 19:49:02 +0000636std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
637 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
638}
639
640} // namespace mach_o
641} // namespace lld