blob: a2c68092724de71af832138a9b8f7cfb30cdb516 [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
Rui Ueyamaea65b5a2017-08-24 23:51:40 +000073 Reference::KindValue lazyImmediateLocationKind() override {
74 return lazyImmediateLocation;
75 }
76
Tim Northover1cc4fb72014-10-15 19:32:21 +000077 Reference::KindValue unwindRefToEhFrameKind() override {
78 return invalid;
79 }
80
Pete Cooper1a6098b2016-02-02 00:02:50 +000081 Reference::KindValue pointerKind() override {
82 return invalid;
83 }
84
Tim Northover1cc4fb72014-10-15 19:32:21 +000085 uint32_t dwarfCompactUnwindType() override {
86 return 0x04000000U;
87 }
88
Pete Cooper1e009112016-03-30 20:15:06 +000089 llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
90 const DefinedAtom *inAtom,
91 uint32_t offsetInAtom,
92 uint64_t fixupAddress, bool swap,
93 FindAtomBySectionAndAddress atomFromAddress,
94 FindAtomBySymbolIndex atomFromSymbolIndex,
95 Reference::KindValue *kind,
96 const lld::Atom **target,
97 Reference::Addend *addend) override;
98 llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +000099 getPairReferenceInfo(const normalized::Relocation &reloc1,
100 const normalized::Relocation &reloc2,
101 const DefinedAtom *inAtom,
102 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000103 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000104 FindAtomBySectionAndAddress atomFromAddress,
105 FindAtomBySymbolIndex atomFromSymbolIndex,
106 Reference::KindValue *kind,
107 const lld::Atom **target,
108 Reference::Addend *addend) override;
109
Nick Kledzik2d432352014-07-17 23:16:21 +0000110 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
111 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000112 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000113 uint64_t imageBaseAddress,
Pete Cooper47e53992016-03-23 22:19:16 +0000114 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
Nick Kledzik2d432352014-07-17 23:16:21 +0000115
116 void appendSectionRelocations(const DefinedAtom &atom,
117 uint64_t atomSectionOffset,
118 const Reference &ref,
119 FindSymbolIndexForAtom symbolIndexForAtom,
120 FindSectionIndexForAtom sectionIndexForAtom,
121 FindAddressForAtom addressForAtom,
122 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000123
Nick Kledzik21921372014-07-24 23:06:56 +0000124 bool isDataInCodeTransition(Reference::KindValue refKind) override {
Davide Italiano0eb80302017-04-15 01:50:51 +0000125 return refKind == modeCode || refKind == modeData;
Nick Kledzik21921372014-07-24 23:06:56 +0000126 }
127
128 Reference::KindValue dataInCodeTransitionStart(
129 const MachODefinedAtom &atom) override {
130 return modeData;
131 }
132
133 Reference::KindValue dataInCodeTransitionEnd(
134 const MachODefinedAtom &atom) override {
135 return modeCode;
136 }
137
Nick Kledzik2458bec2014-07-16 19:49:02 +0000138private:
139 static const Registry::KindStrings _sKindStrings[];
140 static const StubInfo _sStubInfo;
141
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000142 enum X86Kind : Reference::KindValue {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000143 invalid, /// for error condition
144
Nick Kledzik21921372014-07-24 23:06:56 +0000145 modeCode, /// Content starting at this offset is code.
146 modeData, /// Content starting at this offset is data.
147
Nick Kledzik2458bec2014-07-16 19:49:02 +0000148 // Kinds found in mach-o .o files:
149 branch32, /// ex: call _foo
150 branch16, /// ex: callw _foo
151 abs32, /// ex: movl _foo, %eax
152 funcRel32, /// ex: movl _foo-L1(%eax), %eax
153 pointer32, /// ex: .long _foo
154 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000155 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000156
157 // Kinds introduced by Passes:
158 lazyPointer, /// Location contains a lazy pointer.
159 lazyImmediateLocation, /// Location contains immediate value used in stub.
160 };
Shankar Easwarana1d36372015-02-22 23:54:38 +0000161
Nick Kledzik2d432352014-07-17 23:16:21 +0000162 static bool useExternalRelocationTo(const Atom &target);
163
164 void applyFixupFinal(const Reference &ref, uint8_t *location,
165 uint64_t fixupAddress, uint64_t targetAddress,
166 uint64_t inAtomAddress);
167
168 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
169 uint64_t fixupAddress,
170 uint64_t targetAddress,
171 uint64_t inAtomAddress);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000172};
173
174//===----------------------------------------------------------------------===//
175// ArchHandler_x86
176//===----------------------------------------------------------------------===//
177
Nick Kledzik2458bec2014-07-16 19:49:02 +0000178const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
179 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000180 LLD_KIND_STRING_ENTRY(modeCode),
181 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000182 LLD_KIND_STRING_ENTRY(branch32),
183 LLD_KIND_STRING_ENTRY(branch16),
184 LLD_KIND_STRING_ENTRY(abs32),
185 LLD_KIND_STRING_ENTRY(funcRel32),
186 LLD_KIND_STRING_ENTRY(pointer32),
187 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000188 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000189 LLD_KIND_STRING_ENTRY(lazyPointer),
190 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
191 LLD_KIND_STRING_END
192};
193
194const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
195 "dyld_stub_binder",
196
Shankar Easwarana1d36372015-02-22 23:54:38 +0000197 // Lazy pointer references
Nick Kledzik2458bec2014-07-16 19:49:02 +0000198 { Reference::KindArch::x86, pointer32, 0, 0 },
199 { Reference::KindArch::x86, lazyPointer, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000200
Nick Kledzik2458bec2014-07-16 19:49:02 +0000201 // GOT pointer to dyld_stub_binder
202 { Reference::KindArch::x86, pointer32, 0, 0 },
203
204 // x86 code alignment
Shankar Easwarana1d36372015-02-22 23:54:38 +0000205 1,
206
Nick Kledzik2458bec2014-07-16 19:49:02 +0000207 // Stub size and code
Shankar Easwarana1d36372015-02-22 23:54:38 +0000208 6,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000209 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
210 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000211 { false, 0, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000212
Nick Kledzik2458bec2014-07-16 19:49:02 +0000213 // Stub Helper size and code
214 10,
215 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
216 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
217 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
218 { Reference::KindArch::x86, branch32, 6, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000219
Pete Coopere8d9df42016-02-09 20:11:17 +0000220 // Stub helper image cache content type
221 DefinedAtom::typeNonLazyPointer,
222
Nick Kledzik2458bec2014-07-16 19:49:02 +0000223 // Stub Helper-Common size and code
224 12,
Pete Cooper35c33182016-02-09 18:56:37 +0000225 // Stub helper alignment
226 2,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000227 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
228 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
229 0x90 }, // nop
230 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000231 { false, 0, 0, 0 },
232 { Reference::KindArch::x86, abs32, 7, 0 },
233 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000234};
235
236bool ArchHandler_x86::isCallSite(const Reference &ref) {
237 return (ref.kindValue() == branch32);
238}
239
240bool ArchHandler_x86::isPointer(const Reference &ref) {
241 return (ref.kindValue() == pointer32);
242}
243
244bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
245 if (!reloc.scattered)
246 return false;
247 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
248 (reloc.type == GENERIC_RELOC_SECTDIFF);
249}
250
Pete Cooper1e009112016-03-30 20:15:06 +0000251llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +0000252ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
253 const DefinedAtom *inAtom,
254 uint32_t offsetInAtom,
255 uint64_t fixupAddress, bool swap,
256 FindAtomBySectionAndAddress atomFromAddress,
257 FindAtomBySymbolIndex atomFromSymbolIndex,
258 Reference::KindValue *kind,
259 const lld::Atom **target,
260 Reference::Addend *addend) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000261 DefinedAtom::ContentPermissions perms;
262 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
263 uint64_t targetAddress;
264 switch (relocPattern(reloc)) {
265 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
266 // ex: call _foo (and _foo undefined)
267 *kind = branch32;
Pete Cooper1e009112016-03-30 20:15:06 +0000268 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000269 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000270 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000271 break;
272 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
273 // ex: call _foo (and _foo defined)
274 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000275 targetAddress =
276 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000277 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
278 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000279 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
280 // ex: call _foo+n (and _foo defined)
281 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000282 targetAddress =
283 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000284 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000285 return ec;
286 *addend = targetAddress - reloc.value;
287 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000288 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
289 // ex: callw _foo (and _foo undefined)
290 *kind = branch16;
Pete Cooper1e009112016-03-30 20:15:06 +0000291 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000292 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000293 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000294 break;
295 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
296 // ex: callw _foo (and _foo defined)
297 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000298 targetAddress =
299 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000300 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
301 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000302 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
303 // ex: callw _foo+n (and _foo defined)
304 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000305 targetAddress =
306 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000307 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000308 return ec;
309 *addend = targetAddress - reloc.value;
310 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000311 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
312 // ex: movl _foo, %eax (and _foo undefined)
313 // ex: .long _foo (and _foo undefined)
314 perms = inAtom->permissions();
315 *kind =
316 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
317 : pointer32;
Pete Cooper1e009112016-03-30 20:15:06 +0000318 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000319 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000320 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000321 break;
322 case GENERIC_RELOC_VANILLA | rLength4:
323 // ex: movl _foo, %eax (and _foo defined)
324 // ex: .long _foo (and _foo defined)
325 perms = inAtom->permissions();
326 *kind =
327 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
328 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000329 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000330 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
331 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000332 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
333 // ex: .long _foo+n (and _foo defined)
334 perms = inAtom->permissions();
335 *kind =
336 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
337 : pointer32;
Pete Cooper1e009112016-03-30 20:15:06 +0000338 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik7e246a42014-07-18 01:05:35 +0000339 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000340 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000341 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000342 default:
Pete Cooper1e009112016-03-30 20:15:06 +0000343 return llvm::make_error<GenericError>("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000344 }
Mehdi Aminic1edf562016-11-11 04:29:25 +0000345 return llvm::Error::success();
Nick Kledzik2458bec2014-07-16 19:49:02 +0000346}
347
Pete Cooper1e009112016-03-30 20:15:06 +0000348llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +0000349ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
350 const normalized::Relocation &reloc2,
351 const DefinedAtom *inAtom,
352 uint32_t offsetInAtom,
353 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000354 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000355 FindAtomBySectionAndAddress atomFromAddr,
356 FindAtomBySymbolIndex atomFromSymbolIndex,
357 Reference::KindValue *kind,
358 const lld::Atom **target,
359 Reference::Addend *addend) {
360 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
Nick Kledzik2458bec2014-07-16 19:49:02 +0000361 DefinedAtom::ContentPermissions perms = inAtom->permissions();
362 uint32_t fromAddress;
363 uint32_t toAddress;
364 uint32_t value;
365 const lld::Atom *fromTarget;
366 Reference::Addend offsetInTo;
367 Reference::Addend offsetInFrom;
368 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000369 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
370 GENERIC_RELOC_PAIR | rScattered | rLength4):
371 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
372 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000373 toAddress = reloc1.value;
374 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000375 value = *(const little32_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000376 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000377 return ec;
Pete Cooper1e009112016-03-30 20:15:06 +0000378 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000379 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000380 if (fromTarget != inAtom) {
Shankar Easwarana1d36372015-02-22 23:54:38 +0000381 if (*target != inAtom)
Pete Cooper1e009112016-03-30 20:15:06 +0000382 return llvm::make_error<GenericError>(
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000383 "SECTDIFF relocation where neither target is in atom");
Nick Kledzik03e16f22014-07-21 22:06:57 +0000384 *kind = negDelta32;
385 *addend = toAddress - value - fromAddress;
386 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000387 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000388 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
389 // SECTDIFF relocations are used in i386 codegen where the function
390 // prolog does a CALL to the next instruction which POPs the return
391 // address into EBX which becomes the pic-base register. The POP
392 // instruction is label the used for the subtrahend in expressions.
393 // The funcRel32 kind represents the 32-bit delta to some symbol from
394 // the start of the function (atom) containing the funcRel32.
395 *kind = funcRel32;
396 uint32_t ta = fromAddress + value - toAddress;
397 *addend = ta - offsetInFrom;
398 } else {
399 *kind = delta32;
400 *addend = fromAddress + value - toAddress;
401 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000402 }
Mehdi Aminic1edf562016-11-11 04:29:25 +0000403 return llvm::Error::success();
Nick Kledzik2458bec2014-07-16 19:49:02 +0000404 break;
405 default:
Pete Cooper1e009112016-03-30 20:15:06 +0000406 return llvm::make_error<GenericError>("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000407 }
408}
409
Nick Kledzik2d432352014-07-17 23:16:21 +0000410void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000411 bool relocatable,
412 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000413 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000414 uint64_t imageBaseAddress,
Pete Cooper47e53992016-03-23 22:19:16 +0000415 llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000416 // Copy raw bytes.
Pete Cooper47e53992016-03-23 22:19:16 +0000417 std::copy(atom.rawContent().begin(), atom.rawContent().end(),
418 atomContentBuffer.begin());
Nick Kledzik2d432352014-07-17 23:16:21 +0000419 // Apply fix-ups.
420 for (const Reference *ref : atom) {
421 uint32_t offset = ref->offsetInAtom();
422 const Atom *target = ref->target();
423 uint64_t targetAddress = 0;
424 if (isa<DefinedAtom>(target))
425 targetAddress = findAddress(*target);
426 uint64_t atomAddress = findAddress(atom);
427 uint64_t fixupAddress = atomAddress + offset;
428 if (relocatable) {
429 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
430 fixupAddress, targetAddress,
431 atomAddress);
432 } else {
433 applyFixupFinal(*ref, &atomContentBuffer[offset],
434 fixupAddress, targetAddress,
435 atomAddress);
436 }
437 }
438}
439
Tim Northover40d3ad32014-10-27 22:48:35 +0000440void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000441 uint64_t fixupAddress,
442 uint64_t targetAddress,
443 uint64_t inAtomAddress) {
444 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000445 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000446 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000447 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000448 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000449 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000450 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000451 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000452 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000453 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000454 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000455 case pointer32:
456 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000457 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000458 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000459 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000460 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000461 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000462 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000463 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000464 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000465 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000466 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000467 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000468 case modeCode:
469 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000470 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000471 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000472 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000473 case lazyImmediateLocation:
474 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000475 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000476 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000477 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000478 break;
479 }
480}
481
Nick Kledzik2d432352014-07-17 23:16:21 +0000482void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000483 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000484 uint64_t fixupAddress,
485 uint64_t targetAddress,
486 uint64_t inAtomAddress) {
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000487 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
488 return;
489 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000490 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000491 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
492 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000493 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000494 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000495 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000496 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000497 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000498 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000499 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000500 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000501 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000502 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000503 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000504 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000505 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000506 case pointer32:
507 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000508 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000509 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000510 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000511 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000512 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000513 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000514 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000515 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000516 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000517 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000518 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000519 case modeCode:
520 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000521 case lazyPointer:
522 case lazyImmediateLocation:
523 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000524 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000525 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000526 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000527 break;
528 }
529}
530
531bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
532 // Undefined symbols are referenced via external relocations.
533 if (isa<UndefinedAtom>(&target))
534 return true;
535 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
536 switch (defAtom->merge()) {
537 case DefinedAtom::mergeAsTentative:
538 // Tentative definitions are referenced via external relocations.
539 return true;
540 case DefinedAtom::mergeAsWeak:
541 case DefinedAtom::mergeAsWeakAndAddressUsed:
542 // Global weak-defs are referenced via external relocations.
543 return (defAtom->scope() == DefinedAtom::scopeGlobal);
544 default:
545 break;
546 }
547 }
548 // Everything else is reference via an internal relocation.
549 return false;
550}
551
Nick Kledzik2d432352014-07-17 23:16:21 +0000552void ArchHandler_x86::appendSectionRelocations(
553 const DefinedAtom &atom,
554 uint64_t atomSectionOffset,
555 const Reference &ref,
556 FindSymbolIndexForAtom symbolIndexForAtom,
557 FindSectionIndexForAtom sectionIndexForAtom,
558 FindAddressForAtom addressForAtom,
559 normalized::Relocations &relocs) {
560 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
561 return;
562 assert(ref.kindArch() == Reference::KindArch::x86);
563 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
564 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000565 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik21921372014-07-24 23:06:56 +0000566 case modeCode:
567 case modeData:
568 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000569 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000570 if (useExternalReloc) {
571 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
572 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
573 } else {
574 if (ref.addend() != 0)
575 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
576 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
577 else
578 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
579 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
580 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000581 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000582 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000583 if (useExternalReloc) {
584 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
585 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
586 } else {
587 if (ref.addend() != 0)
588 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
589 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
590 else
591 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
592 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
593 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000594 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000595 case pointer32:
596 case abs32:
597 if (useExternalReloc)
598 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000599 GENERIC_RELOC_VANILLA | rExtern | rLength4);
600 else {
601 if (ref.addend() != 0)
602 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
603 GENERIC_RELOC_VANILLA | rScattered | rLength4);
604 else
605 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000606 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000607 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000608 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000609 case funcRel32:
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) - ref.addend(),
613 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000614 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000615 case delta32:
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) +
619 ref.offsetInAtom(),
620 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000621 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000622 case negDelta32:
623 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
624 ref.offsetInAtom(),
625 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
626 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
627 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000628 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000629 case lazyPointer:
630 case lazyImmediateLocation:
631 llvm_unreachable("lazy reference kind implies Stubs pass was run");
632 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000633 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000634 llvm_unreachable("unknown x86 Reference Kind");
635 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000636 }
637}
638
Nick Kledzik2458bec2014-07-16 19:49:02 +0000639std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
640 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
641}
642
643} // namespace mach_o
644} // namespace lld