LLVM API Documentation
00001 //===-- AArch64MachObjectWriter.cpp - ARM Mach Object Writer --------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #include "MCTargetDesc/AArch64FixupKinds.h" 00011 #include "MCTargetDesc/AArch64MCTargetDesc.h" 00012 #include "llvm/ADT/Twine.h" 00013 #include "llvm/MC/MCAsmLayout.h" 00014 #include "llvm/MC/MCAssembler.h" 00015 #include "llvm/MC/MCContext.h" 00016 #include "llvm/MC/MCExpr.h" 00017 #include "llvm/MC/MCFixup.h" 00018 #include "llvm/MC/MCMachObjectWriter.h" 00019 #include "llvm/MC/MCSectionMachO.h" 00020 #include "llvm/MC/MCValue.h" 00021 #include "llvm/Support/ErrorHandling.h" 00022 #include "llvm/Support/MachO.h" 00023 using namespace llvm; 00024 00025 namespace { 00026 class AArch64MachObjectWriter : public MCMachObjectTargetWriter { 00027 bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType, 00028 const MCSymbolRefExpr *Sym, 00029 unsigned &Log2Size, const MCAssembler &Asm); 00030 00031 public: 00032 AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype) 00033 : MCMachObjectTargetWriter(true /* is64Bit */, CPUType, CPUSubtype, 00034 /*UseAggressiveSymbolFolding=*/true) {} 00035 00036 void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, 00037 const MCAsmLayout &Layout, const MCFragment *Fragment, 00038 const MCFixup &Fixup, MCValue Target, 00039 uint64_t &FixedValue) override; 00040 }; 00041 } 00042 00043 bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo( 00044 const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym, 00045 unsigned &Log2Size, const MCAssembler &Asm) { 00046 RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED); 00047 Log2Size = ~0U; 00048 00049 switch ((unsigned)Fixup.getKind()) { 00050 default: 00051 return false; 00052 00053 case FK_Data_1: 00054 Log2Size = llvm::Log2_32(1); 00055 return true; 00056 case FK_Data_2: 00057 Log2Size = llvm::Log2_32(2); 00058 return true; 00059 case FK_Data_4: 00060 Log2Size = llvm::Log2_32(4); 00061 if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) 00062 RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); 00063 return true; 00064 case FK_Data_8: 00065 Log2Size = llvm::Log2_32(8); 00066 if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) 00067 RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); 00068 return true; 00069 case AArch64::fixup_aarch64_add_imm12: 00070 case AArch64::fixup_aarch64_ldst_imm12_scale1: 00071 case AArch64::fixup_aarch64_ldst_imm12_scale2: 00072 case AArch64::fixup_aarch64_ldst_imm12_scale4: 00073 case AArch64::fixup_aarch64_ldst_imm12_scale8: 00074 case AArch64::fixup_aarch64_ldst_imm12_scale16: 00075 Log2Size = llvm::Log2_32(4); 00076 switch (Sym->getKind()) { 00077 default: 00078 llvm_unreachable("Unexpected symbol reference variant kind!"); 00079 case MCSymbolRefExpr::VK_PAGEOFF: 00080 RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12); 00081 return true; 00082 case MCSymbolRefExpr::VK_GOTPAGEOFF: 00083 RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12); 00084 return true; 00085 case MCSymbolRefExpr::VK_TLVPPAGEOFF: 00086 RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12); 00087 return true; 00088 } 00089 case AArch64::fixup_aarch64_pcrel_adrp_imm21: 00090 Log2Size = llvm::Log2_32(4); 00091 // This encompasses the relocation for the whole 21-bit value. 00092 switch (Sym->getKind()) { 00093 default: 00094 Asm.getContext().FatalError(Fixup.getLoc(), 00095 "ADR/ADRP relocations must be GOT relative"); 00096 case MCSymbolRefExpr::VK_PAGE: 00097 RelocType = unsigned(MachO::ARM64_RELOC_PAGE21); 00098 return true; 00099 case MCSymbolRefExpr::VK_GOTPAGE: 00100 RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21); 00101 return true; 00102 case MCSymbolRefExpr::VK_TLVPPAGE: 00103 RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21); 00104 return true; 00105 } 00106 return true; 00107 case AArch64::fixup_aarch64_pcrel_branch26: 00108 case AArch64::fixup_aarch64_pcrel_call26: 00109 Log2Size = llvm::Log2_32(4); 00110 RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26); 00111 return true; 00112 } 00113 } 00114 00115 void AArch64MachObjectWriter::RecordRelocation( 00116 MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, 00117 const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 00118 uint64_t &FixedValue) { 00119 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 00120 00121 // See <reloc.h>. 00122 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment); 00123 unsigned Log2Size = 0; 00124 int64_t Value = 0; 00125 unsigned Index = 0; 00126 unsigned IsExtern = 0; 00127 unsigned Type = 0; 00128 unsigned Kind = Fixup.getKind(); 00129 00130 FixupOffset += Fixup.getOffset(); 00131 00132 // AArch64 pcrel relocation addends do not include the section offset. 00133 if (IsPCRel) 00134 FixedValue += FixupOffset; 00135 00136 // ADRP fixups use relocations for the whole symbol value and only 00137 // put the addend in the instruction itself. Clear out any value the 00138 // generic code figured out from the sybmol definition. 00139 if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21) 00140 FixedValue = 0; 00141 00142 // imm19 relocations are for conditional branches, which require 00143 // assembler local symbols. If we got here, that's not what we have, 00144 // so complain loudly. 00145 if (Kind == AArch64::fixup_aarch64_pcrel_branch19) { 00146 Asm.getContext().FatalError(Fixup.getLoc(), 00147 "conditional branch requires assembler-local" 00148 " label. '" + 00149 Target.getSymA()->getSymbol().getName() + 00150 "' is external."); 00151 return; 00152 } 00153 00154 // 14-bit branch relocations should only target internal labels, and so 00155 // should never get here. 00156 if (Kind == AArch64::fixup_aarch64_pcrel_branch14) { 00157 Asm.getContext().FatalError(Fixup.getLoc(), 00158 "Invalid relocation on conditional branch!"); 00159 return; 00160 } 00161 00162 if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size, 00163 Asm)) { 00164 Asm.getContext().FatalError(Fixup.getLoc(), "unknown AArch64 fixup kind!"); 00165 return; 00166 } 00167 00168 Value = Target.getConstant(); 00169 00170 if (Target.isAbsolute()) { // constant 00171 // FIXME: Should this always be extern? 00172 // SymbolNum of 0 indicates the absolute section. 00173 Type = MachO::ARM64_RELOC_UNSIGNED; 00174 Index = 0; 00175 00176 if (IsPCRel) { 00177 IsExtern = 1; 00178 Asm.getContext().FatalError(Fixup.getLoc(), 00179 "PC relative absolute relocation!"); 00180 00181 // FIXME: x86_64 sets the type to a branch reloc here. Should we do 00182 // something similar? 00183 } 00184 } else if (Target.getSymB()) { // A - B + constant 00185 const MCSymbol *A = &Target.getSymA()->getSymbol(); 00186 const MCSymbolData &A_SD = Asm.getSymbolData(*A); 00187 const MCSymbolData *A_Base = Asm.getAtom(&A_SD); 00188 00189 const MCSymbol *B = &Target.getSymB()->getSymbol(); 00190 const MCSymbolData &B_SD = Asm.getSymbolData(*B); 00191 const MCSymbolData *B_Base = Asm.getAtom(&B_SD); 00192 00193 // Check for "_foo@got - .", which comes through here as: 00194 // Ltmp0: 00195 // ... _foo@got - Ltmp0 00196 if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT && 00197 Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None && 00198 Layout.getSymbolOffset(&B_SD) == 00199 Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) { 00200 // SymB is the PC, so use a PC-rel pointer-to-GOT relocation. 00201 Index = A_Base->getIndex(); 00202 IsExtern = 1; 00203 Type = MachO::ARM64_RELOC_POINTER_TO_GOT; 00204 IsPCRel = 1; 00205 MachO::any_relocation_info MRE; 00206 MRE.r_word0 = FixupOffset; 00207 MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | 00208 (IsExtern << 27) | (Type << 28)); 00209 Writer->addRelocation(Fragment->getParent(), MRE); 00210 return; 00211 } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || 00212 Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) 00213 // Otherwise, neither symbol can be modified. 00214 Asm.getContext().FatalError(Fixup.getLoc(), 00215 "unsupported relocation of modified symbol"); 00216 00217 // We don't support PCrel relocations of differences. 00218 if (IsPCRel) 00219 Asm.getContext().FatalError(Fixup.getLoc(), 00220 "unsupported pc-relative relocation of " 00221 "difference"); 00222 00223 // AArch64 always uses external relocations. If there is no symbol to use as 00224 // a base address (a local symbol with no preceding non-local symbol), 00225 // error out. 00226 // 00227 // FIXME: We should probably just synthesize an external symbol and use 00228 // that. 00229 if (!A_Base) 00230 Asm.getContext().FatalError( 00231 Fixup.getLoc(), 00232 "unsupported relocation of local symbol '" + A->getName() + 00233 "'. Must have non-local symbol earlier in section."); 00234 if (!B_Base) 00235 Asm.getContext().FatalError( 00236 Fixup.getLoc(), 00237 "unsupported relocation of local symbol '" + B->getName() + 00238 "'. Must have non-local symbol earlier in section."); 00239 00240 if (A_Base == B_Base && A_Base) 00241 Asm.getContext().FatalError(Fixup.getLoc(), 00242 "unsupported relocation with identical base"); 00243 00244 Value += (!A_SD.getFragment() ? 0 00245 : Writer->getSymbolAddress(&A_SD, Layout)) - 00246 (!A_Base || !A_Base->getFragment() 00247 ? 0 00248 : Writer->getSymbolAddress(A_Base, Layout)); 00249 Value -= (!B_SD.getFragment() ? 0 00250 : Writer->getSymbolAddress(&B_SD, Layout)) - 00251 (!B_Base || !B_Base->getFragment() 00252 ? 0 00253 : Writer->getSymbolAddress(B_Base, Layout)); 00254 00255 Index = A_Base->getIndex(); 00256 IsExtern = 1; 00257 Type = MachO::ARM64_RELOC_UNSIGNED; 00258 00259 MachO::any_relocation_info MRE; 00260 MRE.r_word0 = FixupOffset; 00261 MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | 00262 (IsExtern << 27) | (Type << 28)); 00263 Writer->addRelocation(Fragment->getParent(), MRE); 00264 00265 Index = B_Base->getIndex(); 00266 IsExtern = 1; 00267 Type = MachO::ARM64_RELOC_SUBTRACTOR; 00268 } else { // A + constant 00269 const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); 00270 const MCSymbolData &SD = Asm.getSymbolData(*Symbol); 00271 const MCSymbolData *Base = Asm.getAtom(&SD); 00272 const MCSectionMachO &Section = static_cast<const MCSectionMachO &>( 00273 Fragment->getParent()->getSection()); 00274 00275 // If the symbol is a variable and we weren't able to get a Base for it 00276 // (i.e., it's not in the symbol table associated with a section) resolve 00277 // the relocation based its expansion instead. 00278 if (Symbol->isVariable() && !Base) { 00279 // If the evaluation is an absolute value, just use that directly 00280 // to keep things easy. 00281 int64_t Res; 00282 if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute( 00283 Res, Layout, Writer->getSectionAddressMap())) { 00284 FixedValue = Res; 00285 return; 00286 } 00287 00288 // FIXME: Will the Target we already have ever have any data in it 00289 // we need to preserve and merge with the new Target? How about 00290 // the FixedValue? 00291 if (!Symbol->getVariableValue()->EvaluateAsRelocatable(Target, &Layout, 00292 &Fixup)) 00293 Asm.getContext().FatalError(Fixup.getLoc(), 00294 "unable to resolve variable '" + 00295 Symbol->getName() + "'"); 00296 return RecordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 00297 FixedValue); 00298 } 00299 00300 // Relocations inside debug sections always use local relocations when 00301 // possible. This seems to be done because the debugger doesn't fully 00302 // understand relocation entries and expects to find values that 00303 // have already been fixed up. 00304 if (Symbol->isInSection()) { 00305 if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) 00306 Base = nullptr; 00307 } 00308 00309 // AArch64 uses external relocations as much as possible. For debug 00310 // sections, and for pointer-sized relocations (.quad), we allow section 00311 // relocations. It's code sections that run into trouble. 00312 if (Base) { 00313 Index = Base->getIndex(); 00314 IsExtern = 1; 00315 00316 // Add the local offset, if needed. 00317 if (Base != &SD) 00318 Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); 00319 } else if (Symbol->isInSection()) { 00320 // Pointer-sized relocations can use a local relocation. Otherwise, 00321 // we have to be in a debug info section. 00322 if (!Section.hasAttribute(MachO::S_ATTR_DEBUG) && Log2Size != 3) 00323 Asm.getContext().FatalError( 00324 Fixup.getLoc(), 00325 "unsupported relocation of local symbol '" + Symbol->getName() + 00326 "'. Must have non-local symbol earlier in section."); 00327 // Adjust the relocation to be section-relative. 00328 // The index is the section ordinal (1-based). 00329 const MCSectionData &SymSD = 00330 Asm.getSectionData(SD.getSymbol().getSection()); 00331 Index = SymSD.getOrdinal() + 1; 00332 IsExtern = 0; 00333 Value += Writer->getSymbolAddress(&SD, Layout); 00334 00335 if (IsPCRel) 00336 Value -= Writer->getFragmentAddress(Fragment, Layout) + 00337 Fixup.getOffset() + (1ULL << Log2Size); 00338 } else { 00339 // Resolve constant variables. 00340 if (SD.getSymbol().isVariable()) { 00341 int64_t Res; 00342 if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute( 00343 Res, Layout, Writer->getSectionAddressMap())) { 00344 FixedValue = Res; 00345 return; 00346 } 00347 } 00348 Asm.getContext().FatalError(Fixup.getLoc(), 00349 "unsupported relocation of variable '" + 00350 Symbol->getName() + "'"); 00351 } 00352 } 00353 00354 // If the relocation kind is Branch26, Page21, or Pageoff12, any addend 00355 // is represented via an Addend relocation, not encoded directly into 00356 // the instruction. 00357 if ((Type == MachO::ARM64_RELOC_BRANCH26 || 00358 Type == MachO::ARM64_RELOC_PAGE21 || 00359 Type == MachO::ARM64_RELOC_PAGEOFF12) && 00360 Value) { 00361 assert((Value & 0xff000000) == 0 && "Added relocation out of range!"); 00362 00363 MachO::any_relocation_info MRE; 00364 MRE.r_word0 = FixupOffset; 00365 MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | 00366 (IsExtern << 27) | (Type << 28)); 00367 Writer->addRelocation(Fragment->getParent(), MRE); 00368 00369 // Now set up the Addend relocation. 00370 Type = MachO::ARM64_RELOC_ADDEND; 00371 Index = Value; 00372 IsPCRel = 0; 00373 Log2Size = 2; 00374 IsExtern = 0; 00375 00376 // Put zero into the instruction itself. The addend is in the relocation. 00377 Value = 0; 00378 } 00379 00380 // If there's any addend left to handle, encode it in the instruction. 00381 FixedValue = Value; 00382 00383 // struct relocation_info (8 bytes) 00384 MachO::any_relocation_info MRE; 00385 MRE.r_word0 = FixupOffset; 00386 MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | 00387 (IsExtern << 27) | (Type << 28)); 00388 Writer->addRelocation(Fragment->getParent(), MRE); 00389 } 00390 00391 MCObjectWriter *llvm::createAArch64MachObjectWriter(raw_ostream &OS, 00392 uint32_t CPUType, 00393 uint32_t CPUSubtype) { 00394 return createMachObjectWriter( 00395 new AArch64MachObjectWriter(CPUType, CPUSubtype), OS, 00396 /*IsLittleEndian=*/true); 00397 }