uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: return cast<MCEncodedFragment>(F).getContents().size(); case MCFragment::FT_Fill: return cast<MCFillFragment>(F).getSize(); case MCFragment::FT_LEB: return cast<MCLEBFragment>(F).getContents().size(); case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); unsigned Offset = Layout.getFragmentOffset(&AF); unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); // If we are padding with nops, force the padding to be larger than the // minimum nop size. if (Size > 0 && AF.hasEmitNops()) { while (Size % getBackend().getMinimumNopSize()) Size += AF.getAlignment(); } if (Size > AF.getMaxBytesToEmit()) return 0; return Size; } case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); int64_t TargetLocation; if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, Layout)) report_fatal_error("expected assembly-time absolute expression"); // FIXME: We need a way to communicate this error. uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t Size = TargetLocation - FragmentOffset; if (Size < 0 || Size >= 0x40000000) report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + "' (at offset '" + Twine(FragmentOffset) + "')"); return Size; } case MCFragment::FT_Dwarf: return cast<MCDwarfLineAddrFragment>(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast<MCDwarfCallFrameFragment>(F).getContents().size(); } llvm_unreachable("invalid fragment kind"); }
uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment, const MCAsmLayout &Layout) { assert(Fragment != nullptr && "Fragment cannot be null"); MCFragment const *NextFragment = Fragment->getNextNode(); return NextFragment == nullptr ? Layout.getSectionAddressSize(Fragment->getParent()) : Layout.getFragmentOffset(NextFragment); }
// Simple getSymbolOffset helper for the non-varibale case. static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S, bool ReportError, uint64_t &Val) { if (!S.getFragment()) { if (ReportError) report_fatal_error("unable to evaluate offset to undefined symbol '" + S.getName() + "'"); return false; } Val = Layout.getFragmentOffset(S.getFragment()) + S.getOffset(); return true; }
void X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer, 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. const 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 = Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); const MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); IsPCRel = 1; FixedValue = (FixupAddress - Writer->getSymbolAddress(SD_B, Layout) + Target.getConstant()); FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = Value; MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (1 << 27) | // r_extern (MachO::GENERIC_RELOC_TLV << 28)); // r_type Writer->addRelocation(Fragment->getParent(), MRE); }
void SVMMemoryLayout::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { SVM::Fixups kind = (SVM::Fixups) Fixup.getKind(); switch (kind) { case SVM::fixup_fnstack: { /* * Function stack adjustment annotation. The adjustment amount is * stored in the first argument of a binary op. * (See SVMMCCodeEmitter::EncodeInstruction) * * We store this offset for later, in our FNStackMap, indexed * by the address of the FNStack pseudo-op itself. */ FNStackMap[std::make_pair(Fragment->getParent(), Layout.getFragmentOffset(Fragment))] = (int)Target.getConstant(); break; } default: { /* * All other fixups are applied later, in ApplyLateFixups(). * This is necessary because other fixup types can depend on * the FNStack values collected above. */ SVMLateFixup LF((MCFragment *) Fragment, Fixup, Target); LateFixupList.push_back(LF); // This gets OR'ed with the fixup later. Zero it. FixedValue = 0; break; } } }
bool X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, unsigned Log2Size, uint64_t &FixedValue) { uint64_t OriginalFixedValue = FixedValue; uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Type = MachO::GENERIC_RELOC_VANILLA; // See <reloc.h>. const MCSymbol *A = &Target.getSymA()->getSymbol(); const MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression", false); uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) report_fatal_error("symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression", false); // Select the appropriate difference relocation type. // // Note that there is no longer any semantic difference between these two // relocation types from the linkers point of view, this is done solely for // pedantic compatibility with 'as'. Type = A_SD->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; Value2 = Writer->getSymbolAddress(B_SD, Layout); FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); } // Relocations are written out in reverse order, so the PAIR comes first. if (Type == MachO::GENERIC_RELOC_SECTDIFF || Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) { // If the offset is too large to fit in a scattered relocation, // we're hosed. It's an unfortunate limitation of the MachO format. if (FixupOffset > 0xffffff) { char Buffer[32]; format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); Asm.getContext().FatalError(Fixup.getLoc(), Twine("Section too large, can't encode " "r_address (") + Buffer + ") into 24 bits of scattered " "relocation entry."); llvm_unreachable("fatal error returned?!"); } MachO::any_relocation_info MRE; MRE.r_word0 = ((0 << 0) | // r_address (MachO::GENERIC_RELOC_PAIR << 24) | // r_type (Log2Size << 28) | (IsPCRel << 30) | MachO::R_SCATTERED); MRE.r_word1 = Value2; Writer->addRelocation(nullptr, Fragment->getParent(), MRE); } else { // If the offset is more than 24-bits, it won't fit in a scattered // relocation offset field, so we fall back to using a non-scattered // relocation. This is a bit risky, as if the offset reaches out of // the block and the linker is doing scattered loading on this // symbol, things can go badly. // // Required for 'as' compatibility. if (FixupOffset > 0xffffff) { FixedValue = OriginalFixedValue; return false; } } MachO::any_relocation_info MRE; MRE.r_word0 = ((FixupOffset << 0) | (Type << 24) | (Log2Size << 28) | (IsPCRel << 30) | MachO::R_SCATTERED); MRE.r_word1 = Value; Writer->addRelocation(nullptr, Fragment->getParent(), MRE); return true; }
uint64_t MachObjectWriter::getFragmentAddress(const MCFragment *Fragment, const MCAsmLayout &Layout) const { return getSectionAddress(Fragment->getParent()) + Layout.getFragmentOffset(Fragment); }
void ARMMachObjectWriter:: RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Type = MachO::ARM_RELOC_HALF; // See <reloc.h>. const MCSymbol *A = &Target.getSymA()->getSymbol(); const MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) Asm.getContext().FatalError(Fixup.getLoc(), "symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); uint32_t Value2 = 0; uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); FixedValue += SecAddr; if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) Asm.getContext().FatalError(Fixup.getLoc(), "symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression"); // Select the appropriate difference relocation type. Type = MachO::ARM_RELOC_HALF_SECTDIFF; Value2 = Writer->getSymbolAddress(B_SD, Layout); FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); } // Relocations are written out in reverse order, so the PAIR comes first. // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: // // For these two r_type relocations they always have a pair following them and // the r_length bits are used differently. The encoding of the r_length is as // follows: // low bit of r_length: // 0 - :lower16: for movw instructions // 1 - :upper16: for movt instructions // high bit of r_length: // 0 - arm instructions // 1 - thumb instructions // the other half of the relocated expression is in the following pair // relocation entry in the low 16 bits of r_address field. unsigned ThumbBit = 0; unsigned MovtBit = 0; switch ((unsigned)Fixup.getKind()) { default: break; case ARM::fixup_arm_movt_hi16: MovtBit = 1; // The thumb bit shouldn't be set in the 'other-half' bit of the // relocation, but it will be set in FixedValue if the base symbol // is a thumb function. Clear it out here. if (Asm.isThumbFunc(A)) FixedValue &= 0xfffffffe; break; case ARM::fixup_t2_movt_hi16: if (Asm.isThumbFunc(A)) FixedValue &= 0xfffffffe; MovtBit = 1; // Fallthrough case ARM::fixup_t2_movw_lo16: ThumbBit = 1; break; } if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { uint32_t OtherHalf = MovtBit ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); MachO::any_relocation_info MRE; MRE.r_word0 = ((OtherHalf << 0) | (MachO::ARM_RELOC_PAIR << 24) | (MovtBit << 28) | (ThumbBit << 29) | (IsPCRel << 30) | MachO::R_SCATTERED); MRE.r_word1 = Value2; Writer->addRelocation(nullptr, Fragment->getParent(), MRE); }
void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Assign symbol and section indexes and offsets. Header.NumberOfSections = 0; DenseMap<COFFSection *, uint16_t> SectionIndices; for (sections::iterator i = Sections.begin(), e = Sections.end(); i != e; i++) { if (Layout.getSectionAddressSize((*i)->MCData) > 0) { size_t Number = ++Header.NumberOfSections; SectionIndices[*i] = Number; MakeSectionReal(**i, Number); } else { (*i)->Number = -1; } } Header.NumberOfSymbols = 0; for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { COFFSymbol *coff_symbol = *i; MCSymbolData const *SymbolData = coff_symbol->MCData; // Update section number & offset for symbols that have them. if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { assert(coff_symbol->Section != NULL); coff_symbol->Data.SectionNumber = coff_symbol->Section->Number; coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + SymbolData->Offset; } if (coff_symbol->should_keep()) { MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); // Update auxiliary symbol info. coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; } else coff_symbol->Index = -1; } // Fixup weak external references. for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { COFFSymbol *coff_symbol = *i; if (coff_symbol->Other != NULL) { assert(coff_symbol->Index != -1); assert(coff_symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!"); assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && "Symbol's aux symbol must be a Weak External!"); coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; } } // Fixup associative COMDAT sections. for (sections::iterator i = Sections.begin(), e = Sections.end(); i != e; i++) { if ((*i)->Symbol->Aux[0].Aux.SectionDefinition.Selection != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) continue; const MCSectionCOFF &MCSec = static_cast<const MCSectionCOFF &>( (*i)->MCData->getSection()); COFFSection *Assoc = SectionMap.lookup(MCSec.getAssocSection()); if (!Assoc) { report_fatal_error(Twine("Missing associated COMDAT section ") + MCSec.getAssocSection()->getSectionName() + " for section " + MCSec.getSectionName()); } // Skip this section if the associated section is unused. if (Assoc->Number == -1) continue; (*i)->Symbol->Aux[0].Aux.SectionDefinition.Number = SectionIndices[Assoc]; } // Assign file offsets to COFF object file structures. unsigned offset = 0; offset += COFF::HeaderSize; offset += COFF::SectionSize * Header.NumberOfSections; for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) { COFFSection *Sec = SectionMap[&i->getSection()]; if (Sec->Number == -1) continue; Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i); if (IsPhysicalSection(Sec)) { Sec->Header.PointerToRawData = offset; offset += Sec->Header.SizeOfRawData; } if (Sec->Relocations.size() > 0) { bool RelocationsOverflow = Sec->Relocations.size() >= 0xffff; if (RelocationsOverflow) { // Signal overflow by setting NumberOfSections to max value. Actual // size is found in reloc #0. Microsoft tools understand this. Sec->Header.NumberOfRelocations = 0xffff; } else { Sec->Header.NumberOfRelocations = Sec->Relocations.size(); } Sec->Header.PointerToRelocations = offset; if (RelocationsOverflow) { // Reloc #0 will contain actual count, so make room for it. offset += COFF::RelocationSize; } offset += COFF::RelocationSize * Sec->Relocations.size(); for (relocations::iterator cr = Sec->Relocations.begin(), er = Sec->Relocations.end(); cr != er; ++cr) { assert((*cr).Symb->Index != -1); (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; } } assert(Sec->Symbol->Aux.size() == 1 && "Section's symbol must have one aux!"); AuxSymbol &Aux = Sec->Symbol->Aux[0]; assert(Aux.AuxType == ATSectionDefinition && "Section's symbol's aux symbol must be a Section Definition!"); Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; Aux.Aux.SectionDefinition.NumberOfRelocations = Sec->Header.NumberOfRelocations; Aux.Aux.SectionDefinition.NumberOfLinenumbers = Sec->Header.NumberOfLineNumbers; } Header.PointerToSymbolTable = offset; Header.TimeDateStamp = sys::TimeValue::now().toEpochTime(); // Write it all to disk... WriteFileHeader(Header); { sections::iterator i, ie; MCAssembler::const_iterator j, je; for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) if ((*i)->Number != -1) { if ((*i)->Relocations.size() >= 0xffff) { (*i)->Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; } WriteSectionHeader((*i)->Header); } for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(), je = Asm.end(); (i != ie) && (j != je); ++i, ++j) { if ((*i)->Number == -1) continue; if ((*i)->Header.PointerToRawData != 0) { assert(OS.tell() == (*i)->Header.PointerToRawData && "Section::PointerToRawData is insane!"); Asm.writeSectionData(j, Layout); } if ((*i)->Relocations.size() > 0) { assert(OS.tell() == (*i)->Header.PointerToRelocations && "Section::PointerToRelocations is insane!"); if ((*i)->Relocations.size() >= 0xffff) { // In case of overflow, write actual relocation count as first // relocation. Including the synthetic reloc itself (+ 1). COFF::relocation r; r.VirtualAddress = (*i)->Relocations.size() + 1; r.SymbolTableIndex = 0; r.Type = 0; WriteRelocation(r); } for (relocations::const_iterator k = (*i)->Relocations.begin(), ke = (*i)->Relocations.end(); k != ke; k++) { WriteRelocation(k->Data); } } else assert((*i)->Header.PointerToRelocations == 0 && "Section::PointerToRelocations is insane!"); } } assert(OS.tell() == Header.PointerToSymbolTable && "Header::PointerToSymbolTable is insane!"); for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) if ((*i)->Index != -1) WriteSymbol(*i); OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); }
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); const MCSymbol &Symbol = Target.getSymA()->getSymbol(); const MCSymbol &A = Symbol.AliasedSymbol(); MCSymbolData &A_SD = Asm.getSymbolData(A); MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[&SectionData->getSection()]; COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; const MCSymbolRefExpr *SymA = Target.getSymA(); const MCSymbolRefExpr *SymB = Target.getSymB(); const bool CrossSection = SymB && &SymA->getSymbol().getSection() != &SymB->getSymbol().getSection(); if (Target.getSymB()) { const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); // Offset of the symbol in the section int64_t a = Layout.getSymbolOffset(&B_SD); // Ofeset of the relocation in the section int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); FixedValue = b - a; // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and // skip recording the relocation. if (!CrossSection) return; } else { FixedValue = Target.getConstant(); } COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. if (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) { Reloc.Symb = coff_symbol->Section->Symbol; FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + coff_symbol->MCData->getOffset(); } else Reloc.Symb = coff_symbol; ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup, CrossSection); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? if (Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32 || Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32) FixedValue += 4; coff_section->Relocations.push_back(Reloc); }
void AArch64MachObjectWriter::RecordRelocation( MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment); unsigned Log2Size = 0; int64_t Value = 0; unsigned Index = 0; unsigned Type = 0; unsigned Kind = Fixup.getKind(); const MCSymbolData *RelSymbol = nullptr; FixupOffset += Fixup.getOffset(); // AArch64 pcrel relocation addends do not include the section offset. if (IsPCRel) FixedValue += FixupOffset; // ADRP fixups use relocations for the whole symbol value and only // put the addend in the instruction itself. Clear out any value the // generic code figured out from the sybmol definition. if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21) FixedValue = 0; // imm19 relocations are for conditional branches, which require // assembler local symbols. If we got here, that's not what we have, // so complain loudly. if (Kind == AArch64::fixup_aarch64_pcrel_branch19) { Asm.getContext().FatalError(Fixup.getLoc(), "conditional branch requires assembler-local" " label. '" + Target.getSymA()->getSymbol().getName() + "' is external."); return; } // 14-bit branch relocations should only target internal labels, and so // should never get here. if (Kind == AArch64::fixup_aarch64_pcrel_branch14) { Asm.getContext().FatalError(Fixup.getLoc(), "Invalid relocation on conditional branch!"); return; } if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size, Asm)) { Asm.getContext().FatalError(Fixup.getLoc(), "unknown AArch64 fixup kind!"); return; } Value = Target.getConstant(); if (Target.isAbsolute()) { // constant // FIXME: Should this always be extern? // SymbolNum of 0 indicates the absolute section. Type = MachO::ARM64_RELOC_UNSIGNED; if (IsPCRel) { Asm.getContext().FatalError(Fixup.getLoc(), "PC relative absolute relocation!"); // FIXME: x86_64 sets the type to a branch reloc here. Should we do // something similar? } } else if (Target.getSymB()) { // A - B + constant const MCSymbol *A = &Target.getSymA()->getSymbol(); const MCSymbolData &A_SD = Asm.getSymbolData(*A); const MCSymbolData *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); const MCSymbolData &B_SD = Asm.getSymbolData(*B); const MCSymbolData *B_Base = Asm.getAtom(&B_SD); // Check for "_foo@got - .", which comes through here as: // Ltmp0: // ... _foo@got - Ltmp0 if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT && Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None && Layout.getSymbolOffset(&B_SD) == Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) { // SymB is the PC, so use a PC-rel pointer-to-GOT relocation. Type = MachO::ARM64_RELOC_POINTER_TO_GOT; IsPCRel = 1; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, Fragment->getParent(), MRE); return; } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) // Otherwise, neither symbol can be modified. Asm.getContext().FatalError(Fixup.getLoc(), "unsupported relocation of modified symbol"); // We don't support PCrel relocations of differences. if (IsPCRel) Asm.getContext().FatalError(Fixup.getLoc(), "unsupported pc-relative relocation of " "difference"); // AArch64 always uses external relocations. If there is no symbol to use as // a base address (a local symbol with no preceding non-local symbol), // error out. // // FIXME: We should probably just synthesize an external symbol and use // that. if (!A_Base) Asm.getContext().FatalError( Fixup.getLoc(), "unsupported relocation of local symbol '" + A->getName() + "'. Must have non-local symbol earlier in section."); if (!B_Base) Asm.getContext().FatalError( Fixup.getLoc(), "unsupported relocation of local symbol '" + B->getName() + "'. Must have non-local symbol earlier in section."); if (A_Base == B_Base && A_Base) Asm.getContext().FatalError(Fixup.getLoc(), "unsupported relocation with identical base"); Value += (!A_SD.getFragment() ? 0 : Writer->getSymbolAddress(&A_SD, Layout)) - (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress(A_Base, Layout)); Value -= (!B_SD.getFragment() ? 0 : Writer->getSymbolAddress(&B_SD, Layout)) - (!B_Base || !B_Base->getFragment() ? 0 : Writer->getSymbolAddress(B_Base, Layout)); Type = MachO::ARM64_RELOC_UNSIGNED; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, Fragment->getParent(), MRE); RelSymbol = B_Base; Type = MachO::ARM64_RELOC_SUBTRACTOR; } else { // A + constant const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); const MCSectionMachO &Section = static_cast<const MCSectionMachO &>( Fragment->getParent()->getSection()); bool CanUseLocalRelocation = canUseLocalRelocation(Section, *Symbol, Log2Size); if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) { const MCSection &Sec = Symbol->getSection(); if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) Asm.addLocalUsedInReloc(*Symbol); } const MCSymbolData &SD = Asm.getSymbolData(*Symbol); const MCSymbolData *Base = Asm.getAtom(&SD); // If the symbol is a variable and we weren't able to get a Base for it // (i.e., it's not in the symbol table associated with a section) resolve // the relocation based its expansion instead. if (Symbol->isVariable() && !Base) { // If the evaluation is an absolute value, just use that directly // to keep things easy. int64_t Res; if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } // FIXME: Will the Target we already have ever have any data in it // we need to preserve and merge with the new Target? How about // the FixedValue? if (!Symbol->getVariableValue()->EvaluateAsRelocatable(Target, &Layout, &Fixup)) Asm.getContext().FatalError(Fixup.getLoc(), "unable to resolve variable '" + Symbol->getName() + "'"); return RecordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, FixedValue); } // Relocations inside debug sections always use local relocations when // possible. This seems to be done because the debugger doesn't fully // understand relocation entries and expects to find values that // have already been fixed up. if (Symbol->isInSection()) { if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) Base = nullptr; } // AArch64 uses external relocations as much as possible. For debug // sections, and for pointer-sized relocations (.quad), we allow section // relocations. It's code sections that run into trouble. if (Base) { RelSymbol = Base; // Add the local offset, if needed. if (Base != &SD) Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); } else if (Symbol->isInSection()) { if (!CanUseLocalRelocation) Asm.getContext().FatalError( Fixup.getLoc(), "unsupported relocation of local symbol '" + Symbol->getName() + "'. Must have non-local symbol earlier in section."); // Adjust the relocation to be section-relative. // The index is the section ordinal (1-based). const MCSectionData &SymSD = Asm.getSectionData(SD.getSymbol().getSection()); Index = SymSD.getOrdinal() + 1; Value += Writer->getSymbolAddress(&SD, Layout); if (IsPCRel) Value -= Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset() + (1ULL << Log2Size); } else { // Resolve constant variables. if (SD.getSymbol().isVariable()) { int64_t Res; if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } } Asm.getContext().FatalError(Fixup.getLoc(), "unsupported relocation of variable '" + Symbol->getName() + "'"); } } // If the relocation kind is Branch26, Page21, or Pageoff12, any addend // is represented via an Addend relocation, not encoded directly into // the instruction. if ((Type == MachO::ARM64_RELOC_BRANCH26 || Type == MachO::ARM64_RELOC_PAGE21 || Type == MachO::ARM64_RELOC_PAGEOFF12) && Value) { assert((Value & 0xff000000) == 0 && "Added relocation out of range!"); MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); // Now set up the Addend relocation. Type = MachO::ARM64_RELOC_ADDEND; Index = Value; RelSymbol = nullptr; IsPCRel = 0; Log2Size = 2; // Put zero into the instruction itself. The addend is in the relocation. Value = 0; } // If there's any addend left to handle, encode it in the instruction. FixedValue = Value; // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
void ELFObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { MCAsmBackend &Backend = Asm.getBackend(); bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { // Let A, B and C being the components of Target and R be the location of // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). // If it is pcrel, we want to compute (A - B + C - R). // In general, ELF has no relocations for -B. It can only represent (A + C) // or (A + C - R). If B = R + K and the relocation is not pcrel, we can // replace B to implement it: (A - R - K + C) if (IsPCRel) { Ctx.reportError( Fixup.getLoc(), "No relocation available to represent this relative expression"); return; } const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), Twine("symbol '") + SymB.getName() + "' can not be undefined in a subtraction expression"); return; } assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); if (&SecB != &FixupSection) { Ctx.reportError(Fixup.getLoc(), "Cannot represent a difference across sections"); return; } uint64_t SymBOffset = Layout.getSymbolOffset(SymB); uint64_t K = SymBOffset - FixupOffset; IsPCRel = true; C -= K; } // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; bool ViaWeakRef = false; if (SymA && SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { SymA = cast<MCSymbolELF>(&Inner->getSymbol()); ViaWeakRef = true; } } } unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); uint64_t OriginalC = C; bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) C += Layout.getSymbolOffset(*SymA); uint64_t Addend = 0; if (hasRelocationAddend()) { Addend = C; C = 0; } FixedValue = C; if (!RelocateWithSymbol) { const MCSection *SecA = (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; auto *ELFSec = cast_or_null<MCSectionELF>(SecA); const auto *SectionSymbol = ELFSec ? cast<MCSymbolELF>(ELFSec->getBeginSymbol()) : nullptr; if (SectionSymbol) SectionSymbol->setUsedInReloc(); ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); return; } const auto *RenamedSymA = SymA; if (SymA) { if (const MCSymbolELF *R = Renames.lookup(SymA)) RenamedSymA = R; if (ViaWeakRef) RenamedSymA->setIsWeakrefUsedInReloc(); else RenamedSymA->setUsedInReloc(); } ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); }
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); const MCSymbol *A = &Target.getSymA()->getSymbol(); MCSymbolData &A_SD = Asm.getSymbolData(*A); MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[&SectionData->getSection()]; COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; if (Target.getSymB()) { if (&Target.getSymA()->getSymbol().getSection() != &Target.getSymB()->getSymbol().getSection()) { llvm_unreachable("Symbol relative relocations are only allowed between " "symbols in the same section"); } const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); FixedValue = Layout.getSymbolOffset(&A_SD) - Layout.getSymbolOffset(&B_SD); // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and // skip recording the relocation. return; } else { FixedValue = Target.getConstant(); } COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. if (coff_symbol->MCData->getSymbol().isTemporary()) { Reloc.Symb = coff_symbol->Section->Symbol; FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + coff_symbol->MCData->getOffset(); } else Reloc.Symb = coff_symbol; ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); switch ((unsigned)Fixup.getKind()) { case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 : COFF::IMAGE_REL_I386_REL32; // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? FixedValue += 4; break; case FK_Data_4: case X86::reloc_signed_4byte: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 : COFF::IMAGE_REL_I386_DIR32; break; case FK_Data_8: if (Is64Bit) Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64; else llvm_unreachable("unsupported relocation type"); break; default: llvm_unreachable("unsupported relocation type"); } coff_section->Relocations.push_back(Reloc); }
void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, 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(Writer, 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()) { RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, Log2Size, FixedValue); return; } // Get the symbol data, if any. const MCSymbolData *SD = nullptr; 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; // Try to record the scattered relocation if needed. Fall back to non // scattered if necessary (see comments in RecordScatteredRelocation() // for details). if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD) && RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, Log2Size, FixedValue)) return; // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned Index = 0; unsigned Type = 0; const MCSymbol *RelSymbol = nullptr; if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. // // FIXME: Currently, these are never generated (see code below). I cannot // find a case where they are actually emitted. Type = MachO::GENERIC_RELOC_VANILLA; } else { // Resolve constant variables. if (SD->getSymbol().isVariable()) { int64_t Res; if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } } // Check whether we need an external or internal relocation. if (Writer->doesSymbolRequireExternRelocation(SD)) { RelSymbol = &SD->getSymbol(); // 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->getSymbol().isUndefined()) FixedValue -= Layout.getSymbolOffset(SD); } else { // The index is the section ordinal (1-based). const MCSectionData &SymSD = Asm.getSectionData( SD->getSymbol().getSection()); Index = SymSD.getOrdinal() + 1; FixedValue += Writer->getSectionAddress(&SymSD); } if (IsPCRel) FixedValue -= Writer->getSectionAddress(Fragment->getParent()); Type = MachO::GENERIC_RELOC_VANILLA; } // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: return cast<MCDataFragment>(F).getContents().size(); case MCFragment::FT_Relaxable: return cast<MCRelaxableFragment>(F).getContents().size(); case MCFragment::FT_CompactEncodedInst: return cast<MCCompactEncodedInstFragment>(F).getContents().size(); case MCFragment::FT_Fill: return cast<MCFillFragment>(F).getSize(); case MCFragment::FT_LEB: return cast<MCLEBFragment>(F).getContents().size(); case MCFragment::FT_SafeSEH: return 4; case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); unsigned Offset = Layout.getFragmentOffset(&AF); unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); // If we are padding with nops, force the padding to be larger than the // minimum nop size. if (Size > 0 && AF.hasEmitNops()) { while (Size % getBackend().getMinimumNopSize()) Size += AF.getAlignment(); } if (Size > AF.getMaxBytesToEmit()) return 0; return Size; } case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); MCValue Value; if (!OF.getOffset().evaluateAsValue(Value, Layout)) { getContext().reportError(OF.getLoc(), "expected assembly-time absolute expression"); return 0; } uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t TargetLocation = Value.getConstant(); if (const MCSymbolRefExpr *A = Value.getSymA()) { uint64_t Val; if (!Layout.getSymbolOffset(A->getSymbol(), Val)) { getContext().reportError(OF.getLoc(), "expected absolute expression"); return 0; } TargetLocation += Val; } int64_t Size = TargetLocation - FragmentOffset; if (Size < 0 || Size >= 0x40000000) { getContext().reportError( OF.getLoc(), "invalid .org offset '" + Twine(TargetLocation) + "' (at offset '" + Twine(FragmentOffset) + "')"); return 0; } return Size; } case MCFragment::FT_Dwarf: return cast<MCDwarfLineAddrFragment>(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast<MCDwarfCallFrameFragment>(F).getContents().size(); case MCFragment::FT_CVInlineLines: return cast<MCCVInlineLineTableFragment>(F).getContents().size(); case MCFragment::FT_CVDefRange: return cast<MCCVDefRangeFragment>(F).getContents().size(); case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } llvm_unreachable("invalid fragment kind"); }
void SVMELFProgramWriter::rwCompress(MCAssembler &Asm, const MCAsmLayout &Layout, SVMMemoryLayout &ML) { /* * Look for all segments with initialized data for RAM, flatten them, and * compress the resulting data. Create a new segment with the compressed * RWDATA. This segment will always be included in the binary. The originals * are considered debug-only sections, since they are no longer needed * at runtime. */ // Flattened binary contents of RAM std::vector<uint8_t> plaintext; // Iterate over SPS_RW sections for (MCAssembler::const_iterator IS = Asm.begin(), ES = Asm.end(); IS != ES; ++IS) { const MCSectionData *SD = &*IS; if (ML.getSectionKind(SD) != SPS_RW_PLAIN) continue; int offset = ML.getSectionMemAddress(SD) - SVMTargetMachine::getRAMBase(); int limit = SVMTargetMachine::getRAMSize(); // Iterate over fragments, pasting them into 'plaintext' for (MCSectionData::const_iterator IF = SD->begin(), EF = SD->end(); IF != EF; ++IF) { const MCFragment *F = &*IF; if (F->getKind() == MCFragment::FT_Data) { const MCDataFragment *DF = cast<MCDataFragment>(F); int fragmentOffset = Layout.getFragmentOffset(F); for (unsigned i = 0; i < DF->getContents().size(); i++) { int totalOffset = fragmentOffset + offset + i; if (totalOffset < limit) { while (totalOffset >= int(plaintext.size())) plaintext.push_back(0); plaintext[totalOffset] = DF->getContents()[i]; } } } } } // FastLZ requires a minimum of 16 bytes to compress. Pad our section data. while (plaintext.size() < 16) plaintext.push_back(0); // Compress using FastLZ level 1 std::vector<uint8_t> compressed(plaintext.size() * 2); compressed.resize(fastlz_compress_level(1, &plaintext[0], plaintext.size(), &compressed[0])); // Create the new section const MCSectionELF *LZSection = Asm.getContext().getELFSection(".rwdata.lz", ELF::SHT_NOTE, 0, SectionKind::getDataNoRel()); MCSectionData &LZSectionSD = Asm.getOrCreateSectionData(*LZSection); LZSectionSD.setAlignment(1); // Force it to be interpreted as SPS_RW, and set the decompressed size ML.setSectionKind(&LZSectionSD, SPS_RW_Z); ML.setSectionMemSize(&LZSectionSD, plaintext.size()); // Add compressed data MCDataFragment *F = new MCDataFragment(&LZSectionSD); F->getContents().append(compressed.begin(), compressed.end()); }
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) { assert(Target.getSymA() && "Relocation must reference a symbol!"); const MCSymbol &Symbol = Target.getSymA()->getSymbol(); const MCSymbol &A = Symbol.AliasedSymbol(); if (!Asm.hasSymbolData(A)) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + A.getName() + "' can not be undefined"); const MCSymbolData &A_SD = Asm.getSymbolData(A); MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[&SectionData->getSection()]; COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; const MCSymbolRefExpr *SymB = Target.getSymB(); bool CrossSection = false; if (SymB) { const MCSymbol *B = &SymB->getSymbol(); const MCSymbolData &B_SD = Asm.getSymbolData(*B); if (!B_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + B->getName() + "' can not be undefined in a subtraction expression"); if (!A_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + Symbol.getName() + "' can not be undefined in a subtraction expression"); CrossSection = &Symbol.getSection() != &B->getSection(); // Offset of the symbol in the section int64_t a = Layout.getSymbolOffset(&B_SD); // Ofeset of the relocation in the section int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); FixedValue = b - a; // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and // skip recording the relocation. if (!CrossSection) return; } else { FixedValue = Target.getConstant(); } COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. if (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) { Reloc.Symb = coff_symbol->Section->Symbol; FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + coff_symbol->MCData->getOffset(); } else Reloc.Symb = coff_symbol; ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup, CrossSection); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 && Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32) || (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386 && Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32)) FixedValue += 4; if (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) { switch (Reloc.Data.Type) { case COFF::IMAGE_REL_ARM_ABSOLUTE: case COFF::IMAGE_REL_ARM_ADDR32: case COFF::IMAGE_REL_ARM_ADDR32NB: case COFF::IMAGE_REL_ARM_TOKEN: case COFF::IMAGE_REL_ARM_SECTION: case COFF::IMAGE_REL_ARM_SECREL: break; case COFF::IMAGE_REL_ARM_BRANCH11: case COFF::IMAGE_REL_ARM_BLX11: // IMAGE_REL_ARM_BRANCH11 and IMAGE_REL_ARM_BLX11 are only used for // pre-ARMv7, which implicitly rules it out of ARMNT (it would be valid // for Windows CE). case COFF::IMAGE_REL_ARM_BRANCH24: case COFF::IMAGE_REL_ARM_BLX24: case COFF::IMAGE_REL_ARM_MOV32A: // IMAGE_REL_ARM_BRANCH24, IMAGE_REL_ARM_BLX24, IMAGE_REL_ARM_MOV32A are // only used for ARM mode code, which is documented as being unsupported // by Windows on ARM. Emperical proof indicates that masm is able to // generate the relocations however the rest of the MSVC toolchain is // unable to handle it. llvm_unreachable("unsupported relocation"); break; case COFF::IMAGE_REL_ARM_MOV32T: break; case COFF::IMAGE_REL_ARM_BRANCH20T: case COFF::IMAGE_REL_ARM_BRANCH24T: case COFF::IMAGE_REL_ARM_BLX23T: // IMAGE_REL_BRANCH20T, IMAGE_REL_ARM_BRANCH24T, IMAGE_REL_ARM_BLX23T all // perform a 4 byte adjustment to the relocation. Relative branches are // offset by 4 on ARM, however, because there is no RELA relocations, all // branches are offset by 4. FixedValue = FixedValue + 4; break; } } coff_section->Relocations.push_back(Reloc); }
void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Assign symbol and section indexes and offsets. Header.NumberOfSections = 0; for (sections::iterator i = Sections.begin(), e = Sections.end(); i != e; i++) { if (Layout.getSectionAddressSize((*i)->MCData) > 0) { MakeSectionReal(**i, ++Header.NumberOfSections); } else { (*i)->Number = -1; } } Header.NumberOfSymbols = 0; for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { COFFSymbol *coff_symbol = *i; MCSymbolData const *SymbolData = coff_symbol->MCData; // Update section number & offset for symbols that have them. if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { assert(coff_symbol->Section != NULL); coff_symbol->Data.SectionNumber = coff_symbol->Section->Number; coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + SymbolData->Offset; } if (coff_symbol->should_keep()) { MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); // Update auxiliary symbol info. coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; } else coff_symbol->Index = -1; } // Fixup weak external references. for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { COFFSymbol *coff_symbol = *i; if (coff_symbol->Other != NULL) { assert(coff_symbol->Index != -1); assert(coff_symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!"); assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && "Symbol's aux symbol must be a Weak External!"); coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; } } // Assign file offsets to COFF object file structures. unsigned offset = 0; offset += COFF::HeaderSize; offset += COFF::SectionSize * Header.NumberOfSections; for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) { COFFSection *Sec = SectionMap[&i->getSection()]; if (Sec->Number == -1) continue; Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i); if (IsPhysicalSection(Sec)) { Sec->Header.PointerToRawData = offset; offset += Sec->Header.SizeOfRawData; } if (Sec->Relocations.size() > 0) { Sec->Header.NumberOfRelocations = Sec->Relocations.size(); Sec->Header.PointerToRelocations = offset; offset += COFF::RelocationSize * Sec->Relocations.size(); for (relocations::iterator cr = Sec->Relocations.begin(), er = Sec->Relocations.end(); cr != er; ++cr) { assert((*cr).Symb->Index != -1); (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; } } assert(Sec->Symbol->Aux.size() == 1 && "Section's symbol must have one aux!"); AuxSymbol &Aux = Sec->Symbol->Aux[0]; assert(Aux.AuxType == ATSectionDefinition && "Section's symbol's aux symbol must be a Section Definition!"); Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; Aux.Aux.SectionDefinition.NumberOfRelocations = Sec->Header.NumberOfRelocations; Aux.Aux.SectionDefinition.NumberOfLinenumbers = Sec->Header.NumberOfLineNumbers; } Header.PointerToSymbolTable = offset; Header.TimeDateStamp = sys::TimeValue::now().toEpochTime(); // Write it all to disk... WriteFileHeader(Header); { sections::iterator i, ie; MCAssembler::const_iterator j, je; for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) if ((*i)->Number != -1) WriteSectionHeader((*i)->Header); for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(), je = Asm.end(); (i != ie) && (j != je); ++i, ++j) { if ((*i)->Number == -1) continue; if ((*i)->Header.PointerToRawData != 0) { assert(OS.tell() == (*i)->Header.PointerToRawData && "Section::PointerToRawData is insane!"); Asm.writeSectionData(j, Layout); } if ((*i)->Relocations.size() > 0) { assert(OS.tell() == (*i)->Header.PointerToRelocations && "Section::PointerToRelocations is insane!"); for (relocations::const_iterator k = (*i)->Relocations.begin(), ke = (*i)->Relocations.end(); k != ke; k++) { WriteRelocation(k->Data); } } else assert((*i)->Header.PointerToRelocations == 0 && "Section::PointerToRelocations is insane!"); } } assert(OS.tell() == Header.PointerToSymbolTable && "Header::PointerToSymbolTable is insane!"); for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) if ((*i)->Index != -1) WriteSymbol(*i); OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); }
void X86MachObjectWriter::RecordX86_64Relocation( MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); uint32_t FixupAddress = Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); int64_t Value = 0; unsigned Index = 0; unsigned IsExtern = 0; unsigned Type = 0; const MCSymbol *RelSymbol = nullptr; Value = Target.getConstant(); if (IsPCRel) { // Compensate for the relocation offset, Darwin x86_64 relocations only have // the addend and appear to have attempted to define it to be the actual // expression addend without the PCrel bias. However, instructions with data // following the relocation are not accommodated for (see comment below // regarding SIGNED{1,2,4}), so it isn't exactly that either. Value += 1LL << Log2Size; } if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. Type = MachO::X86_64_RELOC_UNSIGNED; // FIXME: I believe this is broken, I don't think the linker can understand // it. I think it would require a local relocation, but I'm not sure if that // would work either. The official way to get an absolute PCrel relocation // is to use an absolute symbol (which we don't support yet). if (IsPCRel) { IsExtern = 1; Type = MachO::X86_64_RELOC_BRANCH; } } else if (Target.getSymB()) { // A - B + constant const MCSymbol *A = &Target.getSymA()->getSymbol(); if (A->isTemporary()) A = &Writer->findAliasedSymbol(*A); const MCSymbolData &A_SD = Asm.getSymbolData(*A); const MCSymbol *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); if (B->isTemporary()) B = &Writer->findAliasedSymbol(*B); const MCSymbolData &B_SD = Asm.getSymbolData(*B); const MCSymbol *B_Base = Asm.getAtom(&B_SD); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported relocation of modified symbol", false); // We don't support PCrel relocations of differences. Darwin 'as' doesn't // implement most of these correctly. if (IsPCRel) report_fatal_error("unsupported pc-relative relocation of difference", false); // 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. 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", false); // A subtraction expression where either symbol is undefined is a // non-relocatable expression. if (A->isUndefined() || B->isUndefined()) { StringRef Name = A->isUndefined() ? A->getName() : B->getName(); Asm.getContext().FatalError(Fixup.getLoc(), "unsupported relocation with subtraction expression, symbol '" + Name + "' can not be undefined in a subtraction expression"); } Value += Writer->getSymbolAddress(&A_SD, Layout) - (!A_Base ? 0 : Writer->getSymbolAddress(&A_Base->getData(), Layout)); Value -= Writer->getSymbolAddress(&B_SD, Layout) - (!B_Base ? 0 : Writer->getSymbolAddress(&B_Base->getData(), Layout)); if (!A_Base) Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; Type = MachO::X86_64_RELOC_UNSIGNED; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, Fragment->getParent(), MRE); if (B_Base) RelSymbol = B_Base; else Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; Type = MachO::X86_64_RELOC_SUBTRACTOR; } else { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); if (Symbol->isTemporary() && Value) { const MCSection &Sec = Symbol->getSection(); if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) Asm.addLocalUsedInReloc(*Symbol); } const MCSymbolData &SD = Asm.getSymbolData(*Symbol); RelSymbol = 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<const MCSectionMachO&>( Fragment->getParent()->getSection()); if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) RelSymbol = nullptr; } // x86_64 almost always uses external relocations, except when there is no // symbol to use as a base address (a local symbol with no preceding // non-local symbol). if (RelSymbol) { // Add the local offset, if needed. if (&RelSymbol->getData() != &SD) Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(&RelSymbol->getData()); } else if (Symbol->isInSection() && !Symbol->isVariable()) { // The index is the section ordinal (1-based). Index = SD.getFragment()->getParent()->getOrdinal() + 1; Value += Writer->getSymbolAddress(&SD, Layout); if (IsPCRel) Value -= FixupAddress + (1 << Log2Size); } else if (Symbol->isVariable()) { const MCExpr *Value = Symbol->getVariableValue(); int64_t Res; bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, Writer->getSectionAddressMap()); if (isAbs) { FixedValue = Res; return; } else { report_fatal_error("unsupported relocation of variable '" + Symbol->getName() + "'", false); } } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'", false); } MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); if (IsPCRel) { if (IsRIPRel) { if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { // 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.getKind()) == X86::reloc_riprel_4byte_movq_load) Type = MachO::X86_64_RELOC_GOT_LOAD; else Type = MachO::X86_64_RELOC_GOT; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { Type = MachO::X86_64_RELOC_TLV; } else if (Modifier != MCSymbolRefExpr::VK_None) { report_fatal_error("unsupported symbol modifier in relocation", false); } else { Type = MachO::X86_64_RELOC_SIGNED; // The Darwin x86_64 relocation format has a problem where it cannot // encode an address (L<foo> + <constant>) which is outside the atom // containing L<foo>. 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 = MachO::X86_64_RELOC_SIGNED_1; break; case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break; case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break; } } } else { if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in branch " "relocation", false); Type = MachO::X86_64_RELOC_BRANCH; } } else { if (Modifier == MCSymbolRefExpr::VK_GOT) { Type = MachO::X86_64_RELOC_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 = MachO::X86_64_RELOC_GOT; IsPCRel = 1; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { report_fatal_error("TLVP symbol modifier should have been rip-rel", false); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation", false); else { Type = MachO::X86_64_RELOC_UNSIGNED; unsigned Kind = Fixup.getKind(); if (Kind == X86::reloc_signed_4byte) report_fatal_error("32-bit absolute addressing is not supported in " "64-bit mode", false); } } } // x86_64 always writes custom values into the fixups. FixedValue = Value; // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (IsExtern << 27) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value) const { ++stats::evaluateFixup; // FIXME: This code has some duplication with recordRelocation. We should // probably merge the two into a single callback that tries to evaluate a // fixup and records a relocation if one is needed. const MCExpr *Expr = Fixup.getValue(); if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) getContext().reportFatalError(Fixup.getLoc(), "expected relocatable expression"); bool IsPCRel = Backend.getFixupKindInfo( Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; bool IsResolved; if (IsPCRel) { if (Target.getSymB()) { IsResolved = false; } else if (!Target.getSymA()) { IsResolved = false; } else { const MCSymbolRefExpr *A = Target.getSymA(); const MCSymbol &SA = A->getSymbol(); if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) { IsResolved = false; } else { IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl( *this, SA, *DF, false, true); } } } else { IsResolved = Target.isAbsolute(); } Value = Target.getConstant(); if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol(); if (Sym.isDefined()) Value += Layout.getSymbolOffset(Sym); } if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbol &Sym = B->getSymbol(); if (Sym.isDefined()) Value -= Layout.getSymbolOffset(Sym); } bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; assert((ShouldAlignPC ? IsPCRel : true) && "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); if (IsPCRel) { uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset(); // A number of ARM fixups in Thumb mode require that the effective PC // address be determined as the 32-bit aligned version of the actual offset. if (ShouldAlignPC) Offset &= ~0x3; Value -= Offset; } // Let the backend adjust the fixup value if necessary, including whether // we need a relocation. Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value, IsResolved); return IsResolved; }