X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMachObjectWriter.cpp;h=61df5bb35c761b234c6d31628bf97bb9deee5a80;hb=cecbc3d28277ff4916326311cbf87335ed05d106;hp=e6232acbf0de3f3d6785924aae672deb8cb1797e;hpb=35b0657dea3f5dfee3b753a58c585edd22e3b45c;p=oota-llvm.git diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index e6232acbf0d..61df5bb35c7 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -11,10 +11,12 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MachO.h" @@ -26,15 +28,18 @@ #include using namespace llvm; +// FIXME: this has been copied from (or to) X86AsmBackend.cpp static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case X86::reloc_pcrel_1byte: case FK_Data_1: return 0; + case X86::reloc_pcrel_2byte: case FK_Data_2: return 1; case X86::reloc_pcrel_4byte: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: + case X86::reloc_signed_4byte: case FK_Data_4: return 2; case FK_Data_8: return 3; } @@ -45,6 +50,7 @@ static bool isFixupKindPCRel(unsigned Kind) { default: return false; case X86::reloc_pcrel_1byte: + case X86::reloc_pcrel_2byte: case X86::reloc_pcrel_4byte: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: @@ -57,6 +63,100 @@ static bool isFixupKindRIPRel(unsigned Kind) { Kind == X86::reloc_riprel_4byte_movq_load; } +static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { + // Undefined symbols are always extern. + if (SD->Symbol->isUndefined()) + return true; + + // References to weak definitions require external relocation entries; the + // definition may not always be the one in the same object file. + if (SD->getFlags() & SF_WeakDefinition) + return true; + + // Otherwise, we can use an internal relocation. + return false; +} + +static bool isScatteredFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + const MCSymbolData *BaseSymbol) { + // The effective fixup address is + // addr(atom(A)) + offset(A) + // - addr(atom(B)) - offset(B) + // - addr(BaseSymbol) + + // and the offsets are not relocatable, so the fixup is fully resolved when + // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0. + // + // Note that "false" is almost always conservatively correct (it means we emit + // a relocation which is unnecessary), except when it would force us to emit a + // relocation which the target cannot encode. + + const MCSymbolData *A_Base = 0, *B_Base = 0; + if (const MCSymbolRefExpr *A = Target.getSymA()) { + // Modified symbol references cannot be resolved. + if (A->getKind() != MCSymbolRefExpr::VK_None) + return false; + + A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol())); + if (!A_Base) + return false; + } + + if (const MCSymbolRefExpr *B = Target.getSymB()) { + // Modified symbol references cannot be resolved. + if (B->getKind() != MCSymbolRefExpr::VK_None) + return false; + + B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol())); + if (!B_Base) + return false; + } + + // If there is no base, A and B have to be the same atom for this fixup to be + // fully resolved. + if (!BaseSymbol) + return A_Base == B_Base; + + // Otherwise, B must be missing and A must be the base. + return !B_Base && BaseSymbol == A_Base; +} + +static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm, + const MCValue Target, + const MCSection *BaseSection) { + // The effective fixup address is + // addr(atom(A)) + offset(A) + // - addr(atom(B)) - offset(B) + // - addr() + + // and the offsets are not relocatable, so the fixup is fully resolved when + // addr(atom(A)) - addr(atom(B)) - addr()) == 0. + // + // The simple (Darwin, except on x86_64) way of dealing with this was to + // assume that any reference to a temporary symbol *must* be a temporary + // symbol in the same atom, unless the sections differ. Therefore, any PCrel + // relocation to a temporary symbol (in the same section) is fully + // resolved. This also works in conjunction with absolutized .set, which + // requires the compiler to use .set to absolutize the differences between + // symbols which the compiler knows to be assembly time constants, so we don't + // need to worry about considering symbol differences fully resolved. + + // Non-relative fixups are only resolved if constant. + if (!BaseSection) + return Target.isAbsolute(); + + // Otherwise, relative fixups are only resolved if not a difference and the + // target is a temporary in the same section. + if (Target.isAbsolute() || Target.getSymB()) + return false; + + const MCSymbol *A = &Target.getSymA()->getSymbol(); + if (!A->isTemporary() || !A->isInSection() || + &A->getSection() != BaseSection) + return false; + + return true; +} + namespace { class MachObjectWriterImpl { @@ -129,7 +229,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. @@ -142,7 +243,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 @@ -154,8 +256,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(); } }; @@ -169,6 +271,7 @@ class MachObjectWriterImpl { llvm::DenseMap > Relocations; + llvm::DenseMap IndirectSymBase; /// @} /// @name Symbol Table Data @@ -271,12 +374,14 @@ public: assert(OS.tell() - Start == SegmentLoadCommandSize); } - void WriteSection(const MCAssembler &Asm, const MCSectionData &SD, - uint64_t FileOffset, uint64_t RelocationsStart, - unsigned NumRelocations) { + void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCSectionData &SD, uint64_t FileOffset, + uint64_t RelocationsStart, unsigned NumRelocations) { + uint64_t SectionSize = Layout.getSectionSize(&SD); + // The offset is unused for virtual sections. if (Asm.getBackend().isVirtualSection(SD.getSection())) { - assert(SD.getFileSize() == 0 && "Invalid file size!"); + assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); FileOffset = 0; } @@ -286,17 +391,15 @@ 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) { - Write64(SD.getAddress()); // address - Write64(SD.getSize()); // size + Write64(Layout.getSectionAddress(&SD)); // address + Write64(SectionSize); // size } else { - Write32(SD.getAddress()); // address - Write32(SD.getSize()); // size + Write32(Layout.getSectionAddress(&SD)); // address + Write32(SectionSize); // size } Write32(FileOffset); @@ -309,7 +412,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 @@ -372,7 +475,7 @@ public: assert(OS.tell() - Start == DysymtabLoadCommandSize); } - void WriteNlist(MachSymbolData &MSD) { + void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) { MCSymbolData &Data = *MSD.SymbolData; const MCSymbol &Symbol = Data.getSymbol(); uint8_t Type = 0; @@ -401,9 +504,9 @@ public: // Compute the symbol address. if (Symbol.isDefined()) { if (Symbol.isAbsolute()) { - llvm_unreachable("FIXME: Not yet implemented!"); + Address = cast(Symbol.getVariableValue())->getValue(); } else { - Address = Data.getAddress(); + Address = Layout.getSymbolAddress(&Data); } } else if (Data.isCommon()) { // Common symbols are encoded with the size in the address @@ -415,7 +518,7 @@ public: unsigned Log2Size = Log2_32(Align); assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); if (Log2Size > 15) - llvm_report_error("invalid 'common' alignment '" + + report_fatal_error("invalid 'common' alignment '" + Twine(Align) + "'"); // FIXME: Keep this mask with the SymbolFlags enumeration. Flags = (Flags & 0xF0FF) | (Log2Size << 8); @@ -451,16 +554,19 @@ public: // - Input errors, where something cannot be correctly encoded. 'as' allows // these through in many cases. - void RecordX86_64Relocation(const MCAssembler &Asm, + 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 Address = Fragment->getOffset() + 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; @@ -474,7 +580,7 @@ public: // actual expression addend without the PCrel bias. However, instructions // with data following the relocation are not accomodated for (see comment // below regarding SIGNED{1,2,4}), so it isn't exactly that either. - Value += 1 << Log2Size; + Value += 1LL << Log2Size; } if (Target.isAbsolute()) { // constant @@ -503,33 +609,43 @@ public: // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) - llvm_report_error("unsupported relocation of modified symbol"); + report_fatal_error("unsupported relocation of modified symbol"); // We don't support PCrel relocations of differences. Darwin 'as' doesn't // implement most of these correctly. if (IsPCRel) - llvm_report_error("unsupported pc-relative relocation of difference"); + report_fatal_error("unsupported pc-relative relocation of difference"); - // We don't currently support any situation where one or both of the - // symbols would require a local relocation. This is almost certainly - // unused and may not be possible to encode correctly. - if (!A_Base || !B_Base) - llvm_report_error("unsupported local relocations in difference"); + // The support for the situation where one or both of the symbols would + // require a local relocation is handled just like if the symbols were + // external. This is certainly used in the case of debug sections where + // the section has only temporary symbols and thus the symbols don't have + // base symbols. This is encoded using the section ordinal and + // non-extern relocation entries. // Darwin 'as' doesn't emit correct relocations for this (it ends up with - // a single SIGNED relocation); reject it for now. - if (A_Base == B_Base) - llvm_report_error("unsupported relocation with identical base"); - - Value += A_SD.getAddress() - A_Base->getAddress(); - Value -= B_SD.getAddress() - B_Base->getAddress(); - - Index = A_Base->getIndex(); - IsExtern = 1; + // a single SIGNED relocation); reject it for now. Except the case where + // both symbols don't have a base, equal but both NULL. + if (A_Base == B_Base && A_Base) + report_fatal_error("unsupported relocation with identical base"); + + Value += Layout.getSymbolAddress(&A_SD) - + (A_Base == NULL ? 0 : Layout.getSymbolAddress(A_Base)); + Value -= Layout.getSymbolAddress(&B_SD) - + (B_Base == NULL ? 0 : Layout.getSymbolAddress(B_Base)); + + if (A_Base) { + Index = A_Base->getIndex(); + IsExtern = 1; + } + else { + Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } Type = RIT_X86_64_Unsigned; MachRelocationEntry MRE; - MRE.Word0 = Address; + MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | @@ -537,14 +653,31 @@ public: (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); - Index = B_Base->getIndex(); - IsExtern = 1; + if (B_Base) { + Index = B_Base->getIndex(); + IsExtern = 1; + } + else { + Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } Type = RIT_X86_64_Subtractor; } else { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); MCSymbolData &SD = Asm.getSymbolData(*Symbol); const MCSymbolData *Base = Asm.getAtom(&SD); + // Relocations inside debug sections always use local relocations when + // possible. This seems to be done because the debugger doesn't fully + // understand x86_64 relocation entries, and expects to find values that + // have already been fixed up. + if (Symbol->isInSection()) { + const MCSectionMachO &Section = static_cast( + Fragment->getParent()->getSection()); + if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG)) + Base = 0; + } + // x86_64 almost always uses external relocations, except when there is no // symbol to use as a base address (a local symbol with no preceeding // non-local symbol). @@ -554,22 +687,18 @@ public: // Add the local offset, if needed. if (Base != &SD) - Value += SD.getAddress() - Base->getAddress(); - } else { - // The index is the section ordinal. - // - // FIXME: O(N) - Index = 1; - MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); - for (; it != ie; ++it, ++Index) - if (&*it == SD.getFragment()->getParent()) - break; - assert(it != ie && "Unable to find section index!"); + Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); + } else if (Symbol->isInSection()) { + // The index is the section ordinal (1-based). + Index = SD.getFragment()->getParent()->getOrdinal() + 1; IsExtern = 0; - Value += SD.getAddress(); + Value += Layout.getSymbolAddress(&SD); if (IsPCRel) - Value -= Address + (1 << Log2Size); + Value -= FixupAddress + (1 << Log2Size); + } else { + report_fatal_error("unsupported relocation of undefined symbol '" + + Symbol->getName() + "'"); } MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); @@ -579,47 +708,58 @@ 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) - llvm_report_error("unsupported symbol modifier in relocation"); - else + } 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 { 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) - llvm_report_error("unsupported symbol modifier in branch " + report_fatal_error("unsupported symbol modifier in branch " "relocation"); 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() + (1 << 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) + if (Modifier == MCSymbolRefExpr::VK_GOT) { + Type = RIT_X86_64_GOT; + } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { + // GOTPCREL is allowed as a modifier on non-PCrel instructions, in + // which case all we do is set the PCrel bit in the relocation entry; + // this is used with exception handling, for example. The source is + // required to include any necessary offset directly. Type = RIT_X86_64_GOT; - else if (Modifier != MCSymbolRefExpr::VK_None) - llvm_report_error("unsupported symbol modifier in relocation"); + 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 Type = RIT_X86_64_Unsigned; } @@ -630,7 +770,7 @@ public: // struct relocation_info (8 bytes) MachRelocationEntry MRE; - MRE.Word0 = Address; + MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | @@ -640,12 +780,13 @@ 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 Address = Fragment->getOffset() + 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 . @@ -653,17 +794,17 @@ public: MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) - llvm_report_error("symbol '" + A->getName() + + report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); - uint32_t Value = A_SD->getAddress(); + uint32_t Value = Layout.getSymbolAddress(A_SD); uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) - llvm_report_error("symbol '" + B->getSymbol().getName() + + report_fatal_error("symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression"); // Select the appropriate difference relocation type. @@ -672,7 +813,7 @@ public: // relocation types from the linkers point of view, this is done solely // for pedantic compatibility with 'as'. Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference; - Value2 = B_SD->getAddress(); + Value2 = Layout.getSymbolAddress(B_SD); } // Relocations are written out in reverse order, so the PAIR comes first. @@ -688,41 +829,101 @@ public: } MachRelocationEntry MRE; - MRE.Word0 = ((Address << 0) | - (Type << 24) | - (Log2Size << 28) | - (IsPCRel << 30) | + MRE.Word0 = ((FixupOffset << 0) | + (Type << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | RF_Scattered); MRE.Word1 = Value; Relocations[Fragment->getParent()].push_back(MRE); } - void RecordRelocation(const MCAssembler &Asm, const MCFragment *Fragment, - const MCAsmFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { + 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 += 1ULL << 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 MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) { if (Is64Bit) { - RecordX86_64Relocation(Asm, Fragment, Fixup, Target, FixedValue); + 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() && + 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. + if (Target.getSymB()) + return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); + + // Get the symbol data, if any. + MCSymbolData *SD = 0; + if (Target.getSymA()) + SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); + + // If this is an internal relocation with an offset, it also needs a + // scattered relocation entry. uint32_t Offset = Target.getConstant(); if (IsPCRel) Offset += 1 << Log2Size; - if (Target.getSymB() || - (Target.getSymA() && !Target.getSymA()->getSymbol().isUndefined() && - Offset)) { - RecordScatteredRelocation(Asm, Fragment, Fixup, Target, FixedValue); - return; - } + if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) + return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); // See . - uint32_t Address = Fragment->getOffset() + Fixup.Offset; - uint32_t Value = 0; + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned Index = 0; unsigned IsExtern = 0; unsigned Type = 0; @@ -733,26 +934,19 @@ 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 { - const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); - MCSymbolData *SD = &Asm.getSymbolData(*Symbol); - - if (Symbol->isUndefined()) { + // Check whether we need an external or internal relocation. + if (doesSymbolRequireExternRelocation(SD)) { IsExtern = 1; Index = SD->getIndex(); - Value = 0; + // For external relocations, make sure to offset the fixup value to + // compensate for the addend of the symbol address, if it was + // undefined. This occurs with weak definitions, for example. + if (!SD->Symbol->isUndefined()) + FixedValue -= Layout.getSymbolAddress(SD); } else { - // The index is the section ordinal. - // - // FIXME: O(N) - Index = 1; - MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); - for (; it != ie; ++it, ++Index) - if (&*it == SD->getFragment()->getParent()) - break; - assert(it != ie && "Unable to find section index!"); - Value = SD->getAddress(); + // The index is the section ordinal (1-based). + Index = SD->getFragment()->getParent()->getOrdinal() + 1; } Type = RIT_Vanilla; @@ -760,7 +954,7 @@ public: // struct relocation_info (8 bytes) MachRelocationEntry MRE; - MRE.Word0 = Address; + MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | @@ -778,29 +972,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. @@ -844,7 +1046,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()) @@ -880,7 +1082,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()) @@ -934,7 +1136,37 @@ public: UndefinedSymbolData); } - void WriteObject(const MCAssembler &Asm) { + + bool IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const { + // If we are using scattered symbols, determine whether this value is + // actually resolved; scattering may cause atoms to move. + if (Asm.getBackend().hasScatteredSymbols()) { + if (Asm.getBackend().hasReliableSymbolDifference()) { + // If this is a PCrel relocation, find the base atom (identified by its + // symbol) that the fixup value is relative to. + const MCSymbolData *BaseSymbol = 0; + if (IsPCRel) { + BaseSymbol = DF->getAtom(); + if (!BaseSymbol) + return false; + } + + return isScatteredFixupFullyResolved(Asm, Target, BaseSymbol); + } else { + const MCSection *BaseSection = 0; + if (IsPCRel) + BaseSection = &DF->getParent()->getSection(); + + return isScatteredFixupFullyResolvedSimple(Asm, Target, BaseSection); + } + } + return true; + } + + void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and @@ -962,16 +1194,17 @@ public: for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData &SD = *it; + uint64_t Address = Layout.getSectionAddress(&SD); + uint64_t Size = Layout.getSectionSize(&SD); + uint64_t FileSize = Layout.getSectionFileSize(&SD); - VMSize = std::max(VMSize, SD.getAddress() + SD.getSize()); + VMSize = std::max(VMSize, Address + Size); if (Asm.getBackend().isVirtualSection(SD.getSection())) continue; - SectionDataSize = std::max(SectionDataSize, - SD.getAddress() + SD.getSize()); - SectionDataFileSize = std::max(SectionDataFileSize, - SD.getAddress() + SD.getFileSize()); + SectionDataSize = std::max(SectionDataSize, Address + Size); + SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); } // The section data is padded to 4 bytes. @@ -992,8 +1225,8 @@ public: ie = Asm.end(); it != ie; ++it) { std::vector &Relocs = Relocations[it]; unsigned NumRelocs = Relocs.size(); - uint64_t SectionStart = SectionDataStart + it->getAddress(); - WriteSection(Asm, *it, SectionStart, RelocTableEnd, NumRelocs); + uint64_t SectionStart = SectionDataStart + Layout.getSectionAddress(it); + WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * RelocationInfoSize; } @@ -1034,7 +1267,7 @@ public: // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - Asm.WriteSectionData(it, Writer); + Asm.WriteSectionData(it, Layout, Writer); // Write the extra padding. WriteZeros(SectionDataPadding); @@ -1080,11 +1313,11 @@ public: // Write the symbol table entries. for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) - WriteNlist(LocalSymbolData[i]); + WriteNlist(LocalSymbolData[i], Layout); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) - WriteNlist(ExternalSymbolData[i]); + WriteNlist(ExternalSymbolData[i], Layout); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) - WriteNlist(UndefinedSymbolData[i]); + WriteNlist(UndefinedSymbolData[i], Layout); // Write the string table. OS << StringTable.str(); @@ -1111,13 +1344,23 @@ 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, Fragment, Fixup, + ((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); } -void MachObjectWriter::WriteObject(const MCAssembler &Asm) { - ((MachObjectWriterImpl*) Impl)->WriteObject(Asm); +bool MachObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const { + return ((MachObjectWriterImpl*) Impl)->IsFixupFullyResolved(Asm, Target, + IsPCRel, DF); +} + +void MachObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + ((MachObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); }