10b57cec5SDimitry Andric //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "MCTargetDesc/ARMBaseInfo.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/ARMFixupKinds.h" 110b57cec5SDimitry Andric #include "MCTargetDesc/ARMMCTargetDesc.h" 1281ad6265SDimitry Andric #include "llvm/ADT/StringExtras.h" 130b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 140b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCFixup.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCMachObjectWriter.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCSection.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCValue.h" 230b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace { 280b57cec5SDimitry Andric class ARMMachObjectWriter : public MCMachObjectTargetWriter { 29*0fca6ea1SDimitry Andric void recordARMScatteredRelocation(MachObjectWriter *Writer, 300b57cec5SDimitry Andric const MCAssembler &Asm, 310b57cec5SDimitry Andric const MCFragment *Fragment, 32*0fca6ea1SDimitry Andric const MCFixup &Fixup, MCValue Target, 33*0fca6ea1SDimitry Andric unsigned Type, unsigned Log2Size, 340b57cec5SDimitry Andric uint64_t &FixedValue); 35*0fca6ea1SDimitry Andric void recordARMScatteredHalfRelocation(MachObjectWriter *Writer, 360b57cec5SDimitry Andric const MCAssembler &Asm, 370b57cec5SDimitry Andric const MCFragment *Fragment, 380b57cec5SDimitry Andric const MCFixup &Fixup, MCValue Target, 390b57cec5SDimitry Andric uint64_t &FixedValue); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric bool requiresExternRelocation(MachObjectWriter *Writer, 420b57cec5SDimitry Andric const MCAssembler &Asm, 430b57cec5SDimitry Andric const MCFragment &Fragment, unsigned RelocType, 440b57cec5SDimitry Andric const MCSymbol &S, uint64_t FixedValue); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric public: 470b57cec5SDimitry Andric ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 480b57cec5SDimitry Andric : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 51*0fca6ea1SDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, 52*0fca6ea1SDimitry Andric MCValue Target, uint64_t &FixedValue) override; 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 570b57cec5SDimitry Andric unsigned &Log2Size) { 580b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_VANILLA); 590b57cec5SDimitry Andric Log2Size = ~0U; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric switch (Kind) { 620b57cec5SDimitry Andric default: 630b57cec5SDimitry Andric return false; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric case FK_Data_1: 660b57cec5SDimitry Andric Log2Size = llvm::Log2_32(1); 670b57cec5SDimitry Andric return true; 680b57cec5SDimitry Andric case FK_Data_2: 690b57cec5SDimitry Andric Log2Size = llvm::Log2_32(2); 700b57cec5SDimitry Andric return true; 710b57cec5SDimitry Andric case FK_Data_4: 720b57cec5SDimitry Andric Log2Size = llvm::Log2_32(4); 730b57cec5SDimitry Andric return true; 740b57cec5SDimitry Andric case FK_Data_8: 750b57cec5SDimitry Andric Log2Size = llvm::Log2_32(8); 7606c3fb27SDimitry Andric return false; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // These fixups are expected to always be resolvable at assembly time and 790b57cec5SDimitry Andric // have no relocations supported. 800b57cec5SDimitry Andric case ARM::fixup_arm_ldst_pcrel_12: 810b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10: 820b57cec5SDimitry Andric case ARM::fixup_arm_adr_pcrel_12: 830b57cec5SDimitry Andric case ARM::fixup_arm_thumb_br: 840b57cec5SDimitry Andric return false; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // Handle 24-bit branch kinds. 870b57cec5SDimitry Andric case ARM::fixup_arm_condbranch: 880b57cec5SDimitry Andric case ARM::fixup_arm_uncondbranch: 890b57cec5SDimitry Andric case ARM::fixup_arm_uncondbl: 900b57cec5SDimitry Andric case ARM::fixup_arm_condbl: 910b57cec5SDimitry Andric case ARM::fixup_arm_blx: 920b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_BR24); 930b57cec5SDimitry Andric // Report as 'long', even though that is not quite accurate. 940b57cec5SDimitry Andric Log2Size = llvm::Log2_32(4); 950b57cec5SDimitry Andric return true; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric case ARM::fixup_t2_uncondbranch: 980b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bl: 990b57cec5SDimitry Andric case ARM::fixup_arm_thumb_blx: 1000b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22); 1010b57cec5SDimitry Andric Log2Size = llvm::Log2_32(4); 1020b57cec5SDimitry Andric return true; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // For movw/movt r_type relocations they always have a pair following them and 1050b57cec5SDimitry Andric // the r_length bits are used differently. The encoding of the r_length is as 1060b57cec5SDimitry Andric // follows: 1070b57cec5SDimitry Andric // low bit of r_length: 1080b57cec5SDimitry Andric // 0 - :lower16: for movw instructions 1090b57cec5SDimitry Andric // 1 - :upper16: for movt instructions 1100b57cec5SDimitry Andric // high bit of r_length: 1110b57cec5SDimitry Andric // 0 - arm instructions 1120b57cec5SDimitry Andric // 1 - thumb instructions 1130b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16: 1140b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_HALF); 1150b57cec5SDimitry Andric Log2Size = 1; 1160b57cec5SDimitry Andric return true; 1170b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16: 1180b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_HALF); 1190b57cec5SDimitry Andric Log2Size = 3; 1200b57cec5SDimitry Andric return true; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric case ARM::fixup_arm_movw_lo16: 1230b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_HALF); 1240b57cec5SDimitry Andric Log2Size = 0; 1250b57cec5SDimitry Andric return true; 1260b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16: 1270b57cec5SDimitry Andric RelocType = unsigned(MachO::ARM_RELOC_HALF); 1280b57cec5SDimitry Andric Log2Size = 2; 1290b57cec5SDimitry Andric return true; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 133*0fca6ea1SDimitry Andric void ARMMachObjectWriter::recordARMScatteredHalfRelocation( 134*0fca6ea1SDimitry Andric MachObjectWriter *Writer, const MCAssembler &Asm, 135*0fca6ea1SDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 1360b57cec5SDimitry Andric uint64_t &FixedValue) { 137*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric if (FixupOffset & 0xff000000) { 1400b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 1410b57cec5SDimitry Andric "can not encode offset '0x" + 14281ad6265SDimitry Andric utohexstr(FixupOffset) + 1430b57cec5SDimitry Andric "' in resulting scattered relocation."); 1440b57cec5SDimitry Andric return; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 1480b57cec5SDimitry Andric unsigned Type = MachO::ARM_RELOC_HALF; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric // See <reloc.h>. 1510b57cec5SDimitry Andric const MCSymbol *A = &Target.getSymA()->getSymbol(); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric if (!A->getFragment()) { 1540b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 1550b57cec5SDimitry Andric "symbol '" + A->getName() + 1560b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 1570b57cec5SDimitry Andric return; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 160*0fca6ea1SDimitry Andric uint32_t Value = Writer->getSymbolAddress(*A, Asm); 1610b57cec5SDimitry Andric uint32_t Value2 = 0; 1620b57cec5SDimitry Andric uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 1630b57cec5SDimitry Andric FixedValue += SecAddr; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric if (const MCSymbolRefExpr *B = Target.getSymB()) { 1660b57cec5SDimitry Andric const MCSymbol *SB = &B->getSymbol(); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric if (!SB->getFragment()) { 1690b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 1700b57cec5SDimitry Andric "symbol '" + B->getSymbol().getName() + 1710b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 1720b57cec5SDimitry Andric return; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric // Select the appropriate difference relocation type. 1760b57cec5SDimitry Andric Type = MachO::ARM_RELOC_HALF_SECTDIFF; 177*0fca6ea1SDimitry Andric Value2 = Writer->getSymbolAddress(B->getSymbol(), Asm); 1780b57cec5SDimitry Andric FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric // Relocations are written out in reverse order, so the PAIR comes first. 1820b57cec5SDimitry Andric // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: 1830b57cec5SDimitry Andric // 1840b57cec5SDimitry Andric // For these two r_type relocations they always have a pair following them and 1850b57cec5SDimitry Andric // the r_length bits are used differently. The encoding of the r_length is as 1860b57cec5SDimitry Andric // follows: 1870b57cec5SDimitry Andric // low bit of r_length: 1880b57cec5SDimitry Andric // 0 - :lower16: for movw instructions 1890b57cec5SDimitry Andric // 1 - :upper16: for movt instructions 1900b57cec5SDimitry Andric // high bit of r_length: 1910b57cec5SDimitry Andric // 0 - arm instructions 1920b57cec5SDimitry Andric // 1 - thumb instructions 1930b57cec5SDimitry Andric // the other half of the relocated expression is in the following pair 1940b57cec5SDimitry Andric // relocation entry in the low 16 bits of r_address field. 1950b57cec5SDimitry Andric unsigned ThumbBit = 0; 1960b57cec5SDimitry Andric unsigned MovtBit = 0; 1978bcb0991SDimitry Andric switch (Fixup.getTargetKind()) { 1980b57cec5SDimitry Andric default: break; 1990b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16: 2000b57cec5SDimitry Andric MovtBit = 1; 2010b57cec5SDimitry Andric // The thumb bit shouldn't be set in the 'other-half' bit of the 2020b57cec5SDimitry Andric // relocation, but it will be set in FixedValue if the base symbol 2030b57cec5SDimitry Andric // is a thumb function. Clear it out here. 2040b57cec5SDimitry Andric if (Asm.isThumbFunc(A)) 2050b57cec5SDimitry Andric FixedValue &= 0xfffffffe; 2060b57cec5SDimitry Andric break; 2070b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16: 2080b57cec5SDimitry Andric if (Asm.isThumbFunc(A)) 2090b57cec5SDimitry Andric FixedValue &= 0xfffffffe; 2100b57cec5SDimitry Andric MovtBit = 1; 211bdd1243dSDimitry Andric [[fallthrough]]; 2120b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16: 2130b57cec5SDimitry Andric ThumbBit = 1; 2140b57cec5SDimitry Andric break; 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { 2180b57cec5SDimitry Andric uint32_t OtherHalf = MovtBit 2190b57cec5SDimitry Andric ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric MachO::any_relocation_info MRE; 2220b57cec5SDimitry Andric MRE.r_word0 = ((OtherHalf << 0) | 2230b57cec5SDimitry Andric (MachO::ARM_RELOC_PAIR << 24) | 2240b57cec5SDimitry Andric (MovtBit << 28) | 2250b57cec5SDimitry Andric (ThumbBit << 29) | 2260b57cec5SDimitry Andric (IsPCRel << 30) | 2270b57cec5SDimitry Andric MachO::R_SCATTERED); 2280b57cec5SDimitry Andric MRE.r_word1 = Value2; 2290b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric MachO::any_relocation_info MRE; 2330b57cec5SDimitry Andric MRE.r_word0 = ((FixupOffset << 0) | 2340b57cec5SDimitry Andric (Type << 24) | 2350b57cec5SDimitry Andric (MovtBit << 28) | 2360b57cec5SDimitry Andric (ThumbBit << 29) | 2370b57cec5SDimitry Andric (IsPCRel << 30) | 2380b57cec5SDimitry Andric MachO::R_SCATTERED); 2390b57cec5SDimitry Andric MRE.r_word1 = Value; 2400b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 243*0fca6ea1SDimitry Andric void ARMMachObjectWriter::recordARMScatteredRelocation( 244*0fca6ea1SDimitry Andric MachObjectWriter *Writer, const MCAssembler &Asm, 245*0fca6ea1SDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 246*0fca6ea1SDimitry Andric unsigned Type, unsigned Log2Size, uint64_t &FixedValue) { 247*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric if (FixupOffset & 0xff000000) { 2500b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 2510b57cec5SDimitry Andric "can not encode offset '0x" + 25281ad6265SDimitry Andric utohexstr(FixupOffset) + 2530b57cec5SDimitry Andric "' in resulting scattered relocation."); 2540b57cec5SDimitry Andric return; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric // See <reloc.h>. 2600b57cec5SDimitry Andric const MCSymbol *A = &Target.getSymA()->getSymbol(); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric if (!A->getFragment()) { 2630b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 2640b57cec5SDimitry Andric "symbol '" + A->getName() + 2650b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 2660b57cec5SDimitry Andric return; 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 269*0fca6ea1SDimitry Andric uint32_t Value = Writer->getSymbolAddress(*A, Asm); 2700b57cec5SDimitry Andric uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 2710b57cec5SDimitry Andric FixedValue += SecAddr; 2720b57cec5SDimitry Andric uint32_t Value2 = 0; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric if (const MCSymbolRefExpr *B = Target.getSymB()) { 2750b57cec5SDimitry Andric assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols"); 2760b57cec5SDimitry Andric const MCSymbol *SB = &B->getSymbol(); 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric if (!SB->getFragment()) { 2790b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 2800b57cec5SDimitry Andric "symbol '" + B->getSymbol().getName() + 2810b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 2820b57cec5SDimitry Andric return; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric // Select the appropriate difference relocation type. 2860b57cec5SDimitry Andric Type = MachO::ARM_RELOC_SECTDIFF; 287*0fca6ea1SDimitry Andric Value2 = Writer->getSymbolAddress(B->getSymbol(), Asm); 2880b57cec5SDimitry Andric FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric // Relocations are written out in reverse order, so the PAIR comes first. 2920b57cec5SDimitry Andric if (Type == MachO::ARM_RELOC_SECTDIFF || 2930b57cec5SDimitry Andric Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) { 2940b57cec5SDimitry Andric MachO::any_relocation_info MRE; 2950b57cec5SDimitry Andric MRE.r_word0 = ((0 << 0) | 2960b57cec5SDimitry Andric (MachO::ARM_RELOC_PAIR << 24) | 2970b57cec5SDimitry Andric (Log2Size << 28) | 2980b57cec5SDimitry Andric (IsPCRel << 30) | 2990b57cec5SDimitry Andric MachO::R_SCATTERED); 3000b57cec5SDimitry Andric MRE.r_word1 = Value2; 3010b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric MachO::any_relocation_info MRE; 3050b57cec5SDimitry Andric MRE.r_word0 = ((FixupOffset << 0) | 3060b57cec5SDimitry Andric (Type << 24) | 3070b57cec5SDimitry Andric (Log2Size << 28) | 3080b57cec5SDimitry Andric (IsPCRel << 30) | 3090b57cec5SDimitry Andric MachO::R_SCATTERED); 3100b57cec5SDimitry Andric MRE.r_word1 = Value; 3110b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 3150b57cec5SDimitry Andric const MCAssembler &Asm, 3160b57cec5SDimitry Andric const MCFragment &Fragment, 3170b57cec5SDimitry Andric unsigned RelocType, 3180b57cec5SDimitry Andric const MCSymbol &S, 3190b57cec5SDimitry Andric uint64_t FixedValue) { 3200b57cec5SDimitry Andric // Most cases can be identified purely from the symbol. 3210b57cec5SDimitry Andric if (Writer->doesSymbolRequireExternRelocation(S)) 3220b57cec5SDimitry Andric return true; 3230b57cec5SDimitry Andric int64_t Value = (int64_t)FixedValue; // The displacement is signed. 3240b57cec5SDimitry Andric int64_t Range; 3250b57cec5SDimitry Andric switch (RelocType) { 3260b57cec5SDimitry Andric default: 3270b57cec5SDimitry Andric return false; 3280b57cec5SDimitry Andric case MachO::ARM_RELOC_BR24: 3290b57cec5SDimitry Andric // An ARM call might be to a Thumb function, in which case the offset may 3300b57cec5SDimitry Andric // not be encodable in the instruction and we must use an external 3310b57cec5SDimitry Andric // relocation that explicitly mentions the function. Not a problem if it's 3320b57cec5SDimitry Andric // to a temporary "Lwhatever" symbol though, and in fact trying to use an 3330b57cec5SDimitry Andric // external relocation there causes more issues. 3340b57cec5SDimitry Andric if (!S.isTemporary()) 3350b57cec5SDimitry Andric return true; 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // PC pre-adjustment of 8 for these instructions. 3380b57cec5SDimitry Andric Value -= 8; 3390b57cec5SDimitry Andric // ARM BL/BLX has a 25-bit offset. 3400b57cec5SDimitry Andric Range = 0x1ffffff; 3410b57cec5SDimitry Andric break; 3420b57cec5SDimitry Andric case MachO::ARM_THUMB_RELOC_BR22: 3430b57cec5SDimitry Andric // PC pre-adjustment of 4 for these instructions. 3440b57cec5SDimitry Andric Value -= 4; 3450b57cec5SDimitry Andric // Thumb BL/BLX has a 24-bit offset. 3460b57cec5SDimitry Andric Range = 0xffffff; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric // BL/BLX also use external relocations when an internal relocation 3490b57cec5SDimitry Andric // would result in the target being out of range. This gives the linker 3500b57cec5SDimitry Andric // enough information to generate a branch island. 3510b57cec5SDimitry Andric Value += Writer->getSectionAddress(&S.getSection()); 3520b57cec5SDimitry Andric Value -= Writer->getSectionAddress(Fragment.getParent()); 3530b57cec5SDimitry Andric // If the resultant value would be out of range for an internal relocation, 3540b57cec5SDimitry Andric // use an external instead. 3550b57cec5SDimitry Andric if (Value > Range || Value < -(Range + 1)) 3560b57cec5SDimitry Andric return true; 3570b57cec5SDimitry Andric return false; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer, 3610b57cec5SDimitry Andric MCAssembler &Asm, 3620b57cec5SDimitry Andric const MCFragment *Fragment, 3630b57cec5SDimitry Andric const MCFixup &Fixup, MCValue Target, 3640b57cec5SDimitry Andric uint64_t &FixedValue) { 3650b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 3660b57cec5SDimitry Andric unsigned Log2Size; 3670b57cec5SDimitry Andric unsigned RelocType = MachO::ARM_RELOC_VANILLA; 3680b57cec5SDimitry Andric if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) { 3690b57cec5SDimitry Andric // If we failed to get fixup kind info, it's because there's no legal 3700b57cec5SDimitry Andric // relocation type for the fixup kind. This happens when it's a fixup that's 3710b57cec5SDimitry Andric // expected to always be resolvable at assembly time and not have any 3720b57cec5SDimitry Andric // relocations needed. 37306c3fb27SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), "unsupported relocation type"); 3740b57cec5SDimitry Andric return; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric // If this is a difference or a defined symbol plus an offset, then we need a 3780b57cec5SDimitry Andric // scattered relocation entry. Differences always require scattered 3790b57cec5SDimitry Andric // relocations. 3800b57cec5SDimitry Andric if (Target.getSymB()) { 3810b57cec5SDimitry Andric if (RelocType == MachO::ARM_RELOC_HALF) 382*0fca6ea1SDimitry Andric return recordARMScatteredHalfRelocation(Writer, Asm, Fragment, Fixup, 383*0fca6ea1SDimitry Andric Target, FixedValue); 384*0fca6ea1SDimitry Andric return recordARMScatteredRelocation(Writer, Asm, Fragment, Fixup, Target, 385*0fca6ea1SDimitry Andric RelocType, Log2Size, FixedValue); 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // Get the symbol data, if any. 3890b57cec5SDimitry Andric const MCSymbol *A = nullptr; 3900b57cec5SDimitry Andric if (Target.getSymA()) 3910b57cec5SDimitry Andric A = &Target.getSymA()->getSymbol(); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // FIXME: For other platforms, we need to use scattered relocations for 3940b57cec5SDimitry Andric // internal relocations with offsets. If this is an internal relocation with 3950b57cec5SDimitry Andric // an offset, it also needs a scattered relocation entry. 3960b57cec5SDimitry Andric // 3970b57cec5SDimitry Andric // Is this right for ARM? 3980b57cec5SDimitry Andric uint32_t Offset = Target.getConstant(); 3990b57cec5SDimitry Andric if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 4000b57cec5SDimitry Andric Offset += 1 << Log2Size; 4010b57cec5SDimitry Andric if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) && 4020b57cec5SDimitry Andric RelocType != MachO::ARM_RELOC_HALF) 403*0fca6ea1SDimitry Andric return recordARMScatteredRelocation(Writer, Asm, Fragment, Fixup, Target, 404*0fca6ea1SDimitry Andric RelocType, Log2Size, FixedValue); 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric // See <reloc.h>. 407*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 4080b57cec5SDimitry Andric unsigned Index = 0; 4090b57cec5SDimitry Andric unsigned Type = 0; 4100b57cec5SDimitry Andric const MCSymbol *RelSymbol = nullptr; 4110b57cec5SDimitry Andric 41206c3fb27SDimitry Andric if (!A) { // constant 41306c3fb27SDimitry Andric // FIXME! This is Target.isAbsolute() case as we check SymB above. We check 41406c3fb27SDimitry Andric // !A to ensure that null pointer isn't dereferenced and suppress static 41506c3fb27SDimitry Andric // analyzer warnings. 4160b57cec5SDimitry Andric report_fatal_error("FIXME: relocations to absolute targets " 4170b57cec5SDimitry Andric "not yet implemented"); 4180b57cec5SDimitry Andric } else { 4190b57cec5SDimitry Andric // Resolve constant variables. 4200b57cec5SDimitry Andric if (A->isVariable()) { 4210b57cec5SDimitry Andric int64_t Res; 4220b57cec5SDimitry Andric if (A->getVariableValue()->evaluateAsAbsolute( 423*0fca6ea1SDimitry Andric Res, Asm, Writer->getSectionAddressMap())) { 4240b57cec5SDimitry Andric FixedValue = Res; 4250b57cec5SDimitry Andric return; 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric // Check whether we need an external or internal relocation. 4300b57cec5SDimitry Andric if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A, 4310b57cec5SDimitry Andric FixedValue)) { 4320b57cec5SDimitry Andric RelSymbol = A; 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric // For external relocations, make sure to offset the fixup value to 4350b57cec5SDimitry Andric // compensate for the addend of the symbol address, if it was 4360b57cec5SDimitry Andric // undefined. This occurs with weak definitions, for example. 4370b57cec5SDimitry Andric if (!A->isUndefined()) 438*0fca6ea1SDimitry Andric FixedValue -= Asm.getSymbolOffset(*A); 4390b57cec5SDimitry Andric } else { 4400b57cec5SDimitry Andric // The index is the section ordinal (1-based). 4410b57cec5SDimitry Andric const MCSection &Sec = A->getSection(); 4420b57cec5SDimitry Andric Index = Sec.getOrdinal() + 1; 4430b57cec5SDimitry Andric FixedValue += Writer->getSectionAddress(&Sec); 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric if (IsPCRel) 4460b57cec5SDimitry Andric FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric // The type is determined by the fixup kind. 4490b57cec5SDimitry Andric Type = RelocType; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // struct relocation_info (8 bytes) 4530b57cec5SDimitry Andric MachO::any_relocation_info MRE; 4540b57cec5SDimitry Andric MRE.r_word0 = FixupOffset; 4550b57cec5SDimitry Andric MRE.r_word1 = 4560b57cec5SDimitry Andric (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric // Even when it's not a scattered relocation, movw/movt always uses 4590b57cec5SDimitry Andric // a PAIR relocation. 4600b57cec5SDimitry Andric if (Type == MachO::ARM_RELOC_HALF) { 4610b57cec5SDimitry Andric // The entire addend is needed to correctly apply a relocation. One half is 4620b57cec5SDimitry Andric // extracted from the instruction itself, the other comes from this 4630b57cec5SDimitry Andric // PAIR. I.e. it's correct that we insert the high bits of the addend in the 4640b57cec5SDimitry Andric // MOVW case here. relocation entries. 4650b57cec5SDimitry Andric uint32_t Value = 0; 4668bcb0991SDimitry Andric switch (Fixup.getTargetKind()) { 4670b57cec5SDimitry Andric default: break; 4680b57cec5SDimitry Andric case ARM::fixup_arm_movw_lo16: 4690b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16: 4700b57cec5SDimitry Andric Value = (FixedValue >> 16) & 0xffff; 4710b57cec5SDimitry Andric break; 4720b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16: 4730b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16: 4740b57cec5SDimitry Andric Value = FixedValue & 0xffff; 4750b57cec5SDimitry Andric break; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric MachO::any_relocation_info MREPair; 4780b57cec5SDimitry Andric MREPair.r_word0 = Value; 4790b57cec5SDimitry Andric MREPair.r_word1 = ((0xffffff << 0) | 4800b57cec5SDimitry Andric (Log2Size << 25) | 4810b57cec5SDimitry Andric (MachO::ARM_RELOC_PAIR << 28)); 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MREPair); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 4900b57cec5SDimitry Andric llvm::createARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, 4910b57cec5SDimitry Andric uint32_t CPUSubtype) { 4928bcb0991SDimitry Andric return std::make_unique<ARMMachObjectWriter>(Is64Bit, CPUType, CPUSubtype); 4930b57cec5SDimitry Andric } 494