ARMMachObjectWriter.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. //===-- ARMMachObjectWriter.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/ARMBaseInfo.h"
  9. #include "MCTargetDesc/ARMFixupKinds.h"
  10. #include "MCTargetDesc/ARMMCTargetDesc.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/ADT/Twine.h"
  13. #include "llvm/BinaryFormat/MachO.h"
  14. #include "llvm/MC/MCAsmLayout.h"
  15. #include "llvm/MC/MCAssembler.h"
  16. #include "llvm/MC/MCContext.h"
  17. #include "llvm/MC/MCExpr.h"
  18. #include "llvm/MC/MCFixup.h"
  19. #include "llvm/MC/MCFixupKindInfo.h"
  20. #include "llvm/MC/MCMachObjectWriter.h"
  21. #include "llvm/MC/MCSection.h"
  22. #include "llvm/MC/MCValue.h"
  23. #include "llvm/Support/ErrorHandling.h"
  24. using namespace llvm;
  25. namespace {
  26. class ARMMachObjectWriter : public MCMachObjectTargetWriter {
  27. void RecordARMScatteredRelocation(MachObjectWriter *Writer,
  28. const MCAssembler &Asm,
  29. const MCAsmLayout &Layout,
  30. const MCFragment *Fragment,
  31. const MCFixup &Fixup,
  32. MCValue Target,
  33. unsigned Type,
  34. unsigned Log2Size,
  35. uint64_t &FixedValue);
  36. void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
  37. const MCAssembler &Asm,
  38. const MCAsmLayout &Layout,
  39. const MCFragment *Fragment,
  40. const MCFixup &Fixup, MCValue Target,
  41. uint64_t &FixedValue);
  42. bool requiresExternRelocation(MachObjectWriter *Writer,
  43. const MCAssembler &Asm,
  44. const MCFragment &Fragment, unsigned RelocType,
  45. const MCSymbol &S, uint64_t FixedValue);
  46. public:
  47. ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
  48. : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
  49. void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
  50. const MCAsmLayout &Layout, const MCFragment *Fragment,
  51. const MCFixup &Fixup, MCValue Target,
  52. uint64_t &FixedValue) override;
  53. };
  54. }
  55. static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
  56. unsigned &Log2Size) {
  57. RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
  58. Log2Size = ~0U;
  59. switch (Kind) {
  60. default:
  61. return false;
  62. case FK_Data_1:
  63. Log2Size = llvm::Log2_32(1);
  64. return true;
  65. case FK_Data_2:
  66. Log2Size = llvm::Log2_32(2);
  67. return true;
  68. case FK_Data_4:
  69. Log2Size = llvm::Log2_32(4);
  70. return true;
  71. case FK_Data_8:
  72. Log2Size = llvm::Log2_32(8);
  73. return true;
  74. // These fixups are expected to always be resolvable at assembly time and
  75. // have no relocations supported.
  76. case ARM::fixup_arm_ldst_pcrel_12:
  77. case ARM::fixup_arm_pcrel_10:
  78. case ARM::fixup_arm_adr_pcrel_12:
  79. case ARM::fixup_arm_thumb_br:
  80. return false;
  81. // Handle 24-bit branch kinds.
  82. case ARM::fixup_arm_condbranch:
  83. case ARM::fixup_arm_uncondbranch:
  84. case ARM::fixup_arm_uncondbl:
  85. case ARM::fixup_arm_condbl:
  86. case ARM::fixup_arm_blx:
  87. RelocType = unsigned(MachO::ARM_RELOC_BR24);
  88. // Report as 'long', even though that is not quite accurate.
  89. Log2Size = llvm::Log2_32(4);
  90. return true;
  91. case ARM::fixup_t2_uncondbranch:
  92. case ARM::fixup_arm_thumb_bl:
  93. case ARM::fixup_arm_thumb_blx:
  94. RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
  95. Log2Size = llvm::Log2_32(4);
  96. return true;
  97. // For movw/movt r_type relocations they always have a pair following them and
  98. // the r_length bits are used differently. The encoding of the r_length is as
  99. // follows:
  100. // low bit of r_length:
  101. // 0 - :lower16: for movw instructions
  102. // 1 - :upper16: for movt instructions
  103. // high bit of r_length:
  104. // 0 - arm instructions
  105. // 1 - thumb instructions
  106. case ARM::fixup_arm_movt_hi16:
  107. RelocType = unsigned(MachO::ARM_RELOC_HALF);
  108. Log2Size = 1;
  109. return true;
  110. case ARM::fixup_t2_movt_hi16:
  111. RelocType = unsigned(MachO::ARM_RELOC_HALF);
  112. Log2Size = 3;
  113. return true;
  114. case ARM::fixup_arm_movw_lo16:
  115. RelocType = unsigned(MachO::ARM_RELOC_HALF);
  116. Log2Size = 0;
  117. return true;
  118. case ARM::fixup_t2_movw_lo16:
  119. RelocType = unsigned(MachO::ARM_RELOC_HALF);
  120. Log2Size = 2;
  121. return true;
  122. }
  123. }
  124. void ARMMachObjectWriter::
  125. RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
  126. const MCAssembler &Asm,
  127. const MCAsmLayout &Layout,
  128. const MCFragment *Fragment,
  129. const MCFixup &Fixup,
  130. MCValue Target,
  131. uint64_t &FixedValue) {
  132. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  133. if (FixupOffset & 0xff000000) {
  134. Asm.getContext().reportError(Fixup.getLoc(),
  135. "can not encode offset '0x" +
  136. utohexstr(FixupOffset) +
  137. "' in resulting scattered relocation.");
  138. return;
  139. }
  140. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  141. unsigned Type = MachO::ARM_RELOC_HALF;
  142. // See <reloc.h>.
  143. const MCSymbol *A = &Target.getSymA()->getSymbol();
  144. if (!A->getFragment()) {
  145. Asm.getContext().reportError(Fixup.getLoc(),
  146. "symbol '" + A->getName() +
  147. "' can not be undefined in a subtraction expression");
  148. return;
  149. }
  150. uint32_t Value = Writer->getSymbolAddress(*A, Layout);
  151. uint32_t Value2 = 0;
  152. uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
  153. FixedValue += SecAddr;
  154. if (const MCSymbolRefExpr *B = Target.getSymB()) {
  155. const MCSymbol *SB = &B->getSymbol();
  156. if (!SB->getFragment()) {
  157. Asm.getContext().reportError(Fixup.getLoc(),
  158. "symbol '" + B->getSymbol().getName() +
  159. "' can not be undefined in a subtraction expression");
  160. return;
  161. }
  162. // Select the appropriate difference relocation type.
  163. Type = MachO::ARM_RELOC_HALF_SECTDIFF;
  164. Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
  165. FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
  166. }
  167. // Relocations are written out in reverse order, so the PAIR comes first.
  168. // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
  169. //
  170. // For these two r_type relocations they always have a pair following them and
  171. // the r_length bits are used differently. The encoding of the r_length is as
  172. // follows:
  173. // low bit of r_length:
  174. // 0 - :lower16: for movw instructions
  175. // 1 - :upper16: for movt instructions
  176. // high bit of r_length:
  177. // 0 - arm instructions
  178. // 1 - thumb instructions
  179. // the other half of the relocated expression is in the following pair
  180. // relocation entry in the low 16 bits of r_address field.
  181. unsigned ThumbBit = 0;
  182. unsigned MovtBit = 0;
  183. switch (Fixup.getTargetKind()) {
  184. default: break;
  185. case ARM::fixup_arm_movt_hi16:
  186. MovtBit = 1;
  187. // The thumb bit shouldn't be set in the 'other-half' bit of the
  188. // relocation, but it will be set in FixedValue if the base symbol
  189. // is a thumb function. Clear it out here.
  190. if (Asm.isThumbFunc(A))
  191. FixedValue &= 0xfffffffe;
  192. break;
  193. case ARM::fixup_t2_movt_hi16:
  194. if (Asm.isThumbFunc(A))
  195. FixedValue &= 0xfffffffe;
  196. MovtBit = 1;
  197. [[fallthrough]];
  198. case ARM::fixup_t2_movw_lo16:
  199. ThumbBit = 1;
  200. break;
  201. }
  202. if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
  203. uint32_t OtherHalf = MovtBit
  204. ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
  205. MachO::any_relocation_info MRE;
  206. MRE.r_word0 = ((OtherHalf << 0) |
  207. (MachO::ARM_RELOC_PAIR << 24) |
  208. (MovtBit << 28) |
  209. (ThumbBit << 29) |
  210. (IsPCRel << 30) |
  211. MachO::R_SCATTERED);
  212. MRE.r_word1 = Value2;
  213. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  214. }
  215. MachO::any_relocation_info MRE;
  216. MRE.r_word0 = ((FixupOffset << 0) |
  217. (Type << 24) |
  218. (MovtBit << 28) |
  219. (ThumbBit << 29) |
  220. (IsPCRel << 30) |
  221. MachO::R_SCATTERED);
  222. MRE.r_word1 = Value;
  223. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  224. }
  225. void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
  226. const MCAssembler &Asm,
  227. const MCAsmLayout &Layout,
  228. const MCFragment *Fragment,
  229. const MCFixup &Fixup,
  230. MCValue Target,
  231. unsigned Type,
  232. unsigned Log2Size,
  233. uint64_t &FixedValue) {
  234. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  235. if (FixupOffset & 0xff000000) {
  236. Asm.getContext().reportError(Fixup.getLoc(),
  237. "can not encode offset '0x" +
  238. utohexstr(FixupOffset) +
  239. "' in resulting scattered relocation.");
  240. return;
  241. }
  242. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  243. // See <reloc.h>.
  244. const MCSymbol *A = &Target.getSymA()->getSymbol();
  245. if (!A->getFragment()) {
  246. Asm.getContext().reportError(Fixup.getLoc(),
  247. "symbol '" + A->getName() +
  248. "' can not be undefined in a subtraction expression");
  249. return;
  250. }
  251. uint32_t Value = Writer->getSymbolAddress(*A, Layout);
  252. uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
  253. FixedValue += SecAddr;
  254. uint32_t Value2 = 0;
  255. if (const MCSymbolRefExpr *B = Target.getSymB()) {
  256. assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
  257. const MCSymbol *SB = &B->getSymbol();
  258. if (!SB->getFragment()) {
  259. Asm.getContext().reportError(Fixup.getLoc(),
  260. "symbol '" + B->getSymbol().getName() +
  261. "' can not be undefined in a subtraction expression");
  262. return;
  263. }
  264. // Select the appropriate difference relocation type.
  265. Type = MachO::ARM_RELOC_SECTDIFF;
  266. Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
  267. FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
  268. }
  269. // Relocations are written out in reverse order, so the PAIR comes first.
  270. if (Type == MachO::ARM_RELOC_SECTDIFF ||
  271. Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
  272. MachO::any_relocation_info MRE;
  273. MRE.r_word0 = ((0 << 0) |
  274. (MachO::ARM_RELOC_PAIR << 24) |
  275. (Log2Size << 28) |
  276. (IsPCRel << 30) |
  277. MachO::R_SCATTERED);
  278. MRE.r_word1 = Value2;
  279. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  280. }
  281. MachO::any_relocation_info MRE;
  282. MRE.r_word0 = ((FixupOffset << 0) |
  283. (Type << 24) |
  284. (Log2Size << 28) |
  285. (IsPCRel << 30) |
  286. MachO::R_SCATTERED);
  287. MRE.r_word1 = Value;
  288. Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  289. }
  290. bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
  291. const MCAssembler &Asm,
  292. const MCFragment &Fragment,
  293. unsigned RelocType,
  294. const MCSymbol &S,
  295. uint64_t FixedValue) {
  296. // Most cases can be identified purely from the symbol.
  297. if (Writer->doesSymbolRequireExternRelocation(S))
  298. return true;
  299. int64_t Value = (int64_t)FixedValue; // The displacement is signed.
  300. int64_t Range;
  301. switch (RelocType) {
  302. default:
  303. return false;
  304. case MachO::ARM_RELOC_BR24:
  305. // An ARM call might be to a Thumb function, in which case the offset may
  306. // not be encodable in the instruction and we must use an external
  307. // relocation that explicitly mentions the function. Not a problem if it's
  308. // to a temporary "Lwhatever" symbol though, and in fact trying to use an
  309. // external relocation there causes more issues.
  310. if (!S.isTemporary())
  311. return true;
  312. // PC pre-adjustment of 8 for these instructions.
  313. Value -= 8;
  314. // ARM BL/BLX has a 25-bit offset.
  315. Range = 0x1ffffff;
  316. break;
  317. case MachO::ARM_THUMB_RELOC_BR22:
  318. // PC pre-adjustment of 4 for these instructions.
  319. Value -= 4;
  320. // Thumb BL/BLX has a 24-bit offset.
  321. Range = 0xffffff;
  322. }
  323. // BL/BLX also use external relocations when an internal relocation
  324. // would result in the target being out of range. This gives the linker
  325. // enough information to generate a branch island.
  326. Value += Writer->getSectionAddress(&S.getSection());
  327. Value -= Writer->getSectionAddress(Fragment.getParent());
  328. // If the resultant value would be out of range for an internal relocation,
  329. // use an external instead.
  330. if (Value > Range || Value < -(Range + 1))
  331. return true;
  332. return false;
  333. }
  334. void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer,
  335. MCAssembler &Asm,
  336. const MCAsmLayout &Layout,
  337. const MCFragment *Fragment,
  338. const MCFixup &Fixup, MCValue Target,
  339. uint64_t &FixedValue) {
  340. unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  341. unsigned Log2Size;
  342. unsigned RelocType = MachO::ARM_RELOC_VANILLA;
  343. if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
  344. // If we failed to get fixup kind info, it's because there's no legal
  345. // relocation type for the fixup kind. This happens when it's a fixup that's
  346. // expected to always be resolvable at assembly time and not have any
  347. // relocations needed.
  348. Asm.getContext().reportError(Fixup.getLoc(),
  349. "unsupported relocation on symbol");
  350. return;
  351. }
  352. // If this is a difference or a defined symbol plus an offset, then we need a
  353. // scattered relocation entry. Differences always require scattered
  354. // relocations.
  355. if (Target.getSymB()) {
  356. if (RelocType == MachO::ARM_RELOC_HALF)
  357. return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
  358. Fixup, Target, FixedValue);
  359. return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
  360. Target, RelocType, Log2Size,
  361. FixedValue);
  362. }
  363. // Get the symbol data, if any.
  364. const MCSymbol *A = nullptr;
  365. if (Target.getSymA())
  366. A = &Target.getSymA()->getSymbol();
  367. // FIXME: For other platforms, we need to use scattered relocations for
  368. // internal relocations with offsets. If this is an internal relocation with
  369. // an offset, it also needs a scattered relocation entry.
  370. //
  371. // Is this right for ARM?
  372. uint32_t Offset = Target.getConstant();
  373. if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
  374. Offset += 1 << Log2Size;
  375. if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
  376. RelocType != MachO::ARM_RELOC_HALF)
  377. return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
  378. Target, RelocType, Log2Size,
  379. FixedValue);
  380. // See <reloc.h>.
  381. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  382. unsigned Index = 0;
  383. unsigned Type = 0;
  384. const MCSymbol *RelSymbol = nullptr;
  385. if (Target.isAbsolute()) { // constant
  386. // FIXME!
  387. report_fatal_error("FIXME: relocations to absolute targets "
  388. "not yet implemented");
  389. } else {
  390. // Resolve constant variables.
  391. if (A->isVariable()) {
  392. int64_t Res;
  393. if (A->getVariableValue()->evaluateAsAbsolute(
  394. Res, Layout, Writer->getSectionAddressMap())) {
  395. FixedValue = Res;
  396. return;
  397. }
  398. }
  399. // Check whether we need an external or internal relocation.
  400. if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A,
  401. FixedValue)) {
  402. RelSymbol = A;
  403. // For external relocations, make sure to offset the fixup value to
  404. // compensate for the addend of the symbol address, if it was
  405. // undefined. This occurs with weak definitions, for example.
  406. if (!A->isUndefined())
  407. FixedValue -= Layout.getSymbolOffset(*A);
  408. } else {
  409. // The index is the section ordinal (1-based).
  410. const MCSection &Sec = A->getSection();
  411. Index = Sec.getOrdinal() + 1;
  412. FixedValue += Writer->getSectionAddress(&Sec);
  413. }
  414. if (IsPCRel)
  415. FixedValue -= Writer->getSectionAddress(Fragment->getParent());
  416. // The type is determined by the fixup kind.
  417. Type = RelocType;
  418. }
  419. // struct relocation_info (8 bytes)
  420. MachO::any_relocation_info MRE;
  421. MRE.r_word0 = FixupOffset;
  422. MRE.r_word1 =
  423. (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  424. // Even when it's not a scattered relocation, movw/movt always uses
  425. // a PAIR relocation.
  426. if (Type == MachO::ARM_RELOC_HALF) {
  427. // The entire addend is needed to correctly apply a relocation. One half is
  428. // extracted from the instruction itself, the other comes from this
  429. // PAIR. I.e. it's correct that we insert the high bits of the addend in the
  430. // MOVW case here. relocation entries.
  431. uint32_t Value = 0;
  432. switch (Fixup.getTargetKind()) {
  433. default: break;
  434. case ARM::fixup_arm_movw_lo16:
  435. case ARM::fixup_t2_movw_lo16:
  436. Value = (FixedValue >> 16) & 0xffff;
  437. break;
  438. case ARM::fixup_arm_movt_hi16:
  439. case ARM::fixup_t2_movt_hi16:
  440. Value = FixedValue & 0xffff;
  441. break;
  442. }
  443. MachO::any_relocation_info MREPair;
  444. MREPair.r_word0 = Value;
  445. MREPair.r_word1 = ((0xffffff << 0) |
  446. (Log2Size << 25) |
  447. (MachO::ARM_RELOC_PAIR << 28));
  448. Writer->addRelocation(nullptr, Fragment->getParent(), MREPair);
  449. }
  450. Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
  451. }
  452. std::unique_ptr<MCObjectTargetWriter>
  453. llvm::createARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
  454. uint32_t CPUSubtype) {
  455. return std::make_unique<ARMMachObjectWriter>(Is64Bit, CPUType, CPUSubtype);
  456. }