1226584Sdim//===-- X86MachObjectWriter.cpp - X86 Mach-O Writer -----------------------===// 2226584Sdim// 3226584Sdim// The LLVM Compiler Infrastructure 4226584Sdim// 5226584Sdim// This file is distributed under the University of Illinois Open Source 6226584Sdim// License. See LICENSE.TXT for details. 7226584Sdim// 8226584Sdim//===----------------------------------------------------------------------===// 9226584Sdim 10249423Sdim#include "MCTargetDesc/X86MCTargetDesc.h" 11226584Sdim#include "MCTargetDesc/X86FixupKinds.h" 12249423Sdim#include "llvm/ADT/Twine.h" 13249423Sdim#include "llvm/MC/MCAsmLayout.h" 14226584Sdim#include "llvm/MC/MCAssembler.h" 15243830Sdim#include "llvm/MC/MCContext.h" 16226584Sdim#include "llvm/MC/MCMachObjectWriter.h" 17226584Sdim#include "llvm/MC/MCSectionMachO.h" 18226584Sdim#include "llvm/MC/MCValue.h" 19226584Sdim#include "llvm/Support/ErrorHandling.h" 20243830Sdim#include "llvm/Support/Format.h" 21263508Sdim#include "llvm/Support/MachO.h" 22226584Sdim 23226584Sdimusing namespace llvm; 24226584Sdim 25226584Sdimnamespace { 26226584Sdimclass X86MachObjectWriter : public MCMachObjectTargetWriter { 27243830Sdim bool RecordScatteredRelocation(MachObjectWriter *Writer, 28226584Sdim const MCAssembler &Asm, 29226584Sdim const MCAsmLayout &Layout, 30226584Sdim const MCFragment *Fragment, 31226584Sdim const MCFixup &Fixup, 32226584Sdim MCValue Target, 33226584Sdim unsigned Log2Size, 34226584Sdim uint64_t &FixedValue); 35226584Sdim void RecordTLVPRelocation(MachObjectWriter *Writer, 36226584Sdim const MCAssembler &Asm, 37226584Sdim const MCAsmLayout &Layout, 38226584Sdim const MCFragment *Fragment, 39226584Sdim const MCFixup &Fixup, 40226584Sdim MCValue Target, 41226584Sdim uint64_t &FixedValue); 42226584Sdim 43226584Sdim void RecordX86Relocation(MachObjectWriter *Writer, 44226584Sdim const MCAssembler &Asm, 45226584Sdim const MCAsmLayout &Layout, 46226584Sdim const MCFragment *Fragment, 47226584Sdim const MCFixup &Fixup, 48226584Sdim MCValue Target, 49226584Sdim uint64_t &FixedValue); 50226584Sdim void RecordX86_64Relocation(MachObjectWriter *Writer, 51226584Sdim const MCAssembler &Asm, 52226584Sdim const MCAsmLayout &Layout, 53226584Sdim const MCFragment *Fragment, 54226584Sdim const MCFixup &Fixup, 55226584Sdim MCValue Target, 56226584Sdim uint64_t &FixedValue); 57226584Sdimpublic: 58226584Sdim X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, 59226584Sdim uint32_t CPUSubtype) 60226584Sdim : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, 61226584Sdim /*UseAggressiveSymbolFolding=*/Is64Bit) {} 62226584Sdim 63226584Sdim void RecordRelocation(MachObjectWriter *Writer, 64226584Sdim const MCAssembler &Asm, const MCAsmLayout &Layout, 65226584Sdim const MCFragment *Fragment, const MCFixup &Fixup, 66226584Sdim MCValue Target, uint64_t &FixedValue) { 67226584Sdim if (Writer->is64Bit()) 68226584Sdim RecordX86_64Relocation(Writer, Asm, Layout, Fragment, Fixup, Target, 69226584Sdim FixedValue); 70226584Sdim else 71226584Sdim RecordX86Relocation(Writer, Asm, Layout, Fragment, Fixup, Target, 72226584Sdim FixedValue); 73226584Sdim } 74226584Sdim}; 75226584Sdim} 76226584Sdim 77226584Sdimstatic bool isFixupKindRIPRel(unsigned Kind) { 78226584Sdim return Kind == X86::reloc_riprel_4byte || 79226584Sdim Kind == X86::reloc_riprel_4byte_movq_load; 80226584Sdim} 81226584Sdim 82226584Sdimstatic unsigned getFixupKindLog2Size(unsigned Kind) { 83226584Sdim switch (Kind) { 84226584Sdim default: 85226584Sdim llvm_unreachable("invalid fixup kind!"); 86226584Sdim case FK_PCRel_1: 87226584Sdim case FK_Data_1: return 0; 88226584Sdim case FK_PCRel_2: 89226584Sdim case FK_Data_2: return 1; 90226584Sdim case FK_PCRel_4: 91226584Sdim // FIXME: Remove these!!! 92226584Sdim case X86::reloc_riprel_4byte: 93226584Sdim case X86::reloc_riprel_4byte_movq_load: 94226584Sdim case X86::reloc_signed_4byte: 95226584Sdim case FK_Data_4: return 2; 96226584Sdim case FK_Data_8: return 3; 97226584Sdim } 98226584Sdim} 99226584Sdim 100226584Sdimvoid X86MachObjectWriter::RecordX86_64Relocation(MachObjectWriter *Writer, 101226584Sdim const MCAssembler &Asm, 102226584Sdim const MCAsmLayout &Layout, 103226584Sdim const MCFragment *Fragment, 104226584Sdim const MCFixup &Fixup, 105226584Sdim MCValue Target, 106226584Sdim uint64_t &FixedValue) { 107226584Sdim unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 108226584Sdim unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); 109226584Sdim unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 110226584Sdim 111226584Sdim // See <reloc.h>. 112226584Sdim uint32_t FixupOffset = 113226584Sdim Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 114226584Sdim uint32_t FixupAddress = 115226584Sdim Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); 116226584Sdim int64_t Value = 0; 117226584Sdim unsigned Index = 0; 118226584Sdim unsigned IsExtern = 0; 119226584Sdim unsigned Type = 0; 120226584Sdim 121226584Sdim Value = Target.getConstant(); 122226584Sdim 123226584Sdim if (IsPCRel) { 124226584Sdim // Compensate for the relocation offset, Darwin x86_64 relocations only have 125226584Sdim // the addend and appear to have attempted to define it to be the actual 126226584Sdim // expression addend without the PCrel bias. However, instructions with data 127226584Sdim // following the relocation are not accommodated for (see comment below 128226584Sdim // regarding SIGNED{1,2,4}), so it isn't exactly that either. 129226584Sdim Value += 1LL << Log2Size; 130226584Sdim } 131226584Sdim 132226584Sdim if (Target.isAbsolute()) { // constant 133226584Sdim // SymbolNum of 0 indicates the absolute section. 134263508Sdim Type = MachO::X86_64_RELOC_UNSIGNED; 135226584Sdim Index = 0; 136226584Sdim 137226584Sdim // FIXME: I believe this is broken, I don't think the linker can understand 138226584Sdim // it. I think it would require a local relocation, but I'm not sure if that 139226584Sdim // would work either. The official way to get an absolute PCrel relocation 140226584Sdim // is to use an absolute symbol (which we don't support yet). 141226584Sdim if (IsPCRel) { 142226584Sdim IsExtern = 1; 143263508Sdim Type = MachO::X86_64_RELOC_BRANCH; 144226584Sdim } 145226584Sdim } else if (Target.getSymB()) { // A - B + constant 146226584Sdim const MCSymbol *A = &Target.getSymA()->getSymbol(); 147263508Sdim if (A->isTemporary()) 148263508Sdim A = &A->AliasedSymbol(); 149226584Sdim MCSymbolData &A_SD = Asm.getSymbolData(*A); 150226584Sdim const MCSymbolData *A_Base = Asm.getAtom(&A_SD); 151226584Sdim 152226584Sdim const MCSymbol *B = &Target.getSymB()->getSymbol(); 153263508Sdim if (B->isTemporary()) 154263508Sdim B = &B->AliasedSymbol(); 155226584Sdim MCSymbolData &B_SD = Asm.getSymbolData(*B); 156226584Sdim const MCSymbolData *B_Base = Asm.getAtom(&B_SD); 157226584Sdim 158226584Sdim // Neither symbol can be modified. 159226584Sdim if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || 160226584Sdim Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) 161263508Sdim report_fatal_error("unsupported relocation of modified symbol", false); 162226584Sdim 163226584Sdim // We don't support PCrel relocations of differences. Darwin 'as' doesn't 164226584Sdim // implement most of these correctly. 165226584Sdim if (IsPCRel) 166263508Sdim report_fatal_error("unsupported pc-relative relocation of difference", 167263508Sdim false); 168226584Sdim 169226584Sdim // The support for the situation where one or both of the symbols would 170226584Sdim // require a local relocation is handled just like if the symbols were 171226584Sdim // external. This is certainly used in the case of debug sections where the 172226584Sdim // section has only temporary symbols and thus the symbols don't have base 173226584Sdim // symbols. This is encoded using the section ordinal and non-extern 174226584Sdim // relocation entries. 175226584Sdim 176226584Sdim // Darwin 'as' doesn't emit correct relocations for this (it ends up with a 177226584Sdim // single SIGNED relocation); reject it for now. Except the case where both 178226584Sdim // symbols don't have a base, equal but both NULL. 179226584Sdim if (A_Base == B_Base && A_Base) 180263508Sdim report_fatal_error("unsupported relocation with identical base", false); 181226584Sdim 182263508Sdim // A subtraction expression where both symbols are undefined is a 183263508Sdim // non-relocatable expression. 184263508Sdim if (A->isUndefined() && B->isUndefined()) 185263508Sdim report_fatal_error("unsupported relocation with subtraction expression", 186263508Sdim false); 187263508Sdim 188226584Sdim Value += Writer->getSymbolAddress(&A_SD, Layout) - 189226584Sdim (A_Base == NULL ? 0 : Writer->getSymbolAddress(A_Base, Layout)); 190226584Sdim Value -= Writer->getSymbolAddress(&B_SD, Layout) - 191226584Sdim (B_Base == NULL ? 0 : Writer->getSymbolAddress(B_Base, Layout)); 192226584Sdim 193226584Sdim if (A_Base) { 194226584Sdim Index = A_Base->getIndex(); 195226584Sdim IsExtern = 1; 196226584Sdim } 197226584Sdim else { 198226584Sdim Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; 199226584Sdim IsExtern = 0; 200226584Sdim } 201263508Sdim Type = MachO::X86_64_RELOC_UNSIGNED; 202226584Sdim 203263508Sdim MachO::any_relocation_info MRE; 204263508Sdim MRE.r_word0 = FixupOffset; 205263508Sdim MRE.r_word1 = ((Index << 0) | 206263508Sdim (IsPCRel << 24) | 207263508Sdim (Log2Size << 25) | 208263508Sdim (IsExtern << 27) | 209263508Sdim (Type << 28)); 210226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 211226584Sdim 212226584Sdim if (B_Base) { 213226584Sdim Index = B_Base->getIndex(); 214226584Sdim IsExtern = 1; 215226584Sdim } 216226584Sdim else { 217226584Sdim Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; 218226584Sdim IsExtern = 0; 219226584Sdim } 220263508Sdim Type = MachO::X86_64_RELOC_SUBTRACTOR; 221226584Sdim } else { 222226584Sdim const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); 223226584Sdim MCSymbolData &SD = Asm.getSymbolData(*Symbol); 224226584Sdim const MCSymbolData *Base = Asm.getAtom(&SD); 225226584Sdim 226226584Sdim // Relocations inside debug sections always use local relocations when 227226584Sdim // possible. This seems to be done because the debugger doesn't fully 228226584Sdim // understand x86_64 relocation entries, and expects to find values that 229226584Sdim // have already been fixed up. 230226584Sdim if (Symbol->isInSection()) { 231226584Sdim const MCSectionMachO &Section = static_cast<const MCSectionMachO&>( 232226584Sdim Fragment->getParent()->getSection()); 233226584Sdim if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG)) 234226584Sdim Base = 0; 235226584Sdim } 236226584Sdim 237226584Sdim // x86_64 almost always uses external relocations, except when there is no 238226584Sdim // symbol to use as a base address (a local symbol with no preceding 239226584Sdim // non-local symbol). 240226584Sdim if (Base) { 241226584Sdim Index = Base->getIndex(); 242226584Sdim IsExtern = 1; 243226584Sdim 244226584Sdim // Add the local offset, if needed. 245226584Sdim if (Base != &SD) 246226584Sdim Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); 247226584Sdim } else if (Symbol->isInSection() && !Symbol->isVariable()) { 248226584Sdim // The index is the section ordinal (1-based). 249226584Sdim Index = SD.getFragment()->getParent()->getOrdinal() + 1; 250226584Sdim IsExtern = 0; 251226584Sdim Value += Writer->getSymbolAddress(&SD, Layout); 252226584Sdim 253226584Sdim if (IsPCRel) 254226584Sdim Value -= FixupAddress + (1 << Log2Size); 255226584Sdim } else if (Symbol->isVariable()) { 256226584Sdim const MCExpr *Value = Symbol->getVariableValue(); 257226584Sdim int64_t Res; 258226584Sdim bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, 259226584Sdim Writer->getSectionAddressMap()); 260226584Sdim if (isAbs) { 261226584Sdim FixedValue = Res; 262226584Sdim return; 263226584Sdim } else { 264226584Sdim report_fatal_error("unsupported relocation of variable '" + 265263508Sdim Symbol->getName() + "'", false); 266226584Sdim } 267226584Sdim } else { 268226584Sdim report_fatal_error("unsupported relocation of undefined symbol '" + 269263508Sdim Symbol->getName() + "'", false); 270226584Sdim } 271226584Sdim 272226584Sdim MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); 273226584Sdim if (IsPCRel) { 274226584Sdim if (IsRIPRel) { 275226584Sdim if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { 276226584Sdim // x86_64 distinguishes movq foo@GOTPCREL so that the linker can 277226584Sdim // rewrite the movq to an leaq at link time if the symbol ends up in 278226584Sdim // the same linkage unit. 279226584Sdim if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) 280263508Sdim Type = MachO::X86_64_RELOC_GOT_LOAD; 281226584Sdim else 282263508Sdim Type = MachO::X86_64_RELOC_GOT; 283226584Sdim } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { 284263508Sdim Type = MachO::X86_64_RELOC_TLV; 285226584Sdim } else if (Modifier != MCSymbolRefExpr::VK_None) { 286263508Sdim report_fatal_error("unsupported symbol modifier in relocation", 287263508Sdim false); 288226584Sdim } else { 289263508Sdim Type = MachO::X86_64_RELOC_SIGNED; 290226584Sdim 291226584Sdim // The Darwin x86_64 relocation format has a problem where it cannot 292226584Sdim // encode an address (L<foo> + <constant>) which is outside the atom 293226584Sdim // containing L<foo>. Generally, this shouldn't occur but it does 294226584Sdim // happen when we have a RIPrel instruction with data following the 295226584Sdim // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel 296226584Sdim // adjustment Darwin x86_64 uses, the offset is still negative and the 297226584Sdim // linker has no way to recognize this. 298226584Sdim // 299226584Sdim // To work around this, Darwin uses several special relocation types 300226584Sdim // to indicate the offsets. However, the specification or 301226584Sdim // implementation of these seems to also be incomplete; they should 302226584Sdim // adjust the addend as well based on the actual encoded instruction 303226584Sdim // (the additional bias), but instead appear to just look at the final 304226584Sdim // offset. 305226584Sdim switch (-(Target.getConstant() + (1LL << Log2Size))) { 306263508Sdim case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break; 307263508Sdim case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break; 308263508Sdim case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break; 309226584Sdim } 310226584Sdim } 311226584Sdim } else { 312226584Sdim if (Modifier != MCSymbolRefExpr::VK_None) 313226584Sdim report_fatal_error("unsupported symbol modifier in branch " 314263508Sdim "relocation", false); 315226584Sdim 316263508Sdim Type = MachO::X86_64_RELOC_BRANCH; 317226584Sdim } 318226584Sdim } else { 319226584Sdim if (Modifier == MCSymbolRefExpr::VK_GOT) { 320263508Sdim Type = MachO::X86_64_RELOC_GOT; 321226584Sdim } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { 322226584Sdim // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which 323226584Sdim // case all we do is set the PCrel bit in the relocation entry; this is 324226584Sdim // used with exception handling, for example. The source is required to 325226584Sdim // include any necessary offset directly. 326263508Sdim Type = MachO::X86_64_RELOC_GOT; 327226584Sdim IsPCRel = 1; 328226584Sdim } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { 329263508Sdim report_fatal_error("TLVP symbol modifier should have been rip-rel", 330263508Sdim false); 331226584Sdim } else if (Modifier != MCSymbolRefExpr::VK_None) 332263508Sdim report_fatal_error("unsupported symbol modifier in relocation", false); 333263508Sdim else { 334263508Sdim Type = MachO::X86_64_RELOC_UNSIGNED; 335263508Sdim unsigned Kind = Fixup.getKind(); 336263508Sdim if (Kind == X86::reloc_signed_4byte) 337263508Sdim report_fatal_error("32-bit absolute addressing is not supported in " 338263508Sdim "64-bit mode", false); 339263508Sdim } 340226584Sdim } 341226584Sdim } 342226584Sdim 343226584Sdim // x86_64 always writes custom values into the fixups. 344226584Sdim FixedValue = Value; 345226584Sdim 346226584Sdim // struct relocation_info (8 bytes) 347263508Sdim MachO::any_relocation_info MRE; 348263508Sdim MRE.r_word0 = FixupOffset; 349263508Sdim MRE.r_word1 = ((Index << 0) | 350263508Sdim (IsPCRel << 24) | 351263508Sdim (Log2Size << 25) | 352263508Sdim (IsExtern << 27) | 353263508Sdim (Type << 28)); 354226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 355226584Sdim} 356226584Sdim 357243830Sdimbool X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer, 358226584Sdim const MCAssembler &Asm, 359226584Sdim const MCAsmLayout &Layout, 360226584Sdim const MCFragment *Fragment, 361226584Sdim const MCFixup &Fixup, 362226584Sdim MCValue Target, 363226584Sdim unsigned Log2Size, 364226584Sdim uint64_t &FixedValue) { 365226584Sdim uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 366226584Sdim unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 367263508Sdim unsigned Type = MachO::GENERIC_RELOC_VANILLA; 368226584Sdim 369226584Sdim // See <reloc.h>. 370226584Sdim const MCSymbol *A = &Target.getSymA()->getSymbol(); 371226584Sdim MCSymbolData *A_SD = &Asm.getSymbolData(*A); 372226584Sdim 373226584Sdim if (!A_SD->getFragment()) 374226584Sdim report_fatal_error("symbol '" + A->getName() + 375263508Sdim "' can not be undefined in a subtraction expression", 376263508Sdim false); 377226584Sdim 378226584Sdim uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 379226584Sdim uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); 380226584Sdim FixedValue += SecAddr; 381226584Sdim uint32_t Value2 = 0; 382226584Sdim 383226584Sdim if (const MCSymbolRefExpr *B = Target.getSymB()) { 384226584Sdim MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 385226584Sdim 386226584Sdim if (!B_SD->getFragment()) 387226584Sdim report_fatal_error("symbol '" + B->getSymbol().getName() + 388263508Sdim "' can not be undefined in a subtraction expression", 389263508Sdim false); 390226584Sdim 391226584Sdim // Select the appropriate difference relocation type. 392226584Sdim // 393226584Sdim // Note that there is no longer any semantic difference between these two 394226584Sdim // relocation types from the linkers point of view, this is done solely for 395226584Sdim // pedantic compatibility with 'as'. 396263508Sdim Type = A_SD->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF : 397263508Sdim (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; 398226584Sdim Value2 = Writer->getSymbolAddress(B_SD, Layout); 399226584Sdim FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 400226584Sdim } 401226584Sdim 402226584Sdim // Relocations are written out in reverse order, so the PAIR comes first. 403263508Sdim if (Type == MachO::GENERIC_RELOC_SECTDIFF || 404263508Sdim Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) { 405243830Sdim // If the offset is too large to fit in a scattered relocation, 406243830Sdim // we're hosed. It's an unfortunate limitation of the MachO format. 407243830Sdim if (FixupOffset > 0xffffff) { 408243830Sdim char Buffer[32]; 409243830Sdim format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); 410243830Sdim Asm.getContext().FatalError(Fixup.getLoc(), 411243830Sdim Twine("Section too large, can't encode " 412243830Sdim "r_address (") + Buffer + 413243830Sdim ") into 24 bits of scattered " 414243830Sdim "relocation entry."); 415243830Sdim llvm_unreachable("fatal error returned?!"); 416243830Sdim } 417243830Sdim 418263508Sdim MachO::any_relocation_info MRE; 419263508Sdim MRE.r_word0 = ((0 << 0) | // r_address 420263508Sdim (MachO::GENERIC_RELOC_PAIR << 24) | // r_type 421263508Sdim (Log2Size << 28) | 422263508Sdim (IsPCRel << 30) | 423263508Sdim MachO::R_SCATTERED); 424263508Sdim MRE.r_word1 = Value2; 425226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 426243830Sdim } else { 427243830Sdim // If the offset is more than 24-bits, it won't fit in a scattered 428243830Sdim // relocation offset field, so we fall back to using a non-scattered 429243830Sdim // relocation. This is a bit risky, as if the offset reaches out of 430243830Sdim // the block and the linker is doing scattered loading on this 431243830Sdim // symbol, things can go badly. 432243830Sdim // 433243830Sdim // Required for 'as' compatibility. 434243830Sdim if (FixupOffset > 0xffffff) 435243830Sdim return false; 436226584Sdim } 437226584Sdim 438263508Sdim MachO::any_relocation_info MRE; 439263508Sdim MRE.r_word0 = ((FixupOffset << 0) | 440263508Sdim (Type << 24) | 441263508Sdim (Log2Size << 28) | 442263508Sdim (IsPCRel << 30) | 443263508Sdim MachO::R_SCATTERED); 444263508Sdim MRE.r_word1 = Value; 445226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 446243830Sdim return true; 447226584Sdim} 448226584Sdim 449226584Sdimvoid X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer, 450226584Sdim const MCAssembler &Asm, 451226584Sdim const MCAsmLayout &Layout, 452226584Sdim const MCFragment *Fragment, 453226584Sdim const MCFixup &Fixup, 454226584Sdim MCValue Target, 455226584Sdim uint64_t &FixedValue) { 456226584Sdim assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && 457226584Sdim !is64Bit() && 458226584Sdim "Should only be called with a 32-bit TLVP relocation!"); 459226584Sdim 460226584Sdim unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 461226584Sdim uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 462226584Sdim unsigned IsPCRel = 0; 463226584Sdim 464226584Sdim // Get the symbol data. 465226584Sdim MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 466226584Sdim unsigned Index = SD_A->getIndex(); 467226584Sdim 468226584Sdim // We're only going to have a second symbol in pic mode and it'll be a 469226584Sdim // subtraction from the picbase. For 32-bit pic the addend is the difference 470226584Sdim // between the picbase and the next address. For 32-bit static the addend is 471226584Sdim // zero. 472226584Sdim if (Target.getSymB()) { 473226584Sdim // If this is a subtraction then we're pcrel. 474226584Sdim uint32_t FixupAddress = 475226584Sdim Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); 476226584Sdim MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); 477226584Sdim IsPCRel = 1; 478226584Sdim FixedValue = (FixupAddress - Writer->getSymbolAddress(SD_B, Layout) + 479226584Sdim Target.getConstant()); 480226584Sdim FixedValue += 1ULL << Log2Size; 481226584Sdim } else { 482226584Sdim FixedValue = 0; 483226584Sdim } 484226584Sdim 485226584Sdim // struct relocation_info (8 bytes) 486263508Sdim MachO::any_relocation_info MRE; 487263508Sdim MRE.r_word0 = Value; 488263508Sdim MRE.r_word1 = ((Index << 0) | 489263508Sdim (IsPCRel << 24) | 490263508Sdim (Log2Size << 25) | 491263508Sdim (1 << 27) | // r_extern 492263508Sdim (MachO::GENERIC_RELOC_TLV << 28)); // r_type 493226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 494226584Sdim} 495226584Sdim 496226584Sdimvoid X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, 497226584Sdim const MCAssembler &Asm, 498226584Sdim const MCAsmLayout &Layout, 499226584Sdim const MCFragment *Fragment, 500226584Sdim const MCFixup &Fixup, 501226584Sdim MCValue Target, 502226584Sdim uint64_t &FixedValue) { 503226584Sdim unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 504226584Sdim unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 505226584Sdim 506226584Sdim // If this is a 32-bit TLVP reloc it's handled a bit differently. 507226584Sdim if (Target.getSymA() && 508226584Sdim Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { 509226584Sdim RecordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 510226584Sdim FixedValue); 511226584Sdim return; 512226584Sdim } 513226584Sdim 514226584Sdim // If this is a difference or a defined symbol plus an offset, then we need a 515226584Sdim // scattered relocation entry. Differences always require scattered 516226584Sdim // relocations. 517243830Sdim if (Target.getSymB()) { 518243830Sdim RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 519243830Sdim Target, Log2Size, FixedValue); 520243830Sdim return; 521243830Sdim } 522226584Sdim 523226584Sdim // Get the symbol data, if any. 524226584Sdim MCSymbolData *SD = 0; 525226584Sdim if (Target.getSymA()) 526226584Sdim SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 527226584Sdim 528226584Sdim // If this is an internal relocation with an offset, it also needs a scattered 529226584Sdim // relocation entry. 530226584Sdim uint32_t Offset = Target.getConstant(); 531226584Sdim if (IsPCRel) 532226584Sdim Offset += 1 << Log2Size; 533243830Sdim // Try to record the scattered relocation if needed. Fall back to non 534243830Sdim // scattered if necessary (see comments in RecordScatteredRelocation() 535243830Sdim // for details). 536243830Sdim if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD) && 537243830Sdim RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 538243830Sdim Target, Log2Size, FixedValue)) 539243830Sdim return; 540226584Sdim 541226584Sdim // See <reloc.h>. 542226584Sdim uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 543226584Sdim unsigned Index = 0; 544226584Sdim unsigned IsExtern = 0; 545226584Sdim unsigned Type = 0; 546226584Sdim 547226584Sdim if (Target.isAbsolute()) { // constant 548226584Sdim // SymbolNum of 0 indicates the absolute section. 549226584Sdim // 550226584Sdim // FIXME: Currently, these are never generated (see code below). I cannot 551226584Sdim // find a case where they are actually emitted. 552263508Sdim Type = MachO::GENERIC_RELOC_VANILLA; 553226584Sdim } else { 554226584Sdim // Resolve constant variables. 555226584Sdim if (SD->getSymbol().isVariable()) { 556226584Sdim int64_t Res; 557226584Sdim if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 558226584Sdim Res, Layout, Writer->getSectionAddressMap())) { 559226584Sdim FixedValue = Res; 560226584Sdim return; 561226584Sdim } 562226584Sdim } 563226584Sdim 564226584Sdim // Check whether we need an external or internal relocation. 565226584Sdim if (Writer->doesSymbolRequireExternRelocation(SD)) { 566226584Sdim IsExtern = 1; 567226584Sdim Index = SD->getIndex(); 568226584Sdim // For external relocations, make sure to offset the fixup value to 569226584Sdim // compensate for the addend of the symbol address, if it was 570226584Sdim // undefined. This occurs with weak definitions, for example. 571226584Sdim if (!SD->Symbol->isUndefined()) 572226584Sdim FixedValue -= Layout.getSymbolOffset(SD); 573226584Sdim } else { 574226584Sdim // The index is the section ordinal (1-based). 575226584Sdim const MCSectionData &SymSD = Asm.getSectionData( 576226584Sdim SD->getSymbol().getSection()); 577226584Sdim Index = SymSD.getOrdinal() + 1; 578226584Sdim FixedValue += Writer->getSectionAddress(&SymSD); 579226584Sdim } 580226584Sdim if (IsPCRel) 581226584Sdim FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 582226584Sdim 583263508Sdim Type = MachO::GENERIC_RELOC_VANILLA; 584226584Sdim } 585226584Sdim 586226584Sdim // struct relocation_info (8 bytes) 587263508Sdim MachO::any_relocation_info MRE; 588263508Sdim MRE.r_word0 = FixupOffset; 589263508Sdim MRE.r_word1 = ((Index << 0) | 590263508Sdim (IsPCRel << 24) | 591263508Sdim (Log2Size << 25) | 592263508Sdim (IsExtern << 27) | 593263508Sdim (Type << 28)); 594226584Sdim Writer->addRelocation(Fragment->getParent(), MRE); 595226584Sdim} 596226584Sdim 597226584SdimMCObjectWriter *llvm::createX86MachObjectWriter(raw_ostream &OS, 598226584Sdim bool Is64Bit, 599226584Sdim uint32_t CPUType, 600226584Sdim uint32_t CPUSubtype) { 601226584Sdim return createMachObjectWriter(new X86MachObjectWriter(Is64Bit, 602226584Sdim CPUType, 603226584Sdim CPUSubtype), 604226584Sdim OS, /*IsLittleEndian=*/true); 605226584Sdim} 606