AArch64MachObjectWriter.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //===-- AArch64MachObjectWriter.cpp - ARM Mach Object 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/AArch64FixupKinds.h"
  9. #include "MCTargetDesc/AArch64MCTargetDesc.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/MCExpr.h"
  17. #include "llvm/MC/MCFixup.h"
  18. #include "llvm/MC/MCFragment.h"
  19. #include "llvm/MC/MCMachObjectWriter.h"
  20. #include "llvm/MC/MCSection.h"
  21. #include "llvm/MC/MCSectionMachO.h"
  22. #include "llvm/MC/MCSymbol.h"
  23. #include "llvm/MC/MCValue.h"
  24. #include "llvm/Support/Casting.h"
  25. #include "llvm/Support/MathExtras.h"
  26. #include <cassert>
  27. #include <cstdint>
  28. using namespace llvm;
  29. namespace {
  30. class AArch64MachObjectWriter : public MCMachObjectTargetWriter {
  31. bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType,
  32. const MCSymbolRefExpr *Sym,
  33. unsigned &Log2Size, const MCAssembler &Asm);
  34. public:
  35. AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype, bool IsILP32)
  36. : MCMachObjectTargetWriter(!IsILP32 /* is64Bit */, CPUType, CPUSubtype) {}
  37. void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
  38. const MCAsmLayout &Layout, const MCFragment *Fragment,
  39. const MCFixup &Fixup, MCValue Target,
  40. uint64_t &FixedValue) override;
  41. };
  42. } // end anonymous namespace
  43. bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
  44. const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym,
  45. unsigned &Log2Size, const MCAssembler &Asm) {
  46. RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED);
  47. Log2Size = ~0U;
  48. switch (Fixup.getTargetKind()) {
  49. default:
  50. return false;
  51. case FK_Data_1:
  52. Log2Size = Log2_32(1);
  53. return true;
  54. case FK_Data_2:
  55. Log2Size = Log2_32(2);
  56. return true;
  57. case FK_Data_4:
  58. Log2Size = Log2_32(4);
  59. if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
  60. RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
  61. return true;
  62. case FK_Data_8:
  63. Log2Size = Log2_32(8);
  64. if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
  65. RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
  66. return true;
  67. case AArch64::fixup_aarch64_add_imm12:
  68. case AArch64::fixup_aarch64_ldst_imm12_scale1:
  69. case AArch64::fixup_aarch64_ldst_imm12_scale2:
  70. case AArch64::fixup_aarch64_ldst_imm12_scale4:
  71. case AArch64::fixup_aarch64_ldst_imm12_scale8:
  72. case AArch64::fixup_aarch64_ldst_imm12_scale16:
  73. Log2Size = Log2_32(4);
  74. switch (Sym->getKind()) {
  75. default:
  76. return false;
  77. case MCSymbolRefExpr::VK_PAGEOFF:
  78. RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
  79. return true;
  80. case MCSymbolRefExpr::VK_GOTPAGEOFF:
  81. RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
  82. return true;
  83. case MCSymbolRefExpr::VK_TLVPPAGEOFF:
  84. RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
  85. return true;
  86. }
  87. case AArch64::fixup_aarch64_pcrel_adrp_imm21:
  88. Log2Size = Log2_32(4);
  89. // This encompasses the relocation for the whole 21-bit value.
  90. switch (Sym->getKind()) {
  91. default:
  92. Asm.getContext().reportError(Fixup.getLoc(),
  93. "ADR/ADRP relocations must be GOT relative");
  94. return false;
  95. case MCSymbolRefExpr::VK_PAGE:
  96. RelocType = unsigned(MachO::ARM64_RELOC_PAGE21);
  97. return true;
  98. case MCSymbolRefExpr::VK_GOTPAGE:
  99. RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
  100. return true;
  101. case MCSymbolRefExpr::VK_TLVPPAGE:
  102. RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
  103. return true;
  104. }
  105. return true;
  106. case AArch64::fixup_aarch64_pcrel_branch26:
  107. case AArch64::fixup_aarch64_pcrel_call26:
  108. Log2Size = Log2_32(4);
  109. RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26);
  110. return true;
  111. }
  112. }
  113. static bool canUseLocalRelocation(const MCSectionMachO &Section,
  114. const MCSymbol &Symbol, unsigned Log2Size) {
  115. // Debug info sections can use local relocations.
  116. if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
  117. return true;
  118. // Otherwise, only pointer sized relocations are supported.
  119. if (Log2Size != 3)
  120. return false;
  121. // But only if they don't point to a few forbidden sections.
  122. if (!Symbol.isInSection())
  123. return true;
  124. const MCSectionMachO &RefSec = cast<MCSectionMachO>(Symbol.getSection());
  125. if (RefSec.getType() == MachO::S_CSTRING_LITERALS)
  126. return false;
  127. if (RefSec.getSegmentName() == "__DATA" &&
  128. RefSec.getName() == "__objc_classrefs")
  129. return false;
  130. // FIXME: ld64 currently handles internal pointer-sized relocations
  131. // incorrectly (applying the addend twice). We should be able to return true
  132. // unconditionally by this point when that's fixed.
  133. return false;
  134. }
  135. void AArch64MachObjectWriter::recordRelocation(
  136. MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
  137. const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
  138. uint64_t &FixedValue) {
  139. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  140. // See <reloc.h>.
  141. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
  142. unsigned Log2Size = 0;
  143. int64_t Value = 0;
  144. unsigned Index = 0;
  145. unsigned Type = 0;
  146. unsigned Kind = Fixup.getKind();
  147. const MCSymbol *RelSymbol = nullptr;
  148. FixupOffset += Fixup.getOffset();
  149. // AArch64 pcrel relocation addends do not include the section offset.
  150. if (IsPCRel)
  151. FixedValue += FixupOffset;
  152. // ADRP fixups use relocations for the whole symbol value and only
  153. // put the addend in the instruction itself. Clear out any value the
  154. // generic code figured out from the sybmol definition.
  155. if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
  156. FixedValue = 0;
  157. // imm19 relocations are for conditional branches, which require
  158. // assembler local symbols. If we got here, that's not what we have,
  159. // so complain loudly.
  160. if (Kind == AArch64::fixup_aarch64_pcrel_branch19) {
  161. Asm.getContext().reportError(Fixup.getLoc(),
  162. "conditional branch requires assembler-local"
  163. " label. '" +
  164. Target.getSymA()->getSymbol().getName() +
  165. "' is external.");
  166. return;
  167. }
  168. // 14-bit branch relocations should only target internal labels, and so
  169. // should never get here.
  170. if (Kind == AArch64::fixup_aarch64_pcrel_branch14) {
  171. Asm.getContext().reportError(Fixup.getLoc(),
  172. "Invalid relocation on conditional branch!");
  173. return;
  174. }
  175. if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
  176. Asm)) {
  177. Asm.getContext().reportError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
  178. return;
  179. }
  180. Value = Target.getConstant();
  181. if (Target.isAbsolute()) { // constant
  182. // FIXME: Should this always be extern?
  183. // SymbolNum of 0 indicates the absolute section.
  184. Type = MachO::ARM64_RELOC_UNSIGNED;
  185. if (IsPCRel) {
  186. Asm.getContext().reportError(Fixup.getLoc(),
  187. "PC relative absolute relocation!");
  188. return;
  189. // FIXME: x86_64 sets the type to a branch reloc here. Should we do
  190. // something similar?
  191. }
  192. } else if (Target.getSymB()) { // A - B + constant
  193. const MCSymbol *A = &Target.getSymA()->getSymbol();
  194. const MCSymbol *A_Base = Asm.getAtom(*A);
  195. const MCSymbol *B = &Target.getSymB()->getSymbol();
  196. const MCSymbol *B_Base = Asm.getAtom(*B);
  197. // Check for "_foo@got - .", which comes through here as:
  198. // Ltmp0:
  199. // ... _foo@got - Ltmp0
  200. if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
  201. Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
  202. Layout.getSymbolOffset(*B) ==
  203. Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
  204. // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
  205. Type = MachO::ARM64_RELOC_POINTER_TO_GOT;
  206. IsPCRel = 1;
  207. MachO::any_relocation_info MRE;
  208. MRE.r_word0 = FixupOffset;
  209. MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  210. Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
  211. return;
  212. } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
  213. Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) {
  214. // Otherwise, neither symbol can be modified.
  215. Asm.getContext().reportError(Fixup.getLoc(),
  216. "unsupported relocation of modified symbol");
  217. return;
  218. }
  219. // We don't support PCrel relocations of differences.
  220. if (IsPCRel) {
  221. Asm.getContext().reportError(Fixup.getLoc(),
  222. "unsupported pc-relative relocation of "
  223. "difference");
  224. return;
  225. }
  226. // AArch64 always uses external relocations. If there is no symbol to use as
  227. // a base address (a local symbol with no preceding non-local symbol),
  228. // error out.
  229. //
  230. // FIXME: We should probably just synthesize an external symbol and use
  231. // that.
  232. if (!A_Base) {
  233. Asm.getContext().reportError(
  234. Fixup.getLoc(),
  235. "unsupported relocation of local symbol '" + A->getName() +
  236. "'. Must have non-local symbol earlier in section.");
  237. return;
  238. }
  239. if (!B_Base) {
  240. Asm.getContext().reportError(
  241. Fixup.getLoc(),
  242. "unsupported relocation of local symbol '" + B->getName() +
  243. "'. Must have non-local symbol earlier in section.");
  244. return;
  245. }
  246. if (A_Base == B_Base && A_Base) {
  247. Asm.getContext().reportError(
  248. Fixup.getLoc(), "unsupported relocation with identical base");
  249. return;
  250. }
  251. Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Layout)) -
  252. (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress(
  253. *A_Base, Layout));
  254. Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, Layout)) -
  255. (!B_Base || !B_Base->getFragment() ? 0 : Writer->getSymbolAddress(
  256. *B_Base, Layout));
  257. Type = MachO::ARM64_RELOC_UNSIGNED;
  258. MachO::any_relocation_info MRE;
  259. MRE.r_word0 = FixupOffset;
  260. MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  261. Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
  262. RelSymbol = B_Base;
  263. Type = MachO::ARM64_RELOC_SUBTRACTOR;
  264. } else { // A + constant
  265. const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
  266. const MCSectionMachO &Section =
  267. static_cast<const MCSectionMachO &>(*Fragment->getParent());
  268. bool CanUseLocalRelocation =
  269. canUseLocalRelocation(Section, *Symbol, Log2Size);
  270. if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) {
  271. // Make sure that the symbol is actually in a section here. If it isn't,
  272. // emit an error and exit.
  273. if (!Symbol->isInSection()) {
  274. Asm.getContext().reportError(
  275. Fixup.getLoc(),
  276. "unsupported relocation of local symbol '" + Symbol->getName() +
  277. "'. Must have non-local symbol earlier in section.");
  278. return;
  279. }
  280. const MCSection &Sec = Symbol->getSection();
  281. if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec))
  282. Symbol->setUsedInReloc();
  283. }
  284. const MCSymbol *Base = Asm.getAtom(*Symbol);
  285. // If the symbol is a variable it can either be in a section and
  286. // we have a base or it is absolute and should have been expanded.
  287. assert(!Symbol->isVariable() || Base);
  288. // Relocations inside debug sections always use local relocations when
  289. // possible. This seems to be done because the debugger doesn't fully
  290. // understand relocation entries and expects to find values that
  291. // have already been fixed up.
  292. if (Symbol->isInSection()) {
  293. if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
  294. Base = nullptr;
  295. }
  296. // AArch64 uses external relocations as much as possible. For debug
  297. // sections, and for pointer-sized relocations (.quad), we allow section
  298. // relocations. It's code sections that run into trouble.
  299. if (Base) {
  300. RelSymbol = Base;
  301. // Add the local offset, if needed.
  302. if (Base != Symbol)
  303. Value +=
  304. Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*Base);
  305. } else if (Symbol->isInSection()) {
  306. if (!CanUseLocalRelocation) {
  307. Asm.getContext().reportError(
  308. Fixup.getLoc(),
  309. "unsupported relocation of local symbol '" + Symbol->getName() +
  310. "'. Must have non-local symbol earlier in section.");
  311. return;
  312. }
  313. // Adjust the relocation to be section-relative.
  314. // The index is the section ordinal (1-based).
  315. const MCSection &Sec = Symbol->getSection();
  316. Index = Sec.getOrdinal() + 1;
  317. Value += Writer->getSymbolAddress(*Symbol, Layout);
  318. if (IsPCRel)
  319. Value -= Writer->getFragmentAddress(Fragment, Layout) +
  320. Fixup.getOffset() + (1ULL << Log2Size);
  321. } else {
  322. llvm_unreachable(
  323. "This constant variable should have been expanded during evaluation");
  324. }
  325. }
  326. // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
  327. // is represented via an Addend relocation, not encoded directly into
  328. // the instruction.
  329. if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
  330. Type == MachO::ARM64_RELOC_PAGE21 ||
  331. Type == MachO::ARM64_RELOC_PAGEOFF12) &&
  332. Value) {
  333. if (!isInt<24>(Value)) {
  334. Asm.getContext().reportError(Fixup.getLoc(),
  335. "addend too big for relocation");
  336. return;
  337. }
  338. MachO::any_relocation_info MRE;
  339. MRE.r_word0 = FixupOffset;
  340. MRE.r_word1 =
  341. (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  342. Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
  343. // Now set up the Addend relocation.
  344. Type = MachO::ARM64_RELOC_ADDEND;
  345. Index = Value;
  346. RelSymbol = nullptr;
  347. IsPCRel = 0;
  348. Log2Size = 2;
  349. // Put zero into the instruction itself. The addend is in the relocation.
  350. Value = 0;
  351. }
  352. // If there's any addend left to handle, encode it in the instruction.
  353. FixedValue = Value;
  354. // struct relocation_info (8 bytes)
  355. MachO::any_relocation_info MRE;
  356. MRE.r_word0 = FixupOffset;
  357. MRE.r_word1 =
  358. (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  359. Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
  360. }
  361. std::unique_ptr<MCObjectTargetWriter>
  362. llvm::createAArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype,
  363. bool IsILP32) {
  364. return std::make_unique<AArch64MachObjectWriter>(CPUType, CPUSubtype,
  365. IsILP32);
  366. }