blob: 6ea8e8c42e800dd8791d4cf80b3dcc1dcf1062f7 [file] [log] [blame]
Nick Kledzik2458bec2014-07-16 19:49:02 +00001//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Nick Kledzik2458bec2014-07-16 19:49:02 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "ArchHandler.h"
10#include "Atoms.h"
11#include "MachONormalizedFileBinaryUtils.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000012#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/StringSwitch.h"
14#include "llvm/ADT/Triple.h"
Tim Northover40d3ad32014-10-27 22:48:35 +000015#include "llvm/Support/Endian.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000016#include "llvm/Support/ErrorHandling.h"
17
18using namespace llvm::MachO;
19using namespace lld::mach_o::normalized;
20
21namespace lld {
22namespace mach_o {
23
Tim Northover40d3ad32014-10-27 22:48:35 +000024using llvm::support::ulittle16_t;
25using llvm::support::ulittle32_t;
26
27using llvm::support::little16_t;
28using llvm::support::little32_t;
29
Nick Kledzik2458bec2014-07-16 19:49:02 +000030class ArchHandler_x86 : public ArchHandler {
31public:
Rui Ueyama9071e4a2015-09-10 18:51:36 +000032 ArchHandler_x86() = default;
33 ~ArchHandler_x86() override = default;
Nick Kledzik2458bec2014-07-16 19:49:02 +000034
35 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
36
37 Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
38
39 const StubInfo &stubInfo() override { return _sStubInfo; }
40 bool isCallSite(const Reference &) override;
Nick Kledzik4121bce2014-10-14 01:51:42 +000041 bool isNonCallBranch(const Reference &) override {
42 return false;
43 }
44
Nick Kledzik2458bec2014-07-16 19:49:02 +000045 bool isPointer(const Reference &) override;
46 bool isPairedReloc(const normalized::Relocation &) override;
Tim Northovercf78d372014-09-30 21:29:54 +000047
48 bool needsCompactUnwind() override {
49 return false;
50 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000051
Tim Northovercf78d372014-09-30 21:29:54 +000052 Reference::KindValue imageOffsetKind() override {
53 return invalid;
54 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000055
Tim Northovercf78d372014-09-30 21:29:54 +000056 Reference::KindValue imageOffsetKindIndirect() override {
57 return invalid;
58 }
59
Pete Cooperebecd6c2016-03-15 21:33:10 +000060 Reference::KindValue unwindRefToPersonalityFunctionKind() override {
61 return invalid;
62 }
63
Tim Northover995abe32014-10-15 20:26:24 +000064 Reference::KindValue unwindRefToCIEKind() override {
65 return negDelta32;
66 }
67
Tim Northovera6a6ab92014-10-15 18:19:31 +000068 Reference::KindValue unwindRefToFunctionKind() override{
69 return delta32;
70 }
71
Rui Ueyamaea65b5a2017-08-24 23:51:40 +000072 Reference::KindValue lazyImmediateLocationKind() override {
73 return lazyImmediateLocation;
74 }
75
Tim Northover1cc4fb72014-10-15 19:32:21 +000076 Reference::KindValue unwindRefToEhFrameKind() override {
77 return invalid;
78 }
79
Pete Cooper1a6098b2016-02-02 00:02:50 +000080 Reference::KindValue pointerKind() override {
81 return invalid;
82 }
83
Tim Northover1cc4fb72014-10-15 19:32:21 +000084 uint32_t dwarfCompactUnwindType() override {
85 return 0x04000000U;
86 }
87
Pete Cooper1e009112016-03-30 20:15:06 +000088 llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
89 const DefinedAtom *inAtom,
90 uint32_t offsetInAtom,
91 uint64_t fixupAddress, bool swap,
92 FindAtomBySectionAndAddress atomFromAddress,
93 FindAtomBySymbolIndex atomFromSymbolIndex,
94 Reference::KindValue *kind,
95 const lld::Atom **target,
96 Reference::Addend *addend) override;
97 llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +000098 getPairReferenceInfo(const normalized::Relocation &reloc1,
99 const normalized::Relocation &reloc2,
100 const DefinedAtom *inAtom,
101 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000102 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000103 FindAtomBySectionAndAddress atomFromAddress,
104 FindAtomBySymbolIndex atomFromSymbolIndex,
105 Reference::KindValue *kind,
106 const lld::Atom **target,
107 Reference::Addend *addend) override;
108
Nick Kledzik2d432352014-07-17 23:16:21 +0000109 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
110 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000111 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000112 uint64_t imageBaseAddress,
Pete Cooper47e53992016-03-23 22:19:16 +0000113 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
Nick Kledzik2d432352014-07-17 23:16:21 +0000114
115 void appendSectionRelocations(const DefinedAtom &atom,
116 uint64_t atomSectionOffset,
117 const Reference &ref,
118 FindSymbolIndexForAtom symbolIndexForAtom,
119 FindSectionIndexForAtom sectionIndexForAtom,
120 FindAddressForAtom addressForAtom,
121 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000122
Nick Kledzik21921372014-07-24 23:06:56 +0000123 bool isDataInCodeTransition(Reference::KindValue refKind) override {
Davide Italiano0eb80302017-04-15 01:50:51 +0000124 return refKind == modeCode || refKind == modeData;
Nick Kledzik21921372014-07-24 23:06:56 +0000125 }
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
Pete Coopere8d9df42016-02-09 20:11:17 +0000219 // Stub helper image cache content type
220 DefinedAtom::typeNonLazyPointer,
221
Nick Kledzik2458bec2014-07-16 19:49:02 +0000222 // Stub Helper-Common size and code
223 12,
Pete Cooper35c33182016-02-09 18:56:37 +0000224 // Stub helper alignment
225 2,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000226 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
227 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
228 0x90 }, // nop
229 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000230 { false, 0, 0, 0 },
231 { Reference::KindArch::x86, abs32, 7, 0 },
232 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000233};
234
235bool ArchHandler_x86::isCallSite(const Reference &ref) {
236 return (ref.kindValue() == branch32);
237}
238
239bool ArchHandler_x86::isPointer(const Reference &ref) {
240 return (ref.kindValue() == pointer32);
241}
242
243bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
244 if (!reloc.scattered)
245 return false;
246 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
247 (reloc.type == GENERIC_RELOC_SECTDIFF);
248}
249
Pete Cooper1e009112016-03-30 20:15:06 +0000250llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +0000251ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
252 const DefinedAtom *inAtom,
253 uint32_t offsetInAtom,
254 uint64_t fixupAddress, bool swap,
255 FindAtomBySectionAndAddress atomFromAddress,
256 FindAtomBySymbolIndex atomFromSymbolIndex,
257 Reference::KindValue *kind,
258 const lld::Atom **target,
259 Reference::Addend *addend) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000260 DefinedAtom::ContentPermissions perms;
261 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
262 uint64_t targetAddress;
263 switch (relocPattern(reloc)) {
264 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
265 // ex: call _foo (and _foo undefined)
266 *kind = branch32;
Pete Cooper1e009112016-03-30 20:15:06 +0000267 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000268 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000269 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000270 break;
271 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
272 // ex: call _foo (and _foo defined)
273 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000274 targetAddress =
275 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000276 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
277 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000278 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
279 // ex: call _foo+n (and _foo defined)
280 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000281 targetAddress =
282 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000283 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000284 return ec;
285 *addend = targetAddress - reloc.value;
286 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000287 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
288 // ex: callw _foo (and _foo undefined)
289 *kind = branch16;
Pete Cooper1e009112016-03-30 20:15:06 +0000290 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000291 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000292 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000293 break;
294 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
295 // ex: callw _foo (and _foo defined)
296 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000297 targetAddress =
298 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000299 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
300 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000301 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
302 // ex: callw _foo+n (and _foo defined)
303 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000304 targetAddress =
305 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000306 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000307 return ec;
308 *addend = targetAddress - reloc.value;
309 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000310 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
311 // ex: movl _foo, %eax (and _foo undefined)
312 // ex: .long _foo (and _foo undefined)
313 perms = inAtom->permissions();
314 *kind =
315 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
316 : pointer32;
Pete Cooper1e009112016-03-30 20:15:06 +0000317 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000318 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000319 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000320 break;
321 case GENERIC_RELOC_VANILLA | rLength4:
322 // ex: movl _foo, %eax (and _foo defined)
323 // ex: .long _foo (and _foo defined)
324 perms = inAtom->permissions();
325 *kind =
326 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
327 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000328 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000329 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
330 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000331 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
332 // ex: .long _foo+n (and _foo defined)
333 perms = inAtom->permissions();
334 *kind =
335 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
336 : pointer32;
Pete Cooper1e009112016-03-30 20:15:06 +0000337 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
Nick Kledzik7e246a42014-07-18 01:05:35 +0000338 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000339 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000340 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000341 default:
Pete Cooper1e009112016-03-30 20:15:06 +0000342 return llvm::make_error<GenericError>("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000343 }
Mehdi Aminic1edf562016-11-11 04:29:25 +0000344 return llvm::Error::success();
Nick Kledzik2458bec2014-07-16 19:49:02 +0000345}
346
Pete Cooper1e009112016-03-30 20:15:06 +0000347llvm::Error
Nick Kledzik2458bec2014-07-16 19:49:02 +0000348ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
349 const normalized::Relocation &reloc2,
350 const DefinedAtom *inAtom,
351 uint32_t offsetInAtom,
352 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000353 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000354 FindAtomBySectionAndAddress atomFromAddr,
355 FindAtomBySymbolIndex atomFromSymbolIndex,
356 Reference::KindValue *kind,
357 const lld::Atom **target,
358 Reference::Addend *addend) {
359 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
Nick Kledzik2458bec2014-07-16 19:49:02 +0000360 DefinedAtom::ContentPermissions perms = inAtom->permissions();
361 uint32_t fromAddress;
362 uint32_t toAddress;
363 uint32_t value;
364 const lld::Atom *fromTarget;
365 Reference::Addend offsetInTo;
366 Reference::Addend offsetInFrom;
367 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000368 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
369 GENERIC_RELOC_PAIR | rScattered | rLength4):
370 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
371 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000372 toAddress = reloc1.value;
373 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000374 value = *(const little32_t *)fixupContent;
Pete Cooper1e009112016-03-30 20:15:06 +0000375 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000376 return ec;
Pete Cooper1e009112016-03-30 20:15:06 +0000377 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
Nick Kledzik2458bec2014-07-16 19:49:02 +0000378 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000379 if (fromTarget != inAtom) {
Shankar Easwarana1d36372015-02-22 23:54:38 +0000380 if (*target != inAtom)
Pete Cooper1e009112016-03-30 20:15:06 +0000381 return llvm::make_error<GenericError>(
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000382 "SECTDIFF relocation where neither target is in atom");
Nick Kledzik03e16f22014-07-21 22:06:57 +0000383 *kind = negDelta32;
384 *addend = toAddress - value - fromAddress;
385 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000386 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000387 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
388 // SECTDIFF relocations are used in i386 codegen where the function
389 // prolog does a CALL to the next instruction which POPs the return
390 // address into EBX which becomes the pic-base register. The POP
391 // instruction is label the used for the subtrahend in expressions.
392 // The funcRel32 kind represents the 32-bit delta to some symbol from
393 // the start of the function (atom) containing the funcRel32.
394 *kind = funcRel32;
395 uint32_t ta = fromAddress + value - toAddress;
396 *addend = ta - offsetInFrom;
397 } else {
398 *kind = delta32;
399 *addend = fromAddress + value - toAddress;
400 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000401 }
Mehdi Aminic1edf562016-11-11 04:29:25 +0000402 return llvm::Error::success();
Nick Kledzik2458bec2014-07-16 19:49:02 +0000403 break;
404 default:
Pete Cooper1e009112016-03-30 20:15:06 +0000405 return llvm::make_error<GenericError>("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000406 }
407}
408
Nick Kledzik2d432352014-07-17 23:16:21 +0000409void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000410 bool relocatable,
411 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000412 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000413 uint64_t imageBaseAddress,
Pete Cooper47e53992016-03-23 22:19:16 +0000414 llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000415 // Copy raw bytes.
Pete Cooper47e53992016-03-23 22:19:16 +0000416 std::copy(atom.rawContent().begin(), atom.rawContent().end(),
417 atomContentBuffer.begin());
Nick Kledzik2d432352014-07-17 23:16:21 +0000418 // Apply fix-ups.
419 for (const Reference *ref : atom) {
420 uint32_t offset = ref->offsetInAtom();
421 const Atom *target = ref->target();
422 uint64_t targetAddress = 0;
423 if (isa<DefinedAtom>(target))
424 targetAddress = findAddress(*target);
425 uint64_t atomAddress = findAddress(atom);
426 uint64_t fixupAddress = atomAddress + offset;
427 if (relocatable) {
428 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
429 fixupAddress, targetAddress,
430 atomAddress);
431 } else {
432 applyFixupFinal(*ref, &atomContentBuffer[offset],
433 fixupAddress, targetAddress,
434 atomAddress);
435 }
436 }
437}
438
Tim Northover40d3ad32014-10-27 22:48:35 +0000439void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000440 uint64_t fixupAddress,
441 uint64_t targetAddress,
442 uint64_t inAtomAddress) {
443 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000444 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000445 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000446 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000447 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000448 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000449 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000450 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000451 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000452 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000453 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000454 case pointer32:
455 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000456 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000457 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000458 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000459 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000460 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000461 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000462 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000463 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000464 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000465 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000466 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000467 case modeCode:
468 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000469 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000470 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000471 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000472 case lazyImmediateLocation:
473 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000474 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000475 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000476 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000477 break;
478 }
479}
480
Nick Kledzik2d432352014-07-17 23:16:21 +0000481void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000482 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000483 uint64_t fixupAddress,
484 uint64_t targetAddress,
485 uint64_t inAtomAddress) {
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000486 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
487 return;
488 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000489 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000490 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
491 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000492 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000493 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000494 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000495 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000496 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000497 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000498 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000499 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000500 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000501 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000502 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000503 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000504 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000505 case pointer32:
506 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000507 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000508 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000509 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000510 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000511 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000512 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000513 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000514 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000515 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000516 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000517 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000518 case modeCode:
519 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000520 case lazyPointer:
521 case lazyImmediateLocation:
522 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000523 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000524 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000525 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000526 break;
527 }
528}
529
530bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
531 // Undefined symbols are referenced via external relocations.
532 if (isa<UndefinedAtom>(&target))
533 return true;
534 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
535 switch (defAtom->merge()) {
536 case DefinedAtom::mergeAsTentative:
537 // Tentative definitions are referenced via external relocations.
538 return true;
539 case DefinedAtom::mergeAsWeak:
540 case DefinedAtom::mergeAsWeakAndAddressUsed:
541 // Global weak-defs are referenced via external relocations.
542 return (defAtom->scope() == DefinedAtom::scopeGlobal);
543 default:
544 break;
545 }
546 }
547 // Everything else is reference via an internal relocation.
548 return false;
549}
550
Nick Kledzik2d432352014-07-17 23:16:21 +0000551void ArchHandler_x86::appendSectionRelocations(
552 const DefinedAtom &atom,
553 uint64_t atomSectionOffset,
554 const Reference &ref,
555 FindSymbolIndexForAtom symbolIndexForAtom,
556 FindSectionIndexForAtom sectionIndexForAtom,
557 FindAddressForAtom addressForAtom,
558 normalized::Relocations &relocs) {
559 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
560 return;
561 assert(ref.kindArch() == Reference::KindArch::x86);
562 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
563 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000564 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik21921372014-07-24 23:06:56 +0000565 case modeCode:
566 case modeData:
567 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000568 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000569 if (useExternalReloc) {
570 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
571 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
572 } else {
573 if (ref.addend() != 0)
574 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
575 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
576 else
577 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
578 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
579 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000580 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000581 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000582 if (useExternalReloc) {
583 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
584 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
585 } else {
586 if (ref.addend() != 0)
587 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
588 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
589 else
590 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
591 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
592 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000593 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000594 case pointer32:
595 case abs32:
596 if (useExternalReloc)
597 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000598 GENERIC_RELOC_VANILLA | rExtern | rLength4);
599 else {
600 if (ref.addend() != 0)
601 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
602 GENERIC_RELOC_VANILLA | rScattered | rLength4);
603 else
604 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000605 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000606 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000607 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000608 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000609 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
610 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
611 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
612 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000613 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000614 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000615 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
616 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
617 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
618 ref.offsetInAtom(),
619 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000620 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000621 case negDelta32:
622 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
623 ref.offsetInAtom(),
624 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
625 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
626 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000627 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000628 case lazyPointer:
629 case lazyImmediateLocation:
630 llvm_unreachable("lazy reference kind implies Stubs pass was run");
631 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000632 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000633 llvm_unreachable("unknown x86 Reference Kind");
634 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000635 }
636}
637
Nick Kledzik2458bec2014-07-16 19:49:02 +0000638std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
639 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
640}
641
642} // namespace mach_o
643} // namespace lld