X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FMC%2FMachObjectWriter.cpp;h=fbe068b58ec85dabd7f7a15a0e016c3af3be1c35;hp=a0f708244d7ea49b9584009ea4030712abf79ef1;hb=5b96b26eb76b012a18c5e30b3a179aaf3c9e3e27;hpb=640e948f09c56419b57dfb276d41e03060db6ad8 diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index a0f708244d7..fbe068b58ec 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -145,7 +145,8 @@ class MachObjectWriterImpl { RIT_Pair = 1, RIT_Difference = 2, RIT_PreboundLazyPointer = 3, - RIT_LocalDifference = 4 + RIT_LocalDifference = 4, + RIT_TLV = 5 }; /// X86_64 uses its own relocation types. @@ -158,7 +159,8 @@ class MachObjectWriterImpl { RIT_X86_64_Subtractor = 5, RIT_X86_64_Signed1 = 6, RIT_X86_64_Signed2 = 7, - RIT_X86_64_Signed4 = 8 + RIT_X86_64_Signed4 = 8, + RIT_X86_64_TLV = 9 }; /// MachSymbolData - Helper struct for containing some precomputed information @@ -170,8 +172,8 @@ class MachObjectWriterImpl { // Support lexicographic sorting. bool operator<(const MachSymbolData &RHS) const { - const std::string &Name = SymbolData->getSymbol().getName(); - return Name < RHS.SymbolData->getSymbol().getName(); + return SymbolData->getSymbol().getName() < + RHS.SymbolData->getSymbol().getName(); } }; @@ -185,6 +187,7 @@ class MachObjectWriterImpl { llvm::DenseMap > Relocations; + llvm::DenseMap IndirectSymBase; /// @} /// @name Symbol Table Data @@ -304,9 +307,7 @@ public: uint64_t Start = OS.tell(); (void) Start; - // FIXME: cast<> support! - const MCSectionMachO &Section = - static_cast(SD.getSection()); + const MCSectionMachO &Section = cast(SD.getSection()); WriteBytes(Section.getSectionName(), 16); WriteBytes(Section.getSegmentName(), 16); if (Is64Bit) { @@ -327,7 +328,7 @@ public: Write32(NumRelocations ? RelocationsStart : 0); Write32(NumRelocations); Write32(Flags); - Write32(0); // reserved1 + Write32(IndirectSymBase.lookup(&SD)); // reserved1 Write32(Section.getStubSize()); // reserved2 if (Is64Bit) Write32(0); // reserved3 @@ -471,14 +472,17 @@ public: void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCAsmFixup &Fixup, MCValue Target, + const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind); - unsigned IsRIPRel = isFixupKindRIPRel(Fixup.Kind); - unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); + unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); + unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // See . - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset; + uint32_t FixupOffset = + Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + uint32_t FixupAddress = + Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); int64_t Value = 0; unsigned Index = 0; unsigned IsExtern = 0; @@ -591,7 +595,7 @@ public: Value += Layout.getSymbolAddress(&SD); if (IsPCRel) - Value -= FixupOffset + (1 << Log2Size); + Value -= FixupAddress + (1 << Log2Size); } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'"); @@ -604,14 +608,37 @@ public: // x86_64 distinguishes movq foo@GOTPCREL so that the linker can // rewrite the movq to an leaq at link time if the symbol ends up in // the same linkage unit. - if (unsigned(Fixup.Kind) == X86::reloc_riprel_4byte_movq_load) + if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) Type = RIT_X86_64_GOTLoad; else Type = RIT_X86_64_GOT; - } else if (Modifier != MCSymbolRefExpr::VK_None) + } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { + Type = RIT_X86_64_TLV; + } else if (Modifier != MCSymbolRefExpr::VK_None) { report_fatal_error("unsupported symbol modifier in relocation"); - else + } else { Type = RIT_X86_64_Signed; + + // The Darwin x86_64 relocation format has a problem where it cannot + // encode an address (L + ) which is outside the atom + // containing L. Generally, this shouldn't occur but it does + // happen when we have a RIPrel instruction with data following the + // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel + // adjustment Darwin x86_64 uses, the offset is still negative and + // the linker has no way to recognize this. + // + // To work around this, Darwin uses several special relocation types + // to indicate the offsets. However, the specification or + // implementation of these seems to also be incomplete; they should + // adjust the addend as well based on the actual encoded instruction + // (the additional bias), but instead appear to just look at the + // final offset. + switch (-(Target.getConstant() + (1LL << Log2Size))) { + case 1: Type = RIT_X86_64_Signed1; break; + case 2: Type = RIT_X86_64_Signed2; break; + case 4: Type = RIT_X86_64_Signed4; break; + } + } } else { if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in branch " @@ -619,27 +646,6 @@ public: Type = RIT_X86_64_Branch; } - - // The Darwin x86_64 relocation format has a problem where it cannot - // encode an address (L + ) which is outside the atom - // containing L. Generally, this shouldn't occur but it does happen - // when we have a RIPrel instruction with data following the relocation - // entry (e.g., movb $012, L0(%rip)). Even with the PCrel adjustment - // Darwin x86_64 uses, the offset is still negative and the linker has - // no way to recognize this. - // - // To work around this, Darwin uses several special relocation types to - // indicate the offsets. However, the specification or implementation of - // these seems to also be incomplete; they should adjust the addend as - // well based on the actual encoded instruction (the additional bias), - // but instead appear to just look at the final offset. - if (IsRIPRel) { - switch (-(Target.getConstant() + (1LL << Log2Size))) { - case 1: Type = RIT_X86_64_Signed1; break; - case 2: Type = RIT_X86_64_Signed2; break; - case 4: Type = RIT_X86_64_Signed4; break; - } - } } else { if (Modifier == MCSymbolRefExpr::VK_GOT) { Type = RIT_X86_64_GOT; @@ -650,6 +656,8 @@ public: // required to include any necessary offset directly. Type = RIT_X86_64_GOT; IsPCRel = 1; + } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { + report_fatal_error("TLVP symbol modifier should have been rip-rel"); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation"); else @@ -674,11 +682,11 @@ public: void RecordScatteredRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCAsmFixup &Fixup, MCValue Target, + const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset; - unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind); - unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); unsigned Type = RIT_Vanilla; // See . @@ -730,17 +738,68 @@ public: Relocations[Fragment->getParent()].push_back(MRE); } + void RecordTLVPRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && + !Is64Bit && + "Should only be called with a 32-bit TLVP relocation!"); + + unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); + uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = 0; + + // Get the symbol data. + MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol()); + unsigned Index = SD_A->getIndex(); + + // We're only going to have a second symbol in pic mode and it'll be a + // subtraction from the picbase. For 32-bit pic the addend is the difference + // between the picbase and the next address. For 32-bit static the addend + // is zero. + if (Target.getSymB()) { + // If this is a subtraction then we're pcrel. + uint32_t FixupAddress = + Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); + MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); + IsPCRel = 1; + FixedValue = (FixupAddress - Layout.getSymbolAddress(SD_B) + + Target.getConstant()); + FixedValue += 1 << Log2Size; + } else { + FixedValue = 0; + } + + // struct relocation_info (8 bytes) + MachRelocationEntry MRE; + MRE.Word0 = Value; + MRE.Word1 = ((Index << 0) | + (IsPCRel << 24) | + (Log2Size << 25) | + (1 << 27) | // Extern + (RIT_TLV << 28)); // Type + Relocations[Fragment->getParent()].push_back(MRE); + } + void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCAsmFixup &Fixup, + const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { if (Is64Bit) { RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } - unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind); - unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); + unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); + // If this is a 32-bit TLVP reloc it's handled a bit differently. + if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { + RecordTLVPRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); + return; + } + // If this is a difference or a defined symbol plus an offset, then we need // a scattered relocation entry. // Differences always require scattered relocations. @@ -763,8 +822,7 @@ public: Target, FixedValue); // See . - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset; - uint32_t Value = 0; + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned Index = 0; unsigned IsExtern = 0; unsigned Type = 0; @@ -775,7 +833,6 @@ public: // FIXME: Currently, these are never generated (see code below). I cannot // find a case where they are actually emitted. Type = RIT_Vanilla; - Value = 0; } else { // Check whether we need an external or internal relocation. if (doesSymbolRequireExternRelocation(SD)) { @@ -786,11 +843,9 @@ public: // undefined. This occurs with weak definitions, for example. if (!SD->Symbol->isUndefined()) FixedValue -= Layout.getSymbolAddress(SD); - Value = 0; } else { // The index is the section ordinal (1-based). Index = SD->getFragment()->getParent()->getOrdinal() + 1; - Value = Layout.getSymbolAddress(SD); } Type = RIT_Vanilla; @@ -816,29 +871,37 @@ public: // FIXME: Revisit this when the dust settles. // Bind non lazy symbol pointers first. + unsigned IndirectIndex = 0; for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it) { - // FIXME: cast<> support! + ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { const MCSectionMachO &Section = - static_cast(it->SectionData->getSection()); + cast(it->SectionData->getSection()); if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) continue; + // Initialize the section indirect symbol base, if necessary. + if (!IndirectSymBase.count(it->SectionData)) + IndirectSymBase[it->SectionData] = IndirectIndex; + Asm.getOrCreateSymbolData(*it->Symbol); } // Then lazy symbol pointers and symbol stubs. + IndirectIndex = 0; for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it) { - // FIXME: cast<> support! + ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { const MCSectionMachO &Section = - static_cast(it->SectionData->getSection()); + cast(it->SectionData->getSection()); if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) continue; + // Initialize the section indirect symbol base, if necessary. + if (!IndirectSymBase.count(it->SectionData)) + IndirectSymBase[it->SectionData] = IndirectIndex; + // Set the symbol type to undefined lazy, but only on construction. // // FIXME: Do not hardcode. @@ -882,7 +945,7 @@ public: const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(it)) + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (!it->isExternal() && !Symbol.isUndefined()) @@ -918,7 +981,7 @@ public: const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(it)) + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (it->isExternal() || Symbol.isUndefined()) @@ -1152,7 +1215,7 @@ void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { void MachObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCAsmFixup &Fixup, MCValue Target, + const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { ((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue);