X86MachObjectWriter.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. //===-- X86MachObjectWriter.cpp - X86 Mach-O Writer -----------------------===//
  2. //
  3. // 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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "MCTargetDesc/X86FixupKinds.h"
  9. #include "MCTargetDesc/X86MCTargetDesc.h"
  10. #include "llvm/ADT/Twine.h"
  11. #include "llvm/BinaryFormat/MachO.h"
  12. #include "llvm/MC/MCAsmInfo.h"
  13. #include "llvm/MC/MCAsmLayout.h"
  14. #include "llvm/MC/MCAssembler.h"
  15. #include "llvm/MC/MCContext.h"
  16. #include "llvm/MC/MCMachObjectWriter.h"
  17. #include "llvm/MC/MCSectionMachO.h"
  18. #include "llvm/MC/MCValue.h"
  19. #include "llvm/Support/ErrorHandling.h"
  20. #include "llvm/Support/Format.h"
  21. using namespace llvm;
  22. namespace {
  23. class X86MachObjectWriter : public MCMachObjectTargetWriter {
  24. bool recordScatteredRelocation(MachObjectWriter *Writer,
  25. const MCAssembler &Asm,
  26. const MCAsmLayout &Layout,
  27. const MCFragment *Fragment,
  28. const MCFixup &Fixup,
  29. MCValue Target,
  30. unsigned Log2Size,
  31. uint64_t &FixedValue);
  32. void recordTLVPRelocation(MachObjectWriter *Writer,
  33. const MCAssembler &Asm,
  34. const MCAsmLayout &Layout,
  35. const MCFragment *Fragment,
  36. const MCFixup &Fixup,
  37. MCValue Target,
  38. uint64_t &FixedValue);
  39. void RecordX86Relocation(MachObjectWriter *Writer,
  40. const MCAssembler &Asm,
  41. const MCAsmLayout &Layout,
  42. const MCFragment *Fragment,
  43. const MCFixup &Fixup,
  44. MCValue Target,
  45. uint64_t &FixedValue);
  46. void RecordX86_64Relocation(MachObjectWriter *Writer, MCAssembler &Asm,
  47. const MCAsmLayout &Layout,
  48. const MCFragment *Fragment, const MCFixup &Fixup,
  49. MCValue Target, uint64_t &FixedValue);
  50. public:
  51. X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
  52. : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
  53. void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
  54. const MCAsmLayout &Layout, const MCFragment *Fragment,
  55. const MCFixup &Fixup, MCValue Target,
  56. uint64_t &FixedValue) override {
  57. if (Writer->is64Bit())
  58. RecordX86_64Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
  59. FixedValue);
  60. else
  61. RecordX86Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
  62. FixedValue);
  63. }
  64. };
  65. } // namespace
  66. static bool isFixupKindRIPRel(unsigned Kind) {
  67. return Kind == X86::reloc_riprel_4byte ||
  68. Kind == X86::reloc_riprel_4byte_movq_load ||
  69. Kind == X86::reloc_riprel_4byte_relax ||
  70. Kind == X86::reloc_riprel_4byte_relax_rex;
  71. }
  72. static unsigned getFixupKindLog2Size(unsigned Kind) {
  73. switch (Kind) {
  74. default:
  75. llvm_unreachable("invalid fixup kind!");
  76. case FK_PCRel_1:
  77. case FK_Data_1: return 0;
  78. case FK_PCRel_2:
  79. case FK_Data_2: return 1;
  80. case FK_PCRel_4:
  81. // FIXME: Remove these!!!
  82. case X86::reloc_riprel_4byte:
  83. case X86::reloc_riprel_4byte_relax:
  84. case X86::reloc_riprel_4byte_relax_rex:
  85. case X86::reloc_riprel_4byte_movq_load:
  86. case X86::reloc_signed_4byte:
  87. case X86::reloc_signed_4byte_relax:
  88. case X86::reloc_branch_4byte_pcrel:
  89. case FK_Data_4: return 2;
  90. case FK_Data_8: return 3;
  91. }
  92. }
  93. void X86MachObjectWriter::RecordX86_64Relocation(
  94. MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
  95. const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
  96. uint64_t &FixedValue) {
  97. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  98. unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
  99. unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
  100. // See <reloc.h>.
  101. uint32_t FixupOffset =
  102. Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
  103. uint32_t FixupAddress =
  104. Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
  105. int64_t Value = 0;
  106. unsigned Index = 0;
  107. unsigned IsExtern = 0;
  108. unsigned Type = 0;
  109. const MCSymbol *RelSymbol = nullptr;
  110. Value = Target.getConstant();
  111. if (IsPCRel) {
  112. // Compensate for the relocation offset, Darwin x86_64 relocations only have
  113. // the addend and appear to have attempted to define it to be the actual
  114. // expression addend without the PCrel bias. However, instructions with data
  115. // following the relocation are not accommodated for (see comment below
  116. // regarding SIGNED{1,2,4}), so it isn't exactly that either.
  117. Value += 1LL << Log2Size;
  118. }
  119. if (Target.isAbsolute()) { // constant
  120. // SymbolNum of 0 indicates the absolute section.
  121. Type = MachO::X86_64_RELOC_UNSIGNED;
  122. // FIXME: I believe this is broken, I don't think the linker can understand
  123. // it. I think it would require a local relocation, but I'm not sure if that
  124. // would work either. The official way to get an absolute PCrel relocation
  125. // is to use an absolute symbol (which we don't support yet).
  126. if (IsPCRel) {
  127. IsExtern = 1;
  128. Type = MachO::X86_64_RELOC_BRANCH;
  129. }
  130. } else if (Target.getSymB()) { // A - B + constant
  131. const MCSymbol *A = &Target.getSymA()->getSymbol();
  132. if (A->isTemporary())
  133. A = &Writer->findAliasedSymbol(*A);
  134. const MCSymbol *A_Base = Asm.getAtom(*A);
  135. const MCSymbol *B = &Target.getSymB()->getSymbol();
  136. if (B->isTemporary())
  137. B = &Writer->findAliasedSymbol(*B);
  138. const MCSymbol *B_Base = Asm.getAtom(*B);
  139. // Neither symbol can be modified.
  140. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) {
  141. Asm.getContext().reportError(Fixup.getLoc(),
  142. "unsupported relocation of modified symbol");
  143. return;
  144. }
  145. // We don't support PCrel relocations of differences. Darwin 'as' doesn't
  146. // implement most of these correctly.
  147. if (IsPCRel) {
  148. Asm.getContext().reportError(
  149. Fixup.getLoc(), "unsupported pc-relative relocation of difference");
  150. return;
  151. }
  152. // The support for the situation where one or both of the symbols would
  153. // require a local relocation is handled just like if the symbols were
  154. // external. This is certainly used in the case of debug sections where the
  155. // section has only temporary symbols and thus the symbols don't have base
  156. // symbols. This is encoded using the section ordinal and non-extern
  157. // relocation entries.
  158. // Darwin 'as' doesn't emit correct relocations for this (it ends up with a
  159. // single SIGNED relocation); reject it for now. Except the case where both
  160. // symbols don't have a base, equal but both NULL.
  161. if (A_Base == B_Base && A_Base) {
  162. Asm.getContext().reportError(
  163. Fixup.getLoc(), "unsupported relocation with identical base");
  164. return;
  165. }
  166. // A subtraction expression where either symbol is undefined is a
  167. // non-relocatable expression.
  168. if (A->isUndefined() || B->isUndefined()) {
  169. StringRef Name = A->isUndefined() ? A->getName() : B->getName();
  170. Asm.getContext().reportError(Fixup.getLoc(),
  171. "unsupported relocation with subtraction expression, symbol '" +
  172. Name + "' can not be undefined in a subtraction expression");
  173. return;
  174. }
  175. Value += Writer->getSymbolAddress(*A, Layout) -
  176. (!A_Base ? 0 : Writer->getSymbolAddress(*A_Base, Layout));
  177. Value -= Writer->getSymbolAddress(*B, Layout) -
  178. (!B_Base ? 0 : Writer->getSymbolAddress(*B_Base, Layout));
  179. if (!A_Base)
  180. Index = A->getFragment()->getParent()->getOrdinal() + 1;
  181. Type = MachO::X86_64_RELOC_UNSIGNED;
  182. MachO::any_relocation_info MRE;
  183. MRE.r_word0 = FixupOffset;
  184. MRE.r_word1 =
  185. (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  186. Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
  187. if (B_Base)
  188. RelSymbol = B_Base;
  189. else
  190. Index = B->getFragment()->getParent()->getOrdinal() + 1;
  191. Type = MachO::X86_64_RELOC_SUBTRACTOR;
  192. } else {
  193. const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
  194. if (Symbol->isTemporary() && Value) {
  195. const MCSection &Sec = Symbol->getSection();
  196. if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec))
  197. Symbol->setUsedInReloc();
  198. }
  199. RelSymbol = Asm.getAtom(*Symbol);
  200. // Relocations inside debug sections always use local relocations when
  201. // possible. This seems to be done because the debugger doesn't fully
  202. // understand x86_64 relocation entries, and expects to find values that
  203. // have already been fixed up.
  204. if (Symbol->isInSection()) {
  205. const MCSectionMachO &Section =
  206. static_cast<const MCSectionMachO &>(*Fragment->getParent());
  207. if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
  208. RelSymbol = nullptr;
  209. }
  210. // x86_64 almost always uses external relocations, except when there is no
  211. // symbol to use as a base address (a local symbol with no preceding
  212. // non-local symbol).
  213. if (RelSymbol) {
  214. // Add the local offset, if needed.
  215. if (RelSymbol != Symbol)
  216. Value += Layout.getSymbolOffset(*Symbol) -
  217. Layout.getSymbolOffset(*RelSymbol);
  218. } else if (Symbol->isInSection() && !Symbol->isVariable()) {
  219. // The index is the section ordinal (1-based).
  220. Index = Symbol->getFragment()->getParent()->getOrdinal() + 1;
  221. Value += Writer->getSymbolAddress(*Symbol, Layout);
  222. if (IsPCRel)
  223. Value -= FixupAddress + (1 << Log2Size);
  224. } else if (Symbol->isVariable()) {
  225. const MCExpr *Value = Symbol->getVariableValue();
  226. int64_t Res;
  227. bool isAbs = Value->evaluateAsAbsolute(Res, Layout,
  228. Writer->getSectionAddressMap());
  229. if (isAbs) {
  230. FixedValue = Res;
  231. return;
  232. } else {
  233. Asm.getContext().reportError(Fixup.getLoc(),
  234. "unsupported relocation of variable '" +
  235. Symbol->getName() + "'");
  236. return;
  237. }
  238. } else {
  239. Asm.getContext().reportError(
  240. Fixup.getLoc(), "unsupported relocation of undefined symbol '" +
  241. Symbol->getName() + "'");
  242. return;
  243. }
  244. MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
  245. if (IsPCRel) {
  246. if (IsRIPRel) {
  247. if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
  248. // x86_64 distinguishes movq foo@GOTPCREL so that the linker can
  249. // rewrite the movq to an leaq at link time if the symbol ends up in
  250. // the same linkage unit.
  251. if (Fixup.getTargetKind() == X86::reloc_riprel_4byte_movq_load)
  252. Type = MachO::X86_64_RELOC_GOT_LOAD;
  253. else
  254. Type = MachO::X86_64_RELOC_GOT;
  255. } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
  256. Type = MachO::X86_64_RELOC_TLV;
  257. } else if (Modifier != MCSymbolRefExpr::VK_None) {
  258. Asm.getContext().reportError(
  259. Fixup.getLoc(), "unsupported symbol modifier in relocation");
  260. return;
  261. } else {
  262. Type = MachO::X86_64_RELOC_SIGNED;
  263. // The Darwin x86_64 relocation format has a problem where it cannot
  264. // encode an address (L<foo> + <constant>) which is outside the atom
  265. // containing L<foo>. Generally, this shouldn't occur but it does
  266. // happen when we have a RIPrel instruction with data following the
  267. // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel
  268. // adjustment Darwin x86_64 uses, the offset is still negative and the
  269. // linker has no way to recognize this.
  270. //
  271. // To work around this, Darwin uses several special relocation types
  272. // to indicate the offsets. However, the specification or
  273. // implementation of these seems to also be incomplete; they should
  274. // adjust the addend as well based on the actual encoded instruction
  275. // (the additional bias), but instead appear to just look at the final
  276. // offset.
  277. switch (-(Target.getConstant() + (1LL << Log2Size))) {
  278. case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break;
  279. case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break;
  280. case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break;
  281. }
  282. }
  283. } else {
  284. if (Modifier != MCSymbolRefExpr::VK_None) {
  285. Asm.getContext().reportError(
  286. Fixup.getLoc(),
  287. "unsupported symbol modifier in branch relocation");
  288. return;
  289. }
  290. Type = MachO::X86_64_RELOC_BRANCH;
  291. }
  292. } else {
  293. if (Modifier == MCSymbolRefExpr::VK_GOT) {
  294. Type = MachO::X86_64_RELOC_GOT;
  295. } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
  296. // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which
  297. // case all we do is set the PCrel bit in the relocation entry; this is
  298. // used with exception handling, for example. The source is required to
  299. // include any necessary offset directly.
  300. Type = MachO::X86_64_RELOC_GOT;
  301. IsPCRel = 1;
  302. } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
  303. Asm.getContext().reportError(
  304. Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel");
  305. return;
  306. } else if (Modifier != MCSymbolRefExpr::VK_None) {
  307. Asm.getContext().reportError(
  308. Fixup.getLoc(), "unsupported symbol modifier in relocation");
  309. return;
  310. } else {
  311. Type = MachO::X86_64_RELOC_UNSIGNED;
  312. if (Fixup.getTargetKind() == X86::reloc_signed_4byte) {
  313. Asm.getContext().reportError(
  314. Fixup.getLoc(),
  315. "32-bit absolute addressing is not supported in 64-bit mode");
  316. return;
  317. }
  318. }
  319. }
  320. }
  321. // x86_64 always writes custom values into the fixups.
  322. FixedValue = Value;
  323. // struct relocation_info (8 bytes)
  324. MachO::any_relocation_info MRE;
  325. MRE.r_word0 = FixupOffset;
  326. MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
  327. (IsExtern << 27) | (Type << 28);
  328. Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
  329. }
  330. bool X86MachObjectWriter::recordScatteredRelocation(MachObjectWriter *Writer,
  331. const MCAssembler &Asm,
  332. const MCAsmLayout &Layout,
  333. const MCFragment *Fragment,
  334. const MCFixup &Fixup,
  335. MCValue Target,
  336. unsigned Log2Size,
  337. uint64_t &FixedValue) {
  338. uint64_t OriginalFixedValue = FixedValue;
  339. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  340. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  341. unsigned Type = MachO::GENERIC_RELOC_VANILLA;
  342. // See <reloc.h>.
  343. const MCSymbol *A = &Target.getSymA()->getSymbol();
  344. if (!A->getFragment()) {
  345. Asm.getContext().reportError(
  346. Fixup.getLoc(),
  347. "symbol '" + A->getName() +
  348. "' can not be undefined in a subtraction expression");
  349. return false;
  350. }
  351. uint32_t Value = Writer->getSymbolAddress(*A, Layout);
  352. uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
  353. FixedValue += SecAddr;
  354. uint32_t Value2 = 0;
  355. if (const MCSymbolRefExpr *B = Target.getSymB()) {
  356. const MCSymbol *SB = &B->getSymbol();
  357. if (!SB->getFragment()) {
  358. Asm.getContext().reportError(
  359. Fixup.getLoc(),
  360. "symbol '" + SB->getName() +
  361. "' can not be undefined in a subtraction expression");
  362. return false;
  363. }
  364. // Select the appropriate difference relocation type.
  365. //
  366. // Note that there is no longer any semantic difference between these two
  367. // relocation types from the linkers point of view, this is done solely for
  368. // pedantic compatibility with 'as'.
  369. Type = A->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF
  370. : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
  371. Value2 = Writer->getSymbolAddress(*SB, Layout);
  372. FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
  373. }
  374. // Relocations are written out in reverse order, so the PAIR comes first.
  375. if (Type == MachO::GENERIC_RELOC_SECTDIFF ||
  376. Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
  377. // If the offset is too large to fit in a scattered relocation,
  378. // we're hosed. It's an unfortunate limitation of the MachO format.
  379. if (FixupOffset > 0xffffff) {
  380. char Buffer[32];
  381. format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
  382. Asm.getContext().reportError(Fixup.getLoc(),
  383. Twine("Section too large, can't encode "
  384. "r_address (") + Buffer +
  385. ") into 24 bits of scattered "
  386. "relocation entry.");
  387. return false;
  388. }
  389. MachO::any_relocation_info MRE;
  390. MRE.r_word0 = ((0 << 0) | // r_address
  391. (MachO::GENERIC_RELOC_PAIR << 24) | // r_type
  392. (Log2Size << 28) |
  393. (IsPCRel << 30) |
  394. MachO::R_SCATTERED);
  395. MRE.r_word1 = Value2;
  396. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  397. } else {
  398. // If the offset is more than 24-bits, it won't fit in a scattered
  399. // relocation offset field, so we fall back to using a non-scattered
  400. // relocation. This is a bit risky, as if the offset reaches out of
  401. // the block and the linker is doing scattered loading on this
  402. // symbol, things can go badly.
  403. //
  404. // Required for 'as' compatibility.
  405. if (FixupOffset > 0xffffff) {
  406. FixedValue = OriginalFixedValue;
  407. return false;
  408. }
  409. }
  410. MachO::any_relocation_info MRE;
  411. MRE.r_word0 = ((FixupOffset << 0) |
  412. (Type << 24) |
  413. (Log2Size << 28) |
  414. (IsPCRel << 30) |
  415. MachO::R_SCATTERED);
  416. MRE.r_word1 = Value;
  417. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  418. return true;
  419. }
  420. void X86MachObjectWriter::recordTLVPRelocation(MachObjectWriter *Writer,
  421. const MCAssembler &Asm,
  422. const MCAsmLayout &Layout,
  423. const MCFragment *Fragment,
  424. const MCFixup &Fixup,
  425. MCValue Target,
  426. uint64_t &FixedValue) {
  427. const MCSymbolRefExpr *SymA = Target.getSymA();
  428. assert(SymA->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() &&
  429. "Should only be called with a 32-bit TLVP relocation!");
  430. unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
  431. uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  432. unsigned IsPCRel = 0;
  433. // We're only going to have a second symbol in pic mode and it'll be a
  434. // subtraction from the picbase. For 32-bit pic the addend is the difference
  435. // between the picbase and the next address. For 32-bit static the addend is
  436. // zero.
  437. if (auto *SymB = Target.getSymB()) {
  438. // If this is a subtraction then we're pcrel.
  439. uint32_t FixupAddress =
  440. Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
  441. IsPCRel = 1;
  442. FixedValue = FixupAddress -
  443. Writer->getSymbolAddress(SymB->getSymbol(), Layout) +
  444. Target.getConstant();
  445. FixedValue += 1ULL << Log2Size;
  446. } else {
  447. FixedValue = 0;
  448. }
  449. // struct relocation_info (8 bytes)
  450. MachO::any_relocation_info MRE;
  451. MRE.r_word0 = Value;
  452. MRE.r_word1 =
  453. (IsPCRel << 24) | (Log2Size << 25) | (MachO::GENERIC_RELOC_TLV << 28);
  454. Writer->addRelocation(&SymA->getSymbol(), Fragment->getParent(), MRE);
  455. }
  456. void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
  457. const MCAssembler &Asm,
  458. const MCAsmLayout &Layout,
  459. const MCFragment *Fragment,
  460. const MCFixup &Fixup,
  461. MCValue Target,
  462. uint64_t &FixedValue) {
  463. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  464. unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
  465. // If this is a 32-bit TLVP reloc it's handled a bit differently.
  466. if (Target.getSymA() &&
  467. Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) {
  468. recordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
  469. FixedValue);
  470. return;
  471. }
  472. // If this is a difference or a defined symbol plus an offset, then we need a
  473. // scattered relocation entry. Differences always require scattered
  474. // relocations.
  475. if (Target.getSymB()) {
  476. recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
  477. Target, Log2Size, FixedValue);
  478. return;
  479. }
  480. // Get the symbol data, if any.
  481. const MCSymbol *A = nullptr;
  482. if (Target.getSymA())
  483. A = &Target.getSymA()->getSymbol();
  484. // If this is an internal relocation with an offset, it also needs a scattered
  485. // relocation entry.
  486. uint32_t Offset = Target.getConstant();
  487. if (IsPCRel)
  488. Offset += 1 << Log2Size;
  489. // Try to record the scattered relocation if needed. Fall back to non
  490. // scattered if necessary (see comments in recordScatteredRelocation()
  491. // for details).
  492. if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
  493. recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
  494. Log2Size, FixedValue))
  495. return;
  496. // See <reloc.h>.
  497. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  498. unsigned Index = 0;
  499. unsigned Type = 0;
  500. const MCSymbol *RelSymbol = nullptr;
  501. if (Target.isAbsolute()) { // constant
  502. // SymbolNum of 0 indicates the absolute section.
  503. //
  504. // FIXME: Currently, these are never generated (see code below). I cannot
  505. // find a case where they are actually emitted.
  506. Type = MachO::GENERIC_RELOC_VANILLA;
  507. } else {
  508. assert(A && "Unknown symbol data");
  509. // Resolve constant variables.
  510. if (A->isVariable()) {
  511. int64_t Res;
  512. if (A->getVariableValue()->evaluateAsAbsolute(
  513. Res, Layout, Writer->getSectionAddressMap())) {
  514. FixedValue = Res;
  515. return;
  516. }
  517. }
  518. // Check whether we need an external or internal relocation.
  519. if (Writer->doesSymbolRequireExternRelocation(*A)) {
  520. RelSymbol = A;
  521. // For external relocations, make sure to offset the fixup value to
  522. // compensate for the addend of the symbol address, if it was
  523. // undefined. This occurs with weak definitions, for example.
  524. if (!A->isUndefined())
  525. FixedValue -= Layout.getSymbolOffset(*A);
  526. } else {
  527. // The index is the section ordinal (1-based).
  528. const MCSection &Sec = A->getSection();
  529. Index = Sec.getOrdinal() + 1;
  530. FixedValue += Writer->getSectionAddress(&Sec);
  531. }
  532. if (IsPCRel)
  533. FixedValue -= Writer->getSectionAddress(Fragment->getParent());
  534. Type = MachO::GENERIC_RELOC_VANILLA;
  535. }
  536. // struct relocation_info (8 bytes)
  537. MachO::any_relocation_info MRE;
  538. MRE.r_word0 = FixupOffset;
  539. MRE.r_word1 =
  540. (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  541. Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
  542. }
  543. std::unique_ptr<MCObjectTargetWriter>
  544. llvm::createX86MachObjectWriter(bool Is64Bit, uint32_t CPUType,
  545. uint32_t CPUSubtype) {
  546. return std::make_unique<X86MachObjectWriter>(Is64Bit, CPUType, CPUSubtype);
  547. }