/// WriteFragmentData - Write the \arg F data to the output file. static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F, MCObjectWriter *OW) { uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; // FIXME: Embed in fragments instead? uint64_t FragmentSize = Layout.getFragmentEffectiveSize(&F); switch (F.getKind()) { case MCFragment::FT_Align: { MCAlignFragment &AF = cast<MCAlignFragment>(F); uint64_t Count = FragmentSize / AF.getValueSize(); assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!"); // FIXME: This error shouldn't actually occur (the front end should emit // multiple .align directives to enforce the semantics it wants), but is // severe enough that we want to report it. How to handle this? if (Count * AF.getValueSize() != FragmentSize) report_fatal_error("undefined .align directive, value size '" + Twine(AF.getValueSize()) + "' is not a divisor of padding size '" + Twine(FragmentSize) + "'"); // See if we are aligning with nops, and if so do that first to try to fill // the Count bytes. Then if that did not fill any bytes or there are any // bytes left to fill use the the Value and ValueSize to fill the rest. // If we are aligning with nops, ask that target to emit the right data. if (AF.hasEmitNops()) { if (!Asm.getBackend().WriteNopData(Count, OW)) report_fatal_error("unable to write nop sequence of " + Twine(Count) + " bytes"); break; } // Otherwise, write out in multiples of the value size. for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: assert(0 && "Invalid size!"); case 1: OW->Write8 (uint8_t (AF.getValue())); break; case 2: OW->Write16(uint16_t(AF.getValue())); break; case 4: OW->Write32(uint32_t(AF.getValue())); break; case 8: OW->Write64(uint64_t(AF.getValue())); break; } } break; } case MCFragment::FT_Data: { MCDataFragment &DF = cast<MCDataFragment>(F); assert(FragmentSize == DF.getContents().size() && "Invalid size!"); OW->WriteBytes(DF.getContents().str()); break; } case MCFragment::FT_Fill: { MCFillFragment &FF = cast<MCFillFragment>(F); assert(FF.getValueSize() && "Invalid virtual align in concrete fragment!"); for (uint64_t i = 0, e = FF.getSize() / FF.getValueSize(); i != e; ++i) { switch (FF.getValueSize()) { default: assert(0 && "Invalid size!"); case 1: OW->Write8 (uint8_t (FF.getValue())); break; case 2: OW->Write16(uint16_t(FF.getValue())); break; case 4: OW->Write32(uint32_t(FF.getValue())); break; case 8: OW->Write64(uint64_t(FF.getValue())); break; } } break; } case MCFragment::FT_Inst: llvm_unreachable("unexpected inst fragment after lowering"); break; case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); for (uint64_t i = 0, e = FragmentSize; i != e; ++i) OW->Write8(uint8_t(OF.getValue())); break; } } assert(OW->getStream().tell() - Start == FragmentSize); }
bool MachObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo( (MCFixupKind) Kind); return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; }
void MachObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Compute symbol table information and bind symbol indices. computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData, UndefinedSymbolData); unsigned NumSections = Asm.size(); const MCAssembler::VersionMinInfoType &VersionInfo = Layout.getAssembler().getVersionMinInfo(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; uint64_t LoadCommandsSize = is64Bit() ? sizeof(MachO::segment_command_64) + NumSections * sizeof(MachO::section_64): sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); // Add the deployment target version info load command size, if used. if (VersionInfo.Major != 0) { ++NumLoadCommands; LoadCommandsSize += sizeof(MachO::version_min_command); } // Add the data-in-code load command size, if used. unsigned NumDataRegions = Asm.getDataRegions().size(); if (NumDataRegions) { ++NumLoadCommands; LoadCommandsSize += sizeof(MachO::linkedit_data_command); } // Add the loh load command size, if used. uint64_t LOHRawSize = Asm.getLOHContainer().getEmitSize(*this, Layout); uint64_t LOHSize = RoundUpToAlignment(LOHRawSize, is64Bit() ? 8 : 4); if (LOHSize) { ++NumLoadCommands; LoadCommandsSize += sizeof(MachO::linkedit_data_command); } // Add the symbol table load command sizes, if used. unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + UndefinedSymbolData.size(); if (NumSymbols) { NumLoadCommands += 2; LoadCommandsSize += (sizeof(MachO::symtab_command) + sizeof(MachO::dysymtab_command)); } // Add the linker option load commands sizes. for (const auto &Option : Asm.getLinkerOptions()) { ++NumLoadCommands; LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(Option, is64Bit()); } // Compute the total size of the section data, as well as its file size and vm // size. uint64_t SectionDataStart = (is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header)) + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; for (const MCSection &Sec : Asm) { uint64_t Address = getSectionAddress(&Sec); uint64_t Size = Layout.getSectionAddressSize(&Sec); uint64_t FileSize = Layout.getSectionFileSize(&Sec); FileSize += getPaddingSize(&Sec, Layout); VMSize = std::max(VMSize, Address + Size); if (Sec.isVirtualSection()) continue; SectionDataSize = std::max(SectionDataSize, Address + Size); SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); } // The section data is padded to 4 bytes. // // FIXME: Is this machine dependent? unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); SectionDataFileSize += SectionDataPadding; // Write the prolog, starting with the header and load command... writeHeader(MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize, Asm.getSubsectionsViaSymbols()); uint32_t Prot = MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE; writeSegmentLoadCommand("", NumSections, 0, VMSize, SectionDataStart, SectionDataSize, Prot, Prot); // ... and then the section headers. uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; for (const MCSection &Section : Asm) { const auto &Sec = cast<MCSectionMachO>(Section); std::vector<RelAndSymbol> &Relocs = Relocations[&Sec]; unsigned NumRelocs = Relocs.size(); uint64_t SectionStart = SectionDataStart + getSectionAddress(&Sec); unsigned Flags = Sec.getTypeAndAttributes(); if (Sec.hasInstructions()) Flags |= MachO::S_ATTR_SOME_INSTRUCTIONS; writeSection(Layout, Sec, getSectionAddress(&Sec), SectionStart, Flags, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * sizeof(MachO::any_relocation_info); } // Write out the deployment target information, if it's available. if (VersionInfo.Major != 0) { assert(VersionInfo.Update < 256 && "unencodable update target version"); assert(VersionInfo.Minor < 256 && "unencodable minor target version"); assert(VersionInfo.Major < 65536 && "unencodable major target version"); uint32_t EncodedVersion = VersionInfo.Update | (VersionInfo.Minor << 8) | (VersionInfo.Major << 16); write32(VersionInfo.Kind == MCVM_OSXVersionMin ? MachO::LC_VERSION_MIN_MACOSX : MachO::LC_VERSION_MIN_IPHONEOS); write32(sizeof(MachO::version_min_command)); write32(EncodedVersion); write32(0); // reserved. } // Write the data-in-code load command, if used. uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8; if (NumDataRegions) { uint64_t DataRegionsOffset = RelocTableEnd; uint64_t DataRegionsSize = NumDataRegions * 8; writeLinkeditLoadCommand(MachO::LC_DATA_IN_CODE, DataRegionsOffset, DataRegionsSize); } // Write the loh load command, if used. uint64_t LOHTableEnd = DataInCodeTableEnd + LOHSize; if (LOHSize) writeLinkeditLoadCommand(MachO::LC_LINKER_OPTIMIZATION_HINT, DataInCodeTableEnd, LOHSize); // Write the symbol table load command, if used. if (NumSymbols) { unsigned FirstLocalSymbol = 0; unsigned NumLocalSymbols = LocalSymbolData.size(); unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; unsigned NumExternalSymbols = ExternalSymbolData.size(); unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); unsigned NumSymTabSymbols = NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; uint64_t IndirectSymbolOffset = 0; // If used, the indirect symbols are written after the section data. if (NumIndirectSymbols) IndirectSymbolOffset = LOHTableEnd; // The symbol table is written after the indirect symbol data. uint64_t SymbolTableOffset = LOHTableEnd + IndirectSymbolSize; // The string table is written after symbol table. uint64_t StringTableOffset = SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist)); writeSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.data().size()); writeDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, FirstExternalSymbol, NumExternalSymbols, FirstUndefinedSymbol, NumUndefinedSymbols, IndirectSymbolOffset, NumIndirectSymbols); } // Write the linker options load commands. for (const auto &Option : Asm.getLinkerOptions()) writeLinkerOptionsLoadCommand(Option); // Write the actual section data. for (const MCSection &Sec : Asm) { Asm.writeSectionData(&Sec, Layout); uint64_t Pad = getPaddingSize(&Sec, Layout); WriteZeros(Pad); } // Write the extra padding. WriteZeros(SectionDataPadding); // Write the relocation entries. for (const MCSection &Sec : Asm) { // Write the section relocation entries, in reverse order to match 'as' // (approximately, the exact algorithm is more complicated than this). std::vector<RelAndSymbol> &Relocs = Relocations[&Sec]; for (const RelAndSymbol &Rel : make_range(Relocs.rbegin(), Relocs.rend())) { write32(Rel.MRE.r_word0); write32(Rel.MRE.r_word1); } } // Write out the data-in-code region payload, if there is one. for (MCAssembler::const_data_region_iterator it = Asm.data_region_begin(), ie = Asm.data_region_end(); it != ie; ++it) { const DataRegionData *Data = &(*it); uint64_t Start = getSymbolAddress(*Data->Start, Layout); uint64_t End = getSymbolAddress(*Data->End, Layout); DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind << " start: " << Start << "(" << Data->Start->getName() << ")" << " end: " << End << "(" << Data->End->getName() << ")" << " size: " << End - Start << "\n"); write32(Start); write16(End - Start); write16(Data->Kind); } // Write out the loh commands, if there is one. if (LOHSize) { #ifndef NDEBUG unsigned Start = getStream().tell(); #endif Asm.getLOHContainer().emit(*this, Layout); // Pad to a multiple of the pointer size. writeBytes("", OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4)); assert(getStream().tell() - Start == LOHSize); } // Write the symbol table data, if used. if (NumSymbols) { // Write the indirect symbol entries. for (MCAssembler::const_indirect_symbol_iterator it = Asm.indirect_symbol_begin(), ie = Asm.indirect_symbol_end(); it != ie; ++it) { // Indirect symbols in the non-lazy symbol pointer section have some // special handling. const MCSectionMachO &Section = static_cast<const MCSectionMachO &>(*it->Section); if (Section.getType() == MachO::S_NON_LAZY_SYMBOL_POINTERS) { // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !it->Symbol->isExternal()) { uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL; if (it->Symbol->isAbsolute()) Flags |= MachO::INDIRECT_SYMBOL_ABS; write32(Flags); continue; } } write32(it->Symbol->getIndex()); } // FIXME: Check that offsets match computed ones. // Write the symbol table entries. for (auto *SymbolData : {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData}) for (MachSymbolData &Entry : *SymbolData) writeNlist(Entry, Layout); // Write the string table. getStream() << StringTable.data(); } }
/// This function takes a symbol data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler, const MCAsmLayout &Layout) { MCSymbol const &Symbol = SymbolData.getSymbol(); COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol); SymbolMap[&Symbol] = coff_symbol; if (SymbolData.getFlags() & COFF::SF_WeakExternal) { coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; if (Symbol.isVariable()) { const MCSymbolRefExpr *SymRef = dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue()); if (!SymRef) report_fatal_error("Weak externals may only alias symbols"); coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol()); } else { std::string WeakName = std::string(".weak.") + Symbol.getName().str() + ".default"; COFFSymbol *WeakDefault = createSymbol(WeakName); WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; WeakDefault->Data.Type = 0; WeakDefault->Data.Value = 0; coff_symbol->Other = WeakDefault; } // Setup the Weak External auxiliary symbol. coff_symbol->Aux.resize(1); memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); coff_symbol->Aux[0].AuxType = ATWeakExternal; coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; coff_symbol->MCData = &SymbolData; } else { const MCSymbolData &ResSymData = Assembler.getSymbolData(Symbol.AliasedSymbol()); if (Symbol.isVariable()) { int64_t Addr; if (Symbol.getVariableValue()->EvaluateAsAbsolute(Addr, Layout)) coff_symbol->Data.Value = Addr; } else if (SymbolData.isExternal() && SymbolData.isCommon()) { coff_symbol->Data.Value = SymbolData.getCommonSize(); } coff_symbol->Data.Type = (ResSymData.getFlags() & 0x0000FFFF) >> 0; coff_symbol->Data.StorageClass = (ResSymData.getFlags() & 0x00FF0000) >> 16; // If no storage class was specified in the streamer, define it here. if (coff_symbol->Data.StorageClass == 0) { bool external = ResSymData.isExternal() || !ResSymData.Fragment; coff_symbol->Data.StorageClass = external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; } if (Symbol.isAbsolute() || Symbol.AliasedSymbol().isVariable()) coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; else if (ResSymData.Fragment) coff_symbol->Section = SectionMap[&ResSymData.Fragment->getParent()->getSection()]; coff_symbol->MCData = &ResSymData; } }
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->get()] = 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 && SymbolData->Fragment) { assert(coff_symbol.Section != nullptr); 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) { 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; // We want a deterministic output. It looks like GNU as also writes 0 in here. Header.TimeDateStamp = 0; // 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 *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()]; 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(); unsigned FixupKind = Fixup.getKind(); if (CrossSection) FixupKind = FK_PCRel_4; Reloc.Data.Type = TargetObjectWriter->getRelocType(FixupKind); // 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 MCSymbol *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().reportError(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().reportError(Fixup.getLoc(), "Invalid relocation on conditional branch!"); return; } if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size, Asm)) { Asm.getContext().reportError(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().reportError(Fixup.getLoc(), "PC relative absolute relocation!"); return; // 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 MCSymbol *A_Base = Asm.getAtom(*A); const MCSymbol *B = &Target.getSymB()->getSymbol(); const MCSymbol *B_Base = Asm.getAtom(*B); // 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) == 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().reportError(Fixup.getLoc(), "unsupported relocation of modified symbol"); return; } // We don't support PCrel relocations of differences. if (IsPCRel) { Asm.getContext().reportError(Fixup.getLoc(), "unsupported pc-relative relocation of " "difference"); return; } // 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().reportError( Fixup.getLoc(), "unsupported relocation of local symbol '" + A->getName() + "'. Must have non-local symbol earlier in section."); return; } if (!B_Base) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported relocation of local symbol '" + B->getName() + "'. Must have non-local symbol earlier in section."); return; } if (A_Base == B_Base && A_Base) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported relocation with identical base"); return; } Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Layout)) - (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress( *A_Base, Layout)); Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, 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()); bool CanUseLocalRelocation = canUseLocalRelocation(Section, *Symbol, Log2Size); if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) { const MCSection &Sec = Symbol->getSection(); if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) Symbol->setUsedInReloc(); } const MCSymbol *Base = Asm.getAtom(*Symbol); // 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 (Symbol->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().reportError(Fixup.getLoc(), "unable to resolve variable '" + Symbol->getName() + "'"); return; } 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 != Symbol) Value += Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*Base); } else if (Symbol->isInSection()) { if (!CanUseLocalRelocation) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported relocation of local symbol '" + Symbol->getName() + "'. Must have non-local symbol earlier in section."); return; } // Adjust the relocation to be section-relative. // The index is the section ordinal (1-based). const MCSection &Sec = Symbol->getSection(); Index = Sec.getOrdinal() + 1; Value += Writer->getSymbolAddress(*Symbol, Layout); if (IsPCRel) Value -= Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset() + (1ULL << Log2Size); } else { // Resolve constant variables. if (Symbol->isVariable()) { int64_t Res; if (Symbol->getVariableValue()->evaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } } Asm.getContext().reportError(Fixup.getLoc(), "unsupported relocation of variable '" + Symbol->getName() + "'"); return; } } // 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); }
bool MachObjectWriter:: IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, const MCSymbolData &DataA, const MCFragment &FB, bool InSet, bool IsPCRel) const { if (InSet) return true; // The effective address is // addr(atom(A)) + offset(A) // - addr(atom(B)) - offset(B) // and the offsets are not relocatable, so the fixup is fully resolved when // addr(atom(A)) - addr(atom(B)) == 0. const MCSymbolData *A_Base = 0, *B_Base = 0; const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); const MCSection &SecA = SA.getSection(); const MCSection &SecB = FB.getParent()->getSection(); if (IsPCRel) { // 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. if (!Asm.getBackend().hasReliableSymbolDifference()) { if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) return false; return true; } // For Darwin x86_64, there is one special case when the reference IsPCRel. // If the fragment with the reference does not have a base symbol but meets // the simple way of dealing with this, in that it is a temporary symbol in // the same atom then it is assumed to be fully resolved. This is needed so // a relocation entry is not created and so the static linker does not // mess up the reference later. else if(!FB.getAtom() && SA.isTemporary() && SA.isInSection() && &SecA == &SecB){ return true; } } else { if (!TargetObjectWriter->useAggressiveSymbolFolding()) return false; } const MCFragment *FA = Asm.getSymbolData(SA).getFragment(); // Bail if the symbol has no fragment. if (!FA) return false; A_Base = FA->getAtom(); if (!A_Base) return false; B_Base = FB.getAtom(); if (!B_Base) return false; // If the atoms are the same, they are guaranteed to have the same address. if (A_Base == B_Base) return true; // Otherwise, we can't prove this is fully resolved. return false; }
void MachObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; uint64_t LoadCommandsSize = is64Bit() ? macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size : macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size; // Add the symbol table load command sizes, if used. unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + UndefinedSymbolData.size(); if (NumSymbols) { NumLoadCommands += 2; LoadCommandsSize += (macho::SymtabLoadCommandSize + macho::DysymtabLoadCommandSize); } // Compute the total size of the section data, as well as its file size and vm // size. uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size : macho::Header32Size) + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData &SD = *it; uint64_t Address = getSectionAddress(&SD); uint64_t Size = Layout.getSectionAddressSize(&SD); uint64_t FileSize = Layout.getSectionFileSize(&SD); FileSize += getPaddingSize(&SD, Layout); VMSize = std::max(VMSize, Address + Size); if (SD.getSection().isVirtualSection()) continue; SectionDataSize = std::max(SectionDataSize, Address + Size); SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); } // The section data is padded to 4 bytes. // // FIXME: Is this machine dependent? unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); SectionDataFileSize += SectionDataPadding; // Write the prolog, starting with the header and load command... WriteHeader(NumLoadCommands, LoadCommandsSize, Asm.getSubsectionsViaSymbols()); WriteSegmentLoadCommand(NumSections, VMSize, SectionDataStart, SectionDataSize); // ... and then the section headers. uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; unsigned NumRelocs = Relocs.size(); uint64_t SectionStart = SectionDataStart + getSectionAddress(it); WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * macho::RelocationInfoSize; } // Write the symbol table load command, if used. if (NumSymbols) { unsigned FirstLocalSymbol = 0; unsigned NumLocalSymbols = LocalSymbolData.size(); unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; unsigned NumExternalSymbols = ExternalSymbolData.size(); unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); unsigned NumSymTabSymbols = NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; uint64_t IndirectSymbolOffset = 0; // If used, the indirect symbols are written after the section data. if (NumIndirectSymbols) IndirectSymbolOffset = RelocTableEnd; // The symbol table is written after the indirect symbol data. uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize; // The string table is written after symbol table. uint64_t StringTableOffset = SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size : macho::Nlist32Size); WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.size()); WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, FirstExternalSymbol, NumExternalSymbols, FirstUndefinedSymbol, NumUndefinedSymbols, IndirectSymbolOffset, NumIndirectSymbols); } // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { Asm.WriteSectionData(it, Layout); uint64_t Pad = getPaddingSize(it, Layout); for (unsigned int i = 0; i < Pad; ++i) Write8(0); } // Write the extra padding. WriteZeros(SectionDataPadding); // Write the relocation entries. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { // Write the section relocation entries, in reverse order to match 'as' // (approximately, the exact algorithm is more complicated than this). std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { Write32(Relocs[e - i - 1].Word0); Write32(Relocs[e - i - 1].Word1); } } // Write the symbol table data, if used. if (NumSymbols) { // Write the indirect symbol entries. for (MCAssembler::const_indirect_symbol_iterator it = Asm.indirect_symbol_begin(), ie = Asm.indirect_symbol_end(); it != ie; ++it) { // Indirect symbols in the non lazy symbol pointer section have some // special handling. const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(it->SectionData->getSection()); if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !Asm.getSymbolData(*it->Symbol).isExternal()) { uint32_t Flags = macho::ISF_Local; if (it->Symbol->isAbsolute()) Flags |= macho::ISF_Absolute; Write32(Flags); continue; } } Write32(Asm.getSymbolData(*it->Symbol).getIndex()); } // FIXME: Check that offsets match computed ones. // Write the symbol table entries. for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) WriteNlist(LocalSymbolData[i], Layout); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) WriteNlist(ExternalSymbolData[i], Layout); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) WriteNlist(UndefinedSymbolData[i], Layout); // Write the string table. OS << StringTable.str(); } }
// If bundle alignment is used and there are any instructions in the section, it // needs to be aligned to at least the bundle size. static void setSectionAlignmentForBundling(const MCAssembler &Assembler, MCSection *Section) { if (Section && Assembler.isBundlingEnabled() && Section->hasInstructions() && Section->getAlignment() < Assembler.getBundleAlignSize()) Section->setAlignment(Assembler.getBundleAlignSize()); }
/// ComputeSymbolTable - Compute the symbol table data /// /// \param StringTable [out] - The string table data. /// \param StringIndexMap [out] - Map from symbol names to offsets in the /// string table. void MachObjectWriter:: ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, std::vector<MachSymbolData> &LocalSymbolData, std::vector<MachSymbolData> &ExternalSymbolData, std::vector<MachSymbolData> &UndefinedSymbolData) { // Build section lookup table. DenseMap<const MCSection*, uint8_t> SectionIndexMap; unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it, ++Index) SectionIndexMap[&it->getSection()] = Index; assert(Index <= 256 && "Too many sections!"); // Index 0 is always the empty string. StringMap<uint64_t> StringIndexMap; StringTable += '\x00'; // Build the symbol arrays and the string table, but only for non-local // symbols. // // The particular order that we collect the symbols and create the string // table, then sort the symbols is chosen to match 'as'. Even though it // doesn't matter for correctness, this is important for letting us diff .o // files. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (!it->isExternal() && !Symbol.isUndefined()) continue; uint64_t &Entry = StringIndexMap[Symbol.getName()]; if (!Entry) { Entry = StringTable.size(); StringTable += Symbol.getName(); StringTable += '\x00'; } MachSymbolData MSD; MSD.SymbolData = it; MSD.StringIndex = Entry; if (Symbol.isUndefined()) { MSD.SectionIndex = 0; UndefinedSymbolData.push_back(MSD); } else if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; ExternalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); ExternalSymbolData.push_back(MSD); } } // Now add the data for local symbols. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (it->isExternal() || Symbol.isUndefined()) continue; uint64_t &Entry = StringIndexMap[Symbol.getName()]; if (!Entry) { Entry = StringTable.size(); StringTable += Symbol.getName(); StringTable += '\x00'; } MachSymbolData MSD; MSD.SymbolData = it; MSD.StringIndex = Entry; if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; LocalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); LocalSymbolData.push_back(MSD); } } // External and undefined symbols are required to be in lexicographic order. std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); // The string table is padded to a multiple of 4. while (StringTable.size() % 4) StringTable += '\x00'; }
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 MachObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; uint64_t LoadCommandsSize = is64Bit() ? sizeof(MachO::segment_command_64) + NumSections * sizeof(MachO::section_64): sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); // Add the data-in-code load command size, if used. unsigned NumDataRegions = Asm.getDataRegions().size(); if (NumDataRegions) { ++NumLoadCommands; LoadCommandsSize += sizeof(MachO::linkedit_data_command); } // Add the symbol table load command sizes, if used. unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + UndefinedSymbolData.size(); if (NumSymbols) { NumLoadCommands += 2; LoadCommandsSize += (sizeof(MachO::symtab_command) + sizeof(MachO::dysymtab_command)); } // Add the linker option load commands sizes. const std::vector<std::vector<std::string> > &LinkerOptions = Asm.getLinkerOptions(); for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) { ++NumLoadCommands; LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(LinkerOptions[i], is64Bit()); } // Compute the total size of the section data, as well as its file size and vm // size. uint64_t SectionDataStart = (is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header)) + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData &SD = *it; uint64_t Address = getSectionAddress(&SD); uint64_t Size = Layout.getSectionAddressSize(&SD); uint64_t FileSize = Layout.getSectionFileSize(&SD); FileSize += getPaddingSize(&SD, Layout); VMSize = std::max(VMSize, Address + Size); if (SD.getSection().isVirtualSection()) continue; SectionDataSize = std::max(SectionDataSize, Address + Size); SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); } // The section data is padded to 4 bytes. // // FIXME: Is this machine dependent? unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); SectionDataFileSize += SectionDataPadding; // Write the prolog, starting with the header and load command... WriteHeader(NumLoadCommands, LoadCommandsSize, Asm.getSubsectionsViaSymbols()); WriteSegmentLoadCommand(NumSections, VMSize, SectionDataStart, SectionDataSize); // ... and then the section headers. uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { std::vector<MachO::any_relocation_info> &Relocs = Relocations[it]; unsigned NumRelocs = Relocs.size(); uint64_t SectionStart = SectionDataStart + getSectionAddress(it); WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * sizeof(MachO::any_relocation_info); } // Write the data-in-code load command, if used. uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8; if (NumDataRegions) { uint64_t DataRegionsOffset = RelocTableEnd; uint64_t DataRegionsSize = NumDataRegions * 8; WriteLinkeditLoadCommand(MachO::LC_DATA_IN_CODE, DataRegionsOffset, DataRegionsSize); } // Write the symbol table load command, if used. if (NumSymbols) { unsigned FirstLocalSymbol = 0; unsigned NumLocalSymbols = LocalSymbolData.size(); unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; unsigned NumExternalSymbols = ExternalSymbolData.size(); unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); unsigned NumSymTabSymbols = NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; uint64_t IndirectSymbolOffset = 0; // If used, the indirect symbols are written after the section data. if (NumIndirectSymbols) IndirectSymbolOffset = DataInCodeTableEnd; // The symbol table is written after the indirect symbol data. uint64_t SymbolTableOffset = DataInCodeTableEnd + IndirectSymbolSize; // The string table is written after symbol table. uint64_t StringTableOffset = SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist)); WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.size()); WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, FirstExternalSymbol, NumExternalSymbols, FirstUndefinedSymbol, NumUndefinedSymbols, IndirectSymbolOffset, NumIndirectSymbols); } // Write the linker options load commands. for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) { WriteLinkerOptionsLoadCommand(LinkerOptions[i]); } // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { Asm.writeSectionData(it, Layout); uint64_t Pad = getPaddingSize(it, Layout); for (unsigned int i = 0; i < Pad; ++i) Write8(0); } // Write the extra padding. WriteZeros(SectionDataPadding); // Write the relocation entries. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { // Write the section relocation entries, in reverse order to match 'as' // (approximately, the exact algorithm is more complicated than this). std::vector<MachO::any_relocation_info> &Relocs = Relocations[it]; for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { Write32(Relocs[e - i - 1].r_word0); Write32(Relocs[e - i - 1].r_word1); } } // Write out the data-in-code region payload, if there is one. for (MCAssembler::const_data_region_iterator it = Asm.data_region_begin(), ie = Asm.data_region_end(); it != ie; ++it) { const DataRegionData *Data = &(*it); uint64_t Start = getSymbolAddress(&Layout.getAssembler().getSymbolData(*Data->Start), Layout); uint64_t End = getSymbolAddress(&Layout.getAssembler().getSymbolData(*Data->End), Layout); DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind << " start: " << Start << "(" << Data->Start->getName() << ")" << " end: " << End << "(" << Data->End->getName() << ")" << " size: " << End - Start << "\n"); Write32(Start); Write16(End - Start); Write16(Data->Kind); } // Write the symbol table data, if used. if (NumSymbols) { // Write the indirect symbol entries. for (MCAssembler::const_indirect_symbol_iterator it = Asm.indirect_symbol_begin(), ie = Asm.indirect_symbol_end(); it != ie; ++it) { // Indirect symbols in the non-lazy symbol pointer section have some // special handling. const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(it->SectionData->getSection()); if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !Asm.getSymbolData(*it->Symbol).isExternal()) { uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL; if (it->Symbol->isAbsolute()) Flags |= MachO::INDIRECT_SYMBOL_ABS; Write32(Flags); continue; } } Write32(Asm.getSymbolData(*it->Symbol).getIndex()); } // FIXME: Check that offsets match computed ones. // Write the symbol table entries. for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) WriteNlist(LocalSymbolData[i], Layout); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) WriteNlist(ExternalSymbolData[i], Layout); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) WriteNlist(UndefinedSymbolData[i], Layout); // Write the string table. OS << StringTable.str(); } }
void MachObjectWriter::BindIndirectSymbols(MCAssembler &Asm) { // This is the point where 'as' creates actual symbols for indirect symbols // (in the following two passes). It would be easier for us to do this sooner // when we see the attribute, but that makes getting the order in the symbol // table much more complicated than it is worth. // // FIXME: Revisit this when the dust settles. // Report errors for use of .indirect_symbol not in a symbol pointer section // or stub section. for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), ie = Asm.indirect_symbol_end(); it != ie; ++it) { const MCSectionMachO &Section = cast<MCSectionMachO>(it->SectionData->getSection()); if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS && Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) { MCSymbol &Symbol = *it->Symbol; report_fatal_error("indirect symbol '" + Symbol.getName() + "' not in a symbol pointer or stub section"); } } // 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, ++IndirectIndex) { const MCSectionMachO &Section = cast<MCSectionMachO>(it->SectionData->getSection()); if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) continue; // Initialize the section indirect symbol base, if necessary. IndirectSymBase.insert(std::make_pair(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, ++IndirectIndex) { const MCSectionMachO &Section = cast<MCSectionMachO>(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. IndirectSymBase.insert(std::make_pair(it->SectionData, IndirectIndex)); // Set the symbol type to undefined lazy, but only on construction. // // FIXME: Do not hardcode. bool Created; MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created); if (Created) Entry.setFlags(Entry.getFlags() | 0x0001); } }
/// \brief Write the fragment \p F to the output file. static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F) { MCObjectWriter *OW = &Asm.getWriter(); // FIXME: Embed in fragments instead? uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); Asm.writeFragmentPadding(F, FragmentSize, OW); // This variable (and its dummy usage) is to participate in the assert at // the end of the function. uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; switch (F.getKind()) { case MCFragment::FT_Align: { ++stats::EmittedAlignFragments; const MCAlignFragment &AF = cast<MCAlignFragment>(F); assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!"); uint64_t Count = FragmentSize / AF.getValueSize(); // FIXME: This error shouldn't actually occur (the front end should emit // multiple .align directives to enforce the semantics it wants), but is // severe enough that we want to report it. How to handle this? if (Count * AF.getValueSize() != FragmentSize) report_fatal_error("undefined .align directive, value size '" + Twine(AF.getValueSize()) + "' is not a divisor of padding size '" + Twine(FragmentSize) + "'"); // See if we are aligning with nops, and if so do that first to try to fill // the Count bytes. Then if that did not fill any bytes or there are any // bytes left to fill use the Value and ValueSize to fill the rest. // If we are aligning with nops, ask that target to emit the right data. if (AF.hasEmitNops()) { if (!Asm.getBackend().writeNopData(Count, OW)) report_fatal_error("unable to write nop sequence of " + Twine(Count) + " bytes"); break; } // Otherwise, write out in multiples of the value size. for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: llvm_unreachable("Invalid size!"); case 1: OW->write8 (uint8_t (AF.getValue())); break; case 2: OW->write16(uint16_t(AF.getValue())); break; case 4: OW->write32(uint32_t(AF.getValue())); break; case 8: OW->write64(uint64_t(AF.getValue())); break; } } break; } case MCFragment::FT_Data: ++stats::EmittedDataFragments; OW->writeBytes(cast<MCDataFragment>(F).getContents()); break; case MCFragment::FT_Relaxable: ++stats::EmittedRelaxableFragments; OW->writeBytes(cast<MCRelaxableFragment>(F).getContents()); break; case MCFragment::FT_CompactEncodedInst: ++stats::EmittedCompactEncodedInstFragments; OW->writeBytes(cast<MCCompactEncodedInstFragment>(F).getContents()); break; case MCFragment::FT_Fill: { ++stats::EmittedFillFragments; const MCFillFragment &FF = cast<MCFillFragment>(F); uint8_t V = FF.getValue(); const unsigned MaxChunkSize = 16; char Data[MaxChunkSize]; memcpy(Data, &V, 1); for (unsigned I = 1; I < MaxChunkSize; ++I) Data[I] = Data[0]; uint64_t Size = FF.getSize(); for (unsigned ChunkSize = MaxChunkSize; ChunkSize; ChunkSize /= 2) { StringRef Ref(Data, ChunkSize); for (uint64_t I = 0, E = Size / ChunkSize; I != E; ++I) OW->writeBytes(Ref); Size = Size % ChunkSize; } break; } case MCFragment::FT_LEB: { const MCLEBFragment &LF = cast<MCLEBFragment>(F); OW->writeBytes(LF.getContents()); break; } case MCFragment::FT_SafeSEH: { const MCSafeSEHFragment &SF = cast<MCSafeSEHFragment>(F); OW->write32(SF.getSymbol()->getIndex()); break; } case MCFragment::FT_Org: { ++stats::EmittedOrgFragments; const MCOrgFragment &OF = cast<MCOrgFragment>(F); for (uint64_t i = 0, e = FragmentSize; i != e; ++i) OW->write8(uint8_t(OF.getValue())); break; } case MCFragment::FT_Dwarf: { const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); OW->writeBytes(OF.getContents()); break; } case MCFragment::FT_DwarfFrame: { const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F); OW->writeBytes(CF.getContents()); break; } case MCFragment::FT_CVInlineLines: { const auto &OF = cast<MCCVInlineLineTableFragment>(F); OW->writeBytes(OF.getContents()); break; } case MCFragment::FT_CVDefRange: { const auto &DRF = cast<MCCVDefRangeFragment>(F); OW->writeBytes(DRF.getContents()); break; } case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } assert(OW->getStream().tell() - Start == FragmentSize && "The stream should advance by fragment size"); }
void ELFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { MCContext &Ctx = Asm.getContext(); MCSectionELF *StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); StringTableIndex = addToSectionTable(StrtabSection); RevGroupMapTy RevGroupMap; SectionIndexMapTy SectionIndexMap; std::map<const MCSymbol *, std::vector<const MCSectionELF *>> GroupMembers; // Write out the ELF header ... writeHeader(Asm); // ... then the sections ... SectionOffsetsTy SectionOffsets; std::vector<MCSectionELF *> Groups; std::vector<MCSectionELF *> Relocations; for (MCSection &Sec : Asm) { MCSectionELF &Section = static_cast<MCSectionELF &>(Sec); align(Section.getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); const MCSymbolELF *SignatureSymbol = Section.getGroup(); writeSectionData(Asm, Section, Layout); uint64_t SecEnd = getStream().tell(); SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); MCSectionELF *RelSection = createRelocationSection(Ctx, Section); if (SignatureSymbol) { Asm.registerSymbol(*SignatureSymbol); unsigned &GroupIdx = RevGroupMap[SignatureSymbol]; if (!GroupIdx) { MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol); GroupIdx = addToSectionTable(Group); Group->setAlignment(4); Groups.push_back(Group); } std::vector<const MCSectionELF *> &Members = GroupMembers[SignatureSymbol]; Members.push_back(&Section); if (RelSection) Members.push_back(RelSection); } SectionIndexMap[&Section] = addToSectionTable(&Section); if (RelSection) { SectionIndexMap[RelSection] = addToSectionTable(RelSection); Relocations.push_back(RelSection); } } for (MCSectionELF *Group : Groups) { align(Group->getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); const MCSymbol *SignatureSymbol = Group->getGroup(); assert(SignatureSymbol); write(uint32_t(ELF::GRP_COMDAT)); for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) { uint32_t SecIndex = SectionIndexMap.lookup(Member); write(SecIndex); } uint64_t SecEnd = getStream().tell(); SectionOffsets[Group] = std::make_pair(SecStart, SecEnd); } // Compute symbol table information. computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets); for (MCSectionELF *RelSection : Relocations) { align(RelSection->getAlignment()); // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); writeRelocations(Asm, *RelSection->getAssociatedSection()); uint64_t SecEnd = getStream().tell(); SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); } { uint64_t SecStart = getStream().tell(); const MCSectionELF *Sec = createStringTable(Ctx); uint64_t SecEnd = getStream().tell(); SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); } uint64_t NaturalAlignment = is64Bit() ? 8 : 4; align(NaturalAlignment); const uint64_t SectionHeaderOffset = getStream().tell(); // ... then the section header table ... writeSectionHeader(Layout, SectionIndexMap, SectionOffsets); uint16_t NumSections = (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF : SectionTable.size() + 1; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(NumSections); unsigned NumSectionsOffset; if (is64Bit()) { uint64_t Val = SectionHeaderOffset; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(Val); getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), offsetof(ELF::Elf64_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum); } else { uint32_t Val = SectionHeaderOffset; if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(Val); getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), offsetof(ELF::Elf32_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum); } getStream().pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections), NumSectionsOffset); }
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"); 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(); 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; coff_section->Relocations.push_back(Reloc); }
// It is always valid to create a relocation with a symbol. It is preferable // to use a relocation with a section if that is possible. Using the section // allows us to omit some local symbols from the symbol table. bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, const MCSymbolRefExpr *RefA, const MCSymbol *S, uint64_t C, unsigned Type) const { const auto *Sym = cast_or_null<MCSymbolELF>(S); // A PCRel relocation to an absolute value has no symbol (or section). We // represent that with a relocation to a null section. if (!RefA) return false; MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); switch (Kind) { default: break; // The .odp creation emits a relocation against the symbol ".TOC." which // create a R_PPC64_TOC relocation. However the relocation symbol name // in final object creation should be NULL, since the symbol does not // really exist, it is just the reference to TOC base for the current // object file. Since the symbol is undefined, returning false results // in a relocation with a null section which is the desired result. case MCSymbolRefExpr::VK_PPC_TOCBASE: return false; // These VariantKind cause the relocation to refer to something other than // the symbol itself, like a linker generated table. Since the address of // symbol is not relevant, we cannot replace the symbol with the // section and patch the difference in the addend. case MCSymbolRefExpr::VK_GOT: case MCSymbolRefExpr::VK_PLT: case MCSymbolRefExpr::VK_GOTPCREL: case MCSymbolRefExpr::VK_PPC_GOT_LO: case MCSymbolRefExpr::VK_PPC_GOT_HI: case MCSymbolRefExpr::VK_PPC_GOT_HA: return true; } // An undefined symbol is not in any section, so the relocation has to point // to the symbol itself. assert(Sym && "Expected a symbol"); if (Sym->isUndefined()) return true; unsigned Binding = Sym->getBinding(); switch(Binding) { default: llvm_unreachable("Invalid Binding"); case ELF::STB_LOCAL: break; case ELF::STB_WEAK: // If the symbol is weak, it might be overridden by a symbol in another // file. The relocation has to point to the symbol so that the linker // can update it. return true; case ELF::STB_GLOBAL: // Global ELF symbols can be preempted by the dynamic linker. The relocation // has to point to the symbol for a reason analogous to the STB_WEAK case. return true; } // If a relocation points to a mergeable section, we have to be careful. // If the offset is zero, a relocation with the section will encode the // same information. With a non-zero offset, the situation is different. // For example, a relocation can point 42 bytes past the end of a string. // If we change such a relocation to use the section, the linker would think // that it pointed to another string and subtracting 42 at runtime will // produce the wrong value. auto &Sec = cast<MCSectionELF>(Sym->getSection()); unsigned Flags = Sec.getFlags(); if (Flags & ELF::SHF_MERGE) { if (C != 0) return true; // It looks like gold has a bug (http://sourceware.org/PR16794) and can // only handle section relocations to mergeable sections if using RELA. if (!hasRelocationAddend()) return true; } // Most TLS relocations use a got, so they need the symbol. Even those that // are just an offset (@tpoff), require a symbol in gold versions before // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed // http://sourceware.org/PR16773. if (Flags & ELF::SHF_TLS) return true; // If the symbol is a thumb function the final relocation must set the lowest // bit. With a symbol that is done by just having the symbol have that bit // set, so we would lose the bit if we relocated with the section. // FIXME: We could use the section but add the bit to the relocation value. if (Asm.isThumbFunc(Sym)) return true; if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) return true; return false; }
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 ELFObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) { 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()) { assert(RefB->getKind() == MCSymbolRefExpr::VK_None && "Should not have constructed this"); // 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); }
bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo( const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym, unsigned &Log2Size, const MCAssembler &Asm) { RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED); Log2Size = ~0U; switch ((unsigned)Fixup.getKind()) { default: return false; case FK_Data_1: Log2Size = Log2_32(1); return true; case FK_Data_2: Log2Size = Log2_32(2); return true; case FK_Data_4: Log2Size = Log2_32(4); if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); return true; case FK_Data_8: Log2Size = Log2_32(8); if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); return true; case AArch64::fixup_aarch64_add_imm12: case AArch64::fixup_aarch64_ldst_imm12_scale1: case AArch64::fixup_aarch64_ldst_imm12_scale2: case AArch64::fixup_aarch64_ldst_imm12_scale4: case AArch64::fixup_aarch64_ldst_imm12_scale8: case AArch64::fixup_aarch64_ldst_imm12_scale16: Log2Size = Log2_32(4); switch (Sym->getKind()) { default: return false; case MCSymbolRefExpr::VK_PAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12); return true; case MCSymbolRefExpr::VK_GOTPAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12); return true; case MCSymbolRefExpr::VK_TLVPPAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12); return true; } case AArch64::fixup_aarch64_pcrel_adrp_imm21: Log2Size = Log2_32(4); // This encompasses the relocation for the whole 21-bit value. switch (Sym->getKind()) { default: Asm.getContext().reportError(Fixup.getLoc(), "ADR/ADRP relocations must be GOT relative"); return false; case MCSymbolRefExpr::VK_PAGE: RelocType = unsigned(MachO::ARM64_RELOC_PAGE21); return true; case MCSymbolRefExpr::VK_GOTPAGE: RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21); return true; case MCSymbolRefExpr::VK_TLVPPAGE: RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21); return true; } return true; case AArch64::fixup_aarch64_pcrel_branch26: case AArch64::fixup_aarch64_pcrel_call26: Log2Size = Log2_32(4); RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26); return true; } }
void ELFObjectWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets) { MCContext &Ctx = Asm.getContext(); SymbolTableWriter Writer(*this, is64Bit()); // Symbol table unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; MCSectionELF *SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, ""); SymtabSection->setAlignment(is64Bit() ? 8 : 4); SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); uint64_t SecStart = getStream().tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); std::vector<ELFSymbolData> LocalSymbolData; std::vector<ELFSymbolData> ExternalSymbolData; // Add the data for the symbols. bool HasLargeSectionIndex = false; for (const MCSymbol &S : Asm.symbols()) { const auto &Symbol = cast<MCSymbolELF>(S); bool Used = Symbol.isUsedInReloc(); bool WeakrefUsed = Symbol.isWeakrefUsedInReloc(); bool isSignature = Symbol.isSignature(); if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, Renames.count(&Symbol))) continue; if (Symbol.isTemporary() && Symbol.isUndefined()) { Ctx.reportError(SMLoc(), "Undefined temporary symbol"); continue; } ELFSymbolData MSD; MSD.Symbol = cast<MCSymbolELF>(&Symbol); bool Local = Symbol.getBinding() == ELF::STB_LOCAL; assert(Local || !Symbol.isTemporary()); if (Symbol.isAbsolute()) { MSD.SectionIndex = ELF::SHN_ABS; } else if (Symbol.isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; } else if (Symbol.isUndefined()) { if (isSignature && !Used) { MSD.SectionIndex = RevGroupMap.lookup(&Symbol); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } else { MSD.SectionIndex = ELF::SHN_UNDEF; } } else { const MCSectionELF &Section = static_cast<const MCSectionELF &>(Symbol.getSection()); MSD.SectionIndex = SectionIndexMap.lookup(&Section); assert(MSD.SectionIndex && "Invalid section index!"); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } // The @@@ in symbol version is replaced with @ in undefined symbols and @@ // in defined ones. // // FIXME: All name handling should be done before we get to the writer, // including dealing with GNU-style version suffixes. Fixing this isn't // trivial. // // We thus have to be careful to not perform the symbol version replacement // blindly: // // The ELF format is used on Windows by the MCJIT engine. Thus, on // Windows, the ELFObjectWriter can encounter symbols mangled using the MS // Visual Studio C++ name mangling scheme. Symbols mangled using the MSVC // C++ name mangling can legally have "@@@" as a sub-string. In that case, // the EFLObjectWriter should not interpret the "@@@" sub-string as // specifying GNU-style symbol versioning. The ELFObjectWriter therefore // checks for the MSVC C++ name mangling prefix which is either "?", "@?", // "__imp_?" or "__imp_@?". // // It would have been interesting to perform the MS mangling prefix check // only when the target triple is of the form *-pc-windows-elf. But, it // seems that this information is not easily accessible from the // ELFObjectWriter. StringRef Name = Symbol.getName(); SmallString<32> Buf; if (!Name.startswith("?") && !Name.startswith("@?") && !Name.startswith("__imp_?") && !Name.startswith("__imp_@?")) { // This symbol isn't following the MSVC C++ name mangling convention. We // can thus safely interpret the @@@ in symbol names as specifying symbol // versioning. size_t Pos = Name.find("@@@"); if (Pos != StringRef::npos) { Buf += Name.substr(0, Pos); unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; Buf += Name.substr(Pos + Skip); Name = VersionSymSaver.save(Buf.c_str()); } } // Sections have their own string table if (Symbol.getType() != ELF::STT_SECTION) { MSD.Name = Name; StrTabBuilder.add(Name); } if (Local) LocalSymbolData.push_back(MSD); else ExternalSymbolData.push_back(MSD); } // This holds the .symtab_shndx section index. unsigned SymtabShndxSectionIndex = 0; if (HasLargeSectionIndex) { MCSectionELF *SymtabShndxSection = Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection); SymtabShndxSection->setAlignment(4); } ArrayRef<std::string> FileNames = Asm.getFileNames(); for (const std::string &Name : FileNames) StrTabBuilder.add(Name); StrTabBuilder.finalize(); for (const std::string &Name : FileNames) Writer.writeSymbol(StrTabBuilder.getOffset(Name), ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT, ELF::SHN_ABS, true); // Symbols are required to be in lexicographic order. array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); // Set the symbol indices. Local symbols must come before all other // symbols with non-local bindings. unsigned Index = FileNames.size() + 1; for (ELFSymbolData &MSD : LocalSymbolData) { unsigned StringIndex = MSD.Symbol->getType() == ELF::STT_SECTION ? 0 : StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); } // Write the symbol table entries. LastLocalSymbolIndex = Index; for (ELFSymbolData &MSD : ExternalSymbolData) { unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } uint64_t SecEnd = getStream().tell(); SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes(); if (ShndxIndexes.empty()) { assert(SymtabShndxSectionIndex == 0); return; } assert(SymtabShndxSectionIndex != 0); SecStart = getStream().tell(); const MCSectionELF *SymtabShndxSection = SectionTable[SymtabShndxSectionIndex - 1]; for (uint32_t Index : ShndxIndexes) write(Index); SecEnd = getStream().tell(); SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); }
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::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); }
/// computeSymbolTable - Compute the symbol table data void MachObjectWriter::computeSymbolTable( MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData, std::vector<MachSymbolData> &ExternalSymbolData, std::vector<MachSymbolData> &UndefinedSymbolData) { // Build section lookup table. DenseMap<const MCSection*, uint8_t> SectionIndexMap; unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it, ++Index) SectionIndexMap[&*it] = Index; assert(Index <= 256 && "Too many sections!"); // Build the string table. for (const MCSymbol &Symbol : Asm.symbols()) { if (!Asm.isSymbolLinkerVisible(Symbol)) continue; StringTable.add(Symbol.getName()); } StringTable.finalize(); // Build the symbol arrays but only for non-local symbols. // // The particular order that we collect and then sort the symbols is chosen to // match 'as'. Even though it doesn't matter for correctness, this is // important for letting us diff .o files. for (const MCSymbol &Symbol : Asm.symbols()) { // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (!Symbol.isExternal() && !Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.Symbol = &Symbol; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isUndefined()) { MSD.SectionIndex = 0; UndefinedSymbolData.push_back(MSD); } else if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; ExternalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); ExternalSymbolData.push_back(MSD); } } // Now add the data for local symbols. for (const MCSymbol &Symbol : Asm.symbols()) { // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (Symbol.isExternal() || Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.Symbol = &Symbol; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; LocalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); LocalSymbolData.push_back(MSD); } } // External and undefined symbols are required to be in lexicographic order. std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; for (auto *SymbolData : {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData}) for (MachSymbolData &Entry : *SymbolData) Entry.Symbol->setIndex(Index++); for (const MCSection &Section : Asm) { for (RelAndSymbol &Rel : Relocations[&Section]) { if (!Rel.Sym) continue; // Set the Index and the IsExtern bit. unsigned Index = Rel.Sym->getIndex(); assert(isInt<24>(Index)); if (IsLittleEndian) Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (~0U << 24)) | Index | (1 << 27); else Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4); } } }
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 MCSymbol *A_Base = Asm.getAtom(*A); const MCSymbol *B = &Target.getSymB()->getSymbol(); if (B->isTemporary()) B = &Writer->findAliasedSymbol(*B); const MCSymbol *B_Base = Asm.getAtom(*B); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) { Asm.getContext().reportError(Fixup.getLoc(), "unsupported relocation of modified symbol"); return; } // We don't support PCrel relocations of differences. Darwin 'as' doesn't // implement most of these correctly. if (IsPCRel) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported pc-relative relocation of difference"); return; } // 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) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported relocation with identical base"); return; } // 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().reportError(Fixup.getLoc(), "unsupported relocation with subtraction expression, symbol '" + Name + "' can not be undefined in a subtraction expression"); return; } Value += Writer->getSymbolAddress(*A, Layout) - (!A_Base ? 0 : Writer->getSymbolAddress(*A_Base, Layout)); Value -= Writer->getSymbolAddress(*B, Layout) - (!B_Base ? 0 : Writer->getSymbolAddress(*B_Base, Layout)); if (!A_Base) Index = A->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->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)) Symbol->setUsedInReloc(); } RelSymbol = Asm.getAtom(*Symbol); // 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()); 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 != Symbol) Value += Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*RelSymbol); } else if (Symbol->isInSection() && !Symbol->isVariable()) { // The index is the section ordinal (1-based). Index = Symbol->getFragment()->getParent()->getOrdinal() + 1; Value += Writer->getSymbolAddress(*Symbol, 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 { Asm.getContext().reportError(Fixup.getLoc(), "unsupported relocation of variable '" + Symbol->getName() + "'"); return; } } else { Asm.getContext().reportError( Fixup.getLoc(), "unsupported relocation of undefined symbol '" + Symbol->getName() + "'"); return; } 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) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported symbol modifier in relocation"); return; } 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) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported symbol modifier in branch relocation"); return; } 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) { Asm.getContext().reportError( Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel"); return; } else if (Modifier != MCSymbolRefExpr::VK_None) { Asm.getContext().reportError( Fixup.getLoc(), "unsupported symbol modifier in relocation"); return; } else { Type = MachO::X86_64_RELOC_UNSIGNED; unsigned Kind = Fixup.getKind(); if (Kind == X86::reloc_signed_4byte) { Asm.getContext().reportError( Fixup.getLoc(), "32-bit absolute addressing is not supported in 64-bit mode"); return; } } } } // 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 MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB, bool InSet, bool IsPCRel) const { if (InSet) return true; // The effective address is // addr(atom(A)) + offset(A) // - addr(atom(B)) - offset(B) // and the offsets are not relocatable, so the fixup is fully resolved when // addr(atom(A)) - addr(atom(B)) == 0. const MCSymbol &SA = findAliasedSymbol(SymA); const MCSection &SecA = SA.getSection(); const MCSection &SecB = *FB.getParent(); if (IsPCRel) { // 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. // // If the file isn't using sub-sections-via-symbols, we can make the // same assumptions about any symbol that we normally make about // assembler locals. bool hasReliableSymbolDifference = isX86_64(); if (!hasReliableSymbolDifference) { if (!SA.isInSection() || &SecA != &SecB || (!SA.isTemporary() && FB.getAtom() != SA.getFragment()->getAtom() && Asm.getSubsectionsViaSymbols())) return false; return true; } // For Darwin x86_64, there is one special case when the reference IsPCRel. // If the fragment with the reference does not have a base symbol but meets // the simple way of dealing with this, in that it is a temporary symbol in // the same atom then it is assumed to be fully resolved. This is needed so // a relocation entry is not created and so the static linker does not // mess up the reference later. else if(!FB.getAtom() && SA.isTemporary() && SA.isInSection() && &SecA == &SecB){ return true; } } // If they are not in the same section, we can't compute the diff. if (&SecA != &SecB) return false; const MCFragment *FA = SA.getFragment(); // Bail if the symbol has no fragment. if (!FA) return false; // If the atoms are the same, they are guaranteed to have the same address. if (FA->getAtom() == FB.getAtom()) return true; // Otherwise, we can't prove this is fully resolved. return false; }
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(); if (!A->getFragment()) { Asm.getContext().reportError( Fixup.getLoc(), "symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); return false; } uint32_t Value = Writer->getSymbolAddress(*A, Layout); uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbol *SB = &B->getSymbol(); if (!SB->getFragment()) { Asm.getContext().reportError( Fixup.getLoc(), "symbol '" + SB->getName() + "' can not be undefined in a subtraction expression"); return 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->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; Value2 = Writer->getSymbolAddress(*SB, Layout); FixedValue -= Writer->getSectionAddress(SB->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().reportError(Fixup.getLoc(), Twine("Section too large, can't encode " "r_address (") + Buffer + ") into 24 bits of scattered " "relocation entry."); return false; } 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; }
/// \brief Write the fragment \p F to the output file. static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F) { MCObjectWriter *OW = &Asm.getWriter(); // FIXME: Embed in fragments instead? uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); // Should NOP padding be written out before this fragment? unsigned BundlePadding = F.getBundlePadding(); if (BundlePadding > 0) { assert(Asm.isBundlingEnabled() && "Writing bundle padding with disabled bundling"); assert(F.hasInstructions() && "Writing bundle padding for a fragment without instructions"); unsigned TotalLength = BundlePadding + static_cast<unsigned>(FragmentSize); if (F.alignToBundleEnd() && TotalLength > Asm.getBundleAlignSize()) { // If the padding itself crosses a bundle boundary, it must be emitted // in 2 pieces, since even nop instructions must not cross boundaries. // v--------------v <- BundleAlignSize // v---------v <- BundlePadding // ---------------------------- // | Prev |####|####| F | // ---------------------------- // ^-------------------^ <- TotalLength unsigned DistanceToBoundary = TotalLength - Asm.getBundleAlignSize(); if (!Asm.getBackend().writeNopData(DistanceToBoundary, OW)) report_fatal_error("unable to write NOP sequence of " + Twine(DistanceToBoundary) + " bytes"); BundlePadding -= DistanceToBoundary; } if (!Asm.getBackend().writeNopData(BundlePadding, OW)) report_fatal_error("unable to write NOP sequence of " + Twine(BundlePadding) + " bytes"); } // This variable (and its dummy usage) is to participate in the assert at // the end of the function. uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; switch (F.getKind()) { case MCFragment::FT_Align: { ++stats::EmittedAlignFragments; const MCAlignFragment &AF = cast<MCAlignFragment>(F); assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!"); uint64_t Count = FragmentSize / AF.getValueSize(); // FIXME: This error shouldn't actually occur (the front end should emit // multiple .align directives to enforce the semantics it wants), but is // severe enough that we want to report it. How to handle this? if (Count * AF.getValueSize() != FragmentSize) report_fatal_error("undefined .align directive, value size '" + Twine(AF.getValueSize()) + "' is not a divisor of padding size '" + Twine(FragmentSize) + "'"); // See if we are aligning with nops, and if so do that first to try to fill // the Count bytes. Then if that did not fill any bytes or there are any // bytes left to fill use the Value and ValueSize to fill the rest. // If we are aligning with nops, ask that target to emit the right data. if (AF.hasEmitNops()) { if (!Asm.getBackend().writeNopData(Count, OW)) report_fatal_error("unable to write nop sequence of " + Twine(Count) + " bytes"); break; } // Otherwise, write out in multiples of the value size. for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: llvm_unreachable("Invalid size!"); case 1: OW->Write8 (uint8_t (AF.getValue())); break; case 2: OW->Write16(uint16_t(AF.getValue())); break; case 4: OW->Write32(uint32_t(AF.getValue())); break; case 8: OW->Write64(uint64_t(AF.getValue())); break; } } break; } case MCFragment::FT_Data: ++stats::EmittedDataFragments; writeFragmentContents(F, OW); break; case MCFragment::FT_Relaxable: ++stats::EmittedRelaxableFragments; writeFragmentContents(F, OW); break; case MCFragment::FT_CompactEncodedInst: ++stats::EmittedCompactEncodedInstFragments; writeFragmentContents(F, OW); break; case MCFragment::FT_Fill: { ++stats::EmittedFillFragments; const MCFillFragment &FF = cast<MCFillFragment>(F); assert(FF.getValueSize() && "Invalid virtual align in concrete fragment!"); for (uint64_t i = 0, e = FF.getSize() / FF.getValueSize(); i != e; ++i) { switch (FF.getValueSize()) { default: llvm_unreachable("Invalid size!"); case 1: OW->Write8 (uint8_t (FF.getValue())); break; case 2: OW->Write16(uint16_t(FF.getValue())); break; case 4: OW->Write32(uint32_t(FF.getValue())); break; case 8: OW->Write64(uint64_t(FF.getValue())); break; } } break; } case MCFragment::FT_LEB: { const MCLEBFragment &LF = cast<MCLEBFragment>(F); OW->WriteBytes(LF.getContents().str()); break; } case MCFragment::FT_Org: { ++stats::EmittedOrgFragments; const MCOrgFragment &OF = cast<MCOrgFragment>(F); for (uint64_t i = 0, e = FragmentSize; i != e; ++i) OW->Write8(uint8_t(OF.getValue())); break; } case MCFragment::FT_Dwarf: { const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); OW->WriteBytes(OF.getContents().str()); break; } case MCFragment::FT_DwarfFrame: { const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F); OW->WriteBytes(CF.getContents().str()); break; } } assert(OW->getStream().tell() - Start == FragmentSize && "The stream should advance by fragment size"); }
void AMDGPUMCObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { for (MCAssembler::iterator I = Asm.begin(), E = Asm.end(); I != E; ++I) { Asm.writeSectionData(&*I, Layout); } }