uint64_t MachObjectWriter::getSymbolAddress(const MCSymbolData* SD, const MCAsmLayout &Layout) const { const MCSymbol &S = SD->getSymbol(); // If this is a variable, then recursively evaluate now. if (S.isVariable()) { MCValue Target; if (!S.getVariableValue()->EvaluateAsRelocatable(Target, Layout)) report_fatal_error("unable to evaluate offset for variable '" + S.getName() + "'"); // Verify that any used symbols are defined. if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined()) report_fatal_error("unable to evaluate offset to undefined symbol '" + Target.getSymA()->getSymbol().getName() + "'"); if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined()) report_fatal_error("unable to evaluate offset to undefined symbol '" + Target.getSymB()->getSymbol().getName() + "'"); uint64_t Address = Target.getConstant(); if (Target.getSymA()) Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( Target.getSymA()->getSymbol()), Layout); if (Target.getSymB()) Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( Target.getSymB()->getSymbol()), Layout); return Address; } return getSectionAddress(SD->getFragment()->getParent()) + Layout.getSymbolOffset(SD); }
void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { // Create dummy fragments and assign section ordinals. unsigned SectionIndex = 0; for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) SectionIndex++; SD.setOrdinal(SectionIndex); // Assign layout order indices to sections and fragments. unsigned FragmentIndex = 0; unsigned i = 0; for (unsigned e = Layout.getSectionOrder().size(); i != e; ++i) { MCSectionData *SD = Layout.getSectionOrder()[i]; for (MCSectionData::iterator it2 = SD->begin(), ie2 = SD->end(); it2 != ie2; ++it2) FragmentIndex++; } SD.setLayoutOrder(i); for (MCSectionData::iterator it2 = SD.begin(), ie2 = SD.end(); it2 != ie2; ++it2) { it2->setLayoutOrder(FragmentIndex++); } Layout.getSectionOrder().push_back(&SD); Layout.LayoutSection(&SD); // Layout until everything fits. while (LayoutOnce(Layout)) continue; }
uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment, const MCAsmLayout &Layout) { assert(Fragment != nullptr && "Fragment cannot be null"); MCFragment const *NextFragment = Fragment->getNextNode(); return NextFragment == nullptr ? Layout.getSectionAddressSize(Fragment->getParent()) : Layout.getFragmentOffset(NextFragment); }
void MCAssembler::writeSectionData(const MCSectionData *SD, const MCAsmLayout &Layout) const { // Ignore virtual sections. if (SD->getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!"); // Check that contents are only things legal inside a virtual section. for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) { switch (it->getKind()) { default: llvm_unreachable("Invalid fragment in virtual section!"); case MCFragment::FT_Data: { // Check that we aren't trying to write a non-zero contents (or fixups) // into a virtual section. This is to support clients which use standard // directives to fill the contents of virtual sections. const MCDataFragment &DF = cast<MCDataFragment>(*it); assert(DF.fixup_begin() == DF.fixup_end() && "Cannot have fixups in virtual section!"); for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) if (DF.getContents()[i]) { if (auto *ELFSec = dyn_cast<const MCSectionELF>(&SD->getSection())) report_fatal_error("non-zero initializer found in section '" + ELFSec->getSectionName() + "'"); else report_fatal_error("non-zero initializer found in virtual section"); } break; } case MCFragment::FT_Align: // Check that we aren't trying to write a non-zero value into a virtual // section. assert((cast<MCAlignFragment>(it)->getValueSize() == 0 || cast<MCAlignFragment>(it)->getValue() == 0) && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: assert((cast<MCFillFragment>(it)->getValueSize() == 0 || cast<MCFillFragment>(it)->getValue() == 0) && "Invalid fill in virtual section!"); break; } } return; } uint64_t Start = getWriter().getStream().tell(); (void)Start; for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) writeFragment(*this, Layout, *it); assert(getWriter().getStream().tell() - Start == Layout.getSectionAddressSize(SD)); }
bool MCCodePadder::relaxFragment(MCPaddingFragment *Fragment, MCAsmLayout &Layout) { if (!Fragment->isInsertionPoint()) return false; uint64_t OldSize = Fragment->getSize(); uint64_t MaxWindowSize = getMaxWindowSize(Fragment, Layout); if (MaxWindowSize == UINT64_C(0)) return false; assert(isPowerOf2_64(MaxWindowSize) && "MaxWindowSize must be an integer power of 2"); uint64_t SectionAlignment = Fragment->getParent()->getAlignment(); assert(isPowerOf2_64(SectionAlignment) && "SectionAlignment must be an integer power of 2"); MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout); uint64_t OptimalSize = UINT64_C(0); double OptimalWeight = std::numeric_limits<double>::max(); uint64_t MaxFragmentSize = MaxWindowSize - UINT16_C(1); for (uint64_t Size = UINT64_C(0); Size <= MaxFragmentSize; ++Size) { Fragment->setSize(Size); Layout.invalidateFragmentsFrom(Fragment); double SizeWeight = 0.0; // The section is guaranteed to be aligned to SectionAlignment, but that // doesn't guarantee the exact section offset w.r.t. the policies window // size. // As a concrete example, the section could be aligned to 16B, but a // policy's window size can be 32B. That means that the section actual start // address can either be 0mod32 or 16mod32. The said policy will act // differently for each case, so we need to take both into consideration. for (uint64_t Offset = UINT64_C(0); Offset < MaxWindowSize; Offset += SectionAlignment) { double OffsetWeight = std::accumulate( CodePaddingPolicies.begin(), CodePaddingPolicies.end(), 0.0, [&Jurisdiction, &Offset, &Layout]( double Weight, const MCCodePaddingPolicy *Policy) -> double { double PolicyWeight = Policy->computeRangePenaltyWeight(Jurisdiction, Offset, Layout); assert(PolicyWeight >= 0.0 && "A penalty weight must be positive"); return Weight + PolicyWeight; }); SizeWeight = std::max(SizeWeight, OffsetWeight); } if (SizeWeight < OptimalWeight) { OptimalWeight = SizeWeight; OptimalSize = Size; } if (OptimalWeight == 0.0) break; } Fragment->setSize(OptimalSize); Layout.invalidateFragmentsFrom(Fragment); return OldSize != OptimalSize; }
uint64_t MachObjectWriter::getPaddingSize(const MCSection *Sec, const MCAsmLayout &Layout) const { uint64_t EndAddr = getSectionAddress(Sec) + Layout.getSectionAddressSize(Sec); unsigned Next = Sec->getLayoutOrder() + 1; if (Next >= Layout.getSectionOrder().size()) return 0; const MCSection &NextSec = *Layout.getSectionOrder()[Next]; if (NextSec.isVirtualSection()) return 0; return OffsetToAlignment(EndAddr, NextSec.getAlignment()); }
void MCAssembler::WriteSectionData(const MCSectionData *SD, const MCAsmLayout &Layout, MCObjectWriter *OW) const { // Ignore virtual sections. if (getBackend().isVirtualSection(SD->getSection())) { assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!"); // Check that contents are only things legal inside a virtual section. for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) { switch (it->getKind()) { default: assert(0 && "Invalid fragment in virtual section!"); case MCFragment::FT_Data: { // Check that we aren't trying to write a non-zero contents (or fixups) // into a virtual section. This is to support clients which use standard // directives to fill the contents of virtual sections. MCDataFragment &DF = cast<MCDataFragment>(*it); assert(DF.fixup_begin() == DF.fixup_end() && "Cannot have fixups in virtual section!"); for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) assert(DF.getContents()[i] == 0 && "Invalid data value for virtual section!"); break; } case MCFragment::FT_Align: // Check that we aren't trying to write a non-zero value into a virtual // section. assert((!cast<MCAlignFragment>(it)->getValueSize() || !cast<MCAlignFragment>(it)->getValue()) && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: assert(!cast<MCFillFragment>(it)->getValueSize() && "Invalid fill in virtual section!"); break; } } return; } uint64_t Start = OW->getStream().tell(); (void) Start; for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) WriteFragmentData(*this, Layout, *it, OW); assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); }
uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: return cast<MCEncodedFragment>(F).getContents().size(); case MCFragment::FT_Fill: return cast<MCFillFragment>(F).getSize(); case MCFragment::FT_LEB: return cast<MCLEBFragment>(F).getContents().size(); case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); unsigned Offset = Layout.getFragmentOffset(&AF); unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); // If we are padding with nops, force the padding to be larger than the // minimum nop size. if (Size > 0 && AF.hasEmitNops()) { while (Size % getBackend().getMinimumNopSize()) Size += AF.getAlignment(); } if (Size > AF.getMaxBytesToEmit()) return 0; return Size; } case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); int64_t TargetLocation; if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, Layout)) report_fatal_error("expected assembly-time absolute expression"); // FIXME: We need a way to communicate this error. uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t Size = TargetLocation - FragmentOffset; if (Size < 0 || Size >= 0x40000000) report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + "' (at offset '" + Twine(FragmentOffset) + "')"); return Size; } case MCFragment::FT_Dwarf: return cast<MCDwarfLineAddrFragment>(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast<MCDwarfCallFrameFragment>(F).getContents().size(); } llvm_unreachable("invalid fragment kind"); }
void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm, const MCAsmLayout &Layout) { uint64_t StartAddress = 0; for (const MCSection *Sec : Layout.getSectionOrder()) { StartAddress = alignTo(StartAddress, Sec->getAlignment()); SectionAddress[Sec] = StartAddress; StartAddress += Layout.getSectionAddressSize(Sec); // Explicitly pad the section to match the alignment requirements of the // following one. This is for 'gas' compatibility, it shouldn't /// strictly be necessary. StartAddress += getPaddingSize(Sec, Layout); } }
uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout) { if (Sym.isCommon() && Sym.isExternal()) return Sym.getCommonAlignment(); uint64_t Res; if (!Layout.getSymbolOffset(Sym, Res)) return 0; if (Layout.getAssembler().isThumbFunc(&Sym)) Res |= 1; return Res; }
void MachObjectWriter::WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCSectionData &SD, uint64_t FileOffset, uint64_t RelocationsStart, unsigned NumRelocations) { uint64_t SectionSize = Layout.getSectionAddressSize(&SD); // The offset is unused for virtual sections. if (SD.getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); FileOffset = 0; } // struct section (68 bytes) or // struct section_64 (80 bytes) uint64_t Start = OS.tell(); (void) Start; const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection()); WriteBytes(Section.getSectionName(), 16); WriteBytes(Section.getSegmentName(), 16); if (is64Bit()) { Write64(getSectionAddress(&SD)); // address Write64(SectionSize); // size } else { Write32(getSectionAddress(&SD)); // address Write32(SectionSize); // size } Write32(FileOffset); unsigned Flags = Section.getTypeAndAttributes(); if (SD.hasInstructions()) Flags |= MCSectionMachO::S_ATTR_SOME_INSTRUCTIONS; assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); Write32(Log2_32(SD.getAlignment())); Write32(NumRelocations ? RelocationsStart : 0); Write32(NumRelocations); Write32(Flags); Write32(IndirectSymBase.lookup(&SD)); // reserved1 Write32(Section.getStubSize()); // reserved2 if (is64Bit()) Write32(0); // reserved3 assert(OS.tell() - Start == (is64Bit() ? macho::Section64Size : macho::Section32Size)); }
uint64_t MachObjectWriter::getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const { // If this is a variable, then recursively evaluate now. if (S.isVariable()) { if (const MCConstantExpr *C = dyn_cast<const MCConstantExpr>(S.getVariableValue())) return C->getValue(); MCValue Target; if (!S.getVariableValue()->evaluateAsRelocatable(Target, &Layout, nullptr)) report_fatal_error("unable to evaluate offset for variable '" + S.getName() + "'"); // Verify that any used symbols are defined. if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined()) report_fatal_error("unable to evaluate offset to undefined symbol '" + Target.getSymA()->getSymbol().getName() + "'"); if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined()) report_fatal_error("unable to evaluate offset to undefined symbol '" + Target.getSymB()->getSymbol().getName() + "'"); uint64_t Address = Target.getConstant(); if (Target.getSymA()) Address += getSymbolAddress(Target.getSymA()->getSymbol(), Layout); if (Target.getSymB()) Address += getSymbolAddress(Target.getSymB()->getSymbol(), Layout); return Address; } return getSectionAddress(S.getFragment()->getParent()) + Layout.getSymbolOffset(S); }
void ELFObjectWriter::writeSectionHeader( const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets) { const unsigned NumSections = SectionTable.size(); // Null section first. uint64_t FirstSectionSize = (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0; WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0); for (const MCSectionELF *Section : SectionTable) { uint32_t GroupSymbolIndex; unsigned Type = Section->getType(); if (Type != ELF::SHT_GROUP) GroupSymbolIndex = 0; else GroupSymbolIndex = Section->getGroup()->getIndex(); const std::pair<uint64_t, uint64_t> &Offsets = SectionOffsets.find(Section)->second; uint64_t Size; if (Type == ELF::SHT_NOBITS) Size = Layout.getSectionAddressSize(Section); else Size = Offsets.second - Offsets.first; writeSection(SectionIndexMap, GroupSymbolIndex, Offsets.first, Size, *Section); } }
bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) { if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF) return false; } } if (Used) return true; if (Renamed) return false; if (Symbol.isVariable() && Symbol.isUndefined()) { // FIXME: this is here just to diagnose the case of a var = commmon_sym. Layout.getBaseSymbol(Symbol); return false; } if (Symbol.isUndefined() && !Symbol.isBindingSet()) return false; if (Symbol.isTemporary()) return false; if (Symbol.getType() == ELF::STT_SECTION) return false; return true; }
void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm, const MCAsmLayout &Layout) { uint64_t StartAddress = 0; const SmallVectorImpl<MCSectionData*> &Order = Layout.getSectionOrder(); for (int i = 0, n = Order.size(); i != n ; ++i) { const MCSectionData *SD = Order[i]; StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); SectionAddress[SD] = StartAddress; StartAddress += Layout.getSectionAddressSize(SD); // Explicitly pad the section to match the alignment requirements of the // following one. This is for 'gas' compatibility, it shouldn't /// strictly be necessary. StartAddress += getPaddingSize(SD, Layout); } }
void SVMELFProgramWriter::writeSectionHeader(const MCAsmLayout &Layout, const MCSectionData *SD) { const MCSectionELF *SE = dyn_cast<MCSectionELF>(&SD->getSection()); assert(SE); uint32_t sh_type = SE->getType(); uint32_t sh_link = 0; uint32_t sh_info = 0; // Type-specific data finds itself in sh_link and sh_info switch (sh_type) { case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: sh_link = EMB.getStringTableIndex(); sh_info = EMB.getLastLocalSymbolIndex(); break; default: break; } Write32(EMB.getSectionStringTableIndex(SE)); // sh_name Write32(sh_type); // sh_type Write32(SE->getFlags()); // sh_flags Write32(ML.getSectionMemAddress(SD)); // sh_addr Write32(ML.getSectionDiskOffset(SD)); // sh_offset Write32(Layout.getSectionFileSize(SD)); // sh_size Write32(sh_link); // sh_link Write32(sh_info); // sh_info Write32(SD->getAlignment()); // sh_addralign Write32(SE->getEntrySize()); // sh_entsize }
uint32_t SVMMemoryLayout::getSectionMemSize(const MCSectionData *SD, const MCAsmLayout &Layout) const { SectionMemSizeOverrides_t::const_iterator it = SectionMemSizeOverrides.find(SD); if (it == SectionMemSizeOverrides.end()) return Layout.getSectionAddressSize(SD); else return it->second; }
void MachObjectWriter::writeSection(const MCAsmLayout &Layout, const MCSection &Sec, uint64_t VMAddr, uint64_t FileOffset, unsigned Flags, uint64_t RelocationsStart, unsigned NumRelocations) { uint64_t SectionSize = Layout.getSectionAddressSize(&Sec); const MCSectionMachO &Section = cast<MCSectionMachO>(Sec); // The offset is unused for virtual sections. if (Section.isVirtualSection()) { assert(Layout.getSectionFileSize(&Sec) == 0 && "Invalid file size!"); FileOffset = 0; } // struct section (68 bytes) or // struct section_64 (80 bytes) uint64_t Start = getStream().tell(); (void) Start; writeBytes(Section.getSectionName(), 16); writeBytes(Section.getSegmentName(), 16); if (is64Bit()) { write64(VMAddr); // address write64(SectionSize); // size } else { write32(VMAddr); // address write32(SectionSize); // size } write32(FileOffset); assert(isPowerOf2_32(Section.getAlignment()) && "Invalid alignment!"); write32(Log2_32(Section.getAlignment())); write32(NumRelocations ? RelocationsStart : 0); write32(NumRelocations); write32(Flags); write32(IndirectSymBase.lookup(&Sec)); // reserved1 write32(Section.getStubSize()); // reserved2 if (is64Bit()) write32(0); // reserved3 assert(getStream().tell() - Start == (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section))); }
// Each LOH is composed by, in this order (each field is encoded using ULEB128): // - Its kind. // - Its number of arguments (let say N). // - Its arg1. // - ... // - Its argN. // <arg1> to <argN> are absolute addresses in the object file, i.e., // relative addresses from the beginning of the object file. void MCLOHDirective::Emit_impl(raw_ostream &OutStream, const MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { const MCAssembler &Asm = Layout.getAssembler(); encodeULEB128(Kind, OutStream); encodeULEB128(Args.size(), OutStream); for (LOHArgs::const_iterator It = Args.begin(), EndIt = Args.end(); It != EndIt; ++It) encodeULEB128(ObjWriter.getSymbolAddress(&Asm.getSymbolData(**It), Layout), OutStream); }
static uint64_t getSymbolValue(const MCSymbolData &Data, const MCAsmLayout &Layout) { if (Data.isCommon() && Data.isExternal()) return Data.getCommonSize(); uint64_t Res; if (!Layout.getSymbolOffset(&Data, Res)) return 0; return Res; }
// Simple getSymbolOffset helper for the non-varibale case. static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S, bool ReportError, uint64_t &Val) { if (!S.getFragment()) { if (ReportError) report_fatal_error("unable to evaluate offset to undefined symbol '" + S.getName() + "'"); return false; } Val = Layout.getFragmentOffset(S.getFragment()) + S.getOffset(); return true; }
void X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() && "Should only be called with a 32-bit TLVP relocation!"); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned IsPCRel = 0; // Get the symbol data. const MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol()); unsigned Index = SD_A->getIndex(); // We're only going to have a second symbol in pic mode and it'll be a // subtraction from the picbase. For 32-bit pic the addend is the difference // between the picbase and the next address. For 32-bit static the addend is // zero. if (Target.getSymB()) { // If this is a subtraction then we're pcrel. uint32_t FixupAddress = Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); const MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); IsPCRel = 1; FixedValue = (FixupAddress - Writer->getSymbolAddress(SD_B, Layout) + Target.getConstant()); FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = Value; MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (1 << 27) | // r_extern (MachO::GENERIC_RELOC_TLV << 28)); // r_type Writer->addRelocation(Fragment->getParent(), MRE); }
void SVMMemoryLayout::AllocateSections(MCAssembler &Asm, const MCAsmLayout &Layout) { memset(spsMemSize, 0, sizeof spsMemSize); memset(spsDiskSize, 0, sizeof spsDiskSize); bssAlign = 1; // Leave one free block at the beginning of DEBUG, for a special message. spsMemSize[SPS_DEBUG] = SVMTargetMachine::getBlockSize(); spsDiskSize[SPS_DEBUG] = spsMemSize[SPS_DEBUG]; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData *SD = &*it; SVMProgramSection sps = getSectionKind(SD); switch (sps) { case SPS_BSS: // Also track BSS segment alignment, then fall through... bssAlign = std::max(bssAlign, SD->getAlignment()); case SPS_RO: case SPS_RW_Z: case SPS_RW_PLAIN: case SPS_DEBUG: case SPS_META: spsMemSize[sps] = RoundUpToAlignment(spsMemSize[sps], SD->getAlignment()); spsDiskSize[sps] = RoundUpToAlignment(spsDiskSize[sps], SD->getAlignment()); SectionOffsetMap[SD] = spsDiskSize[sps]; spsMemSize[sps] += getSectionMemSize(SD, Layout); spsDiskSize[sps] += Layout.getSectionAddressSize(SD); break; default: break; } } unsigned memUsed = getSectionMemAddress(SPS_END) - SVMTargetMachine::getRAMBase(); unsigned memMax = SVMTargetMachine::getRAMSize(); if (memUsed > memMax) report_fatal_error("Application is too large to fit in RAM! Need " + Twine(memUsed) + " bytes, which exceeds the maximum of " + Twine(memMax)); }
void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol); const MCSymbolELF *Base = cast_or_null<MCSymbolELF>(Layout.getBaseSymbol(Symbol)); // This has to be in sync with when computeSymbolTable uses SHN_ABS or // SHN_COMMON. bool IsReserved = !Base || Symbol.isCommon(); // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = Symbol.getBinding(); uint8_t Type = Symbol.getType(); if (Base) { Type = mergeTypeForSet(Type, Base->getType()); } uint8_t Info = (Binding << 4) | Type; // Other and Visibility share the same byte with Visibility using the lower // 2 bits uint8_t Visibility = Symbol.getVisibility(); uint8_t Other = Symbol.getOther() | Visibility; uint64_t Value = SymbolValue(*MSD.Symbol, Layout); uint64_t Size = 0; const MCExpr *ESize = MSD.Symbol->getSize(); if (!ESize && Base) ESize = Base->getSize(); if (ESize) { int64_t Res; if (!ESize->evaluateKnownAbsolute(Res, Layout)) report_fatal_error("Size expression must be absolute."); Size = Res; } // Write out the symbol table entry Writer.writeSymbol(StringIndex, Info, Value, Size, Other, MSD.SectionIndex, IsReserved); }
static bool getSymbolOffsetImpl(const MCAsmLayout &Layout, const MCSymbolData *SD, bool ReportError, uint64_t &Val) { const MCSymbol &S = SD->getSymbol(); if (!S.isVariable()) return getLabelOffset(Layout, *SD, ReportError, Val); // If SD is a variable, evaluate it. MCValue Target; if (!S.getVariableValue()->EvaluateAsValue(Target, &Layout, nullptr)) report_fatal_error("unable to evaluate offset for variable '" + S.getName() + "'"); uint64_t Offset = Target.getConstant(); const MCAssembler &Asm = Layout.getAssembler(); const MCSymbolRefExpr *A = Target.getSymA(); if (A) { uint64_t ValA; if (!getLabelOffset(Layout, Asm.getSymbolData(A->getSymbol()), ReportError, ValA)) return false; Offset += ValA; } const MCSymbolRefExpr *B = Target.getSymB(); if (B) { uint64_t ValB; if (!getLabelOffset(Layout, Asm.getSymbolData(B->getSymbol()), ReportError, ValB)) return false; Offset -= ValB; } Val = Offset; return true; }
void SVMMemoryLayout::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { SVM::Fixups kind = (SVM::Fixups) Fixup.getKind(); switch (kind) { case SVM::fixup_fnstack: { /* * Function stack adjustment annotation. The adjustment amount is * stored in the first argument of a binary op. * (See SVMMCCodeEmitter::EncodeInstruction) * * We store this offset for later, in our FNStackMap, indexed * by the address of the FNStack pseudo-op itself. */ FNStackMap[std::make_pair(Fragment->getParent(), Layout.getFragmentOffset(Fragment))] = (int)Target.getConstant(); break; } default: { /* * All other fixups are applied later, in ApplyLateFixups(). * This is necessary because other fixup types can depend on * the FNStack values collected above. */ SVMLateFixup LF((MCFragment *) Fragment, Fixup, Target); LateFixupList.push_back(LF); // This gets OR'ed with the fixup later. Zero it. FixedValue = 0; break; } } }
void X86MachObjectWriter::RecordX86_64Relocation( MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); uint32_t FixupAddress = Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); int64_t Value = 0; unsigned Index = 0; unsigned IsExtern = 0; unsigned Type = 0; const MCSymbol *RelSymbol = nullptr; Value = Target.getConstant(); if (IsPCRel) { // Compensate for the relocation offset, Darwin x86_64 relocations only have // the addend and appear to have attempted to define it to be the actual // expression addend without the PCrel bias. However, instructions with data // following the relocation are not accommodated for (see comment below // regarding SIGNED{1,2,4}), so it isn't exactly that either. Value += 1LL << Log2Size; } if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. Type = MachO::X86_64_RELOC_UNSIGNED; // FIXME: I believe this is broken, I don't think the linker can understand // it. I think it would require a local relocation, but I'm not sure if that // would work either. The official way to get an absolute PCrel relocation // is to use an absolute symbol (which we don't support yet). if (IsPCRel) { IsExtern = 1; Type = MachO::X86_64_RELOC_BRANCH; } } else if (Target.getSymB()) { // A - B + constant const MCSymbol *A = &Target.getSymA()->getSymbol(); if (A->isTemporary()) A = &Writer->findAliasedSymbol(*A); const MCSymbolData &A_SD = Asm.getSymbolData(*A); const MCSymbol *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); if (B->isTemporary()) B = &Writer->findAliasedSymbol(*B); const MCSymbolData &B_SD = Asm.getSymbolData(*B); const MCSymbol *B_Base = Asm.getAtom(&B_SD); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported relocation of modified symbol", false); // We don't support PCrel relocations of differences. Darwin 'as' doesn't // implement most of these correctly. if (IsPCRel) report_fatal_error("unsupported pc-relative relocation of difference", false); // The support for the situation where one or both of the symbols would // require a local relocation is handled just like if the symbols were // external. This is certainly used in the case of debug sections where the // section has only temporary symbols and thus the symbols don't have base // symbols. This is encoded using the section ordinal and non-extern // relocation entries. // Darwin 'as' doesn't emit correct relocations for this (it ends up with a // single SIGNED relocation); reject it for now. Except the case where both // symbols don't have a base, equal but both NULL. if (A_Base == B_Base && A_Base) report_fatal_error("unsupported relocation with identical base", false); // A subtraction expression where either symbol is undefined is a // non-relocatable expression. if (A->isUndefined() || B->isUndefined()) { StringRef Name = A->isUndefined() ? A->getName() : B->getName(); Asm.getContext().FatalError(Fixup.getLoc(), "unsupported relocation with subtraction expression, symbol '" + Name + "' can not be undefined in a subtraction expression"); } Value += Writer->getSymbolAddress(&A_SD, Layout) - (!A_Base ? 0 : Writer->getSymbolAddress(&A_Base->getData(), Layout)); Value -= Writer->getSymbolAddress(&B_SD, Layout) - (!B_Base ? 0 : Writer->getSymbolAddress(&B_Base->getData(), Layout)); if (!A_Base) Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; Type = MachO::X86_64_RELOC_UNSIGNED; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, Fragment->getParent(), MRE); if (B_Base) RelSymbol = B_Base; else Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; Type = MachO::X86_64_RELOC_SUBTRACTOR; } else { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); if (Symbol->isTemporary() && Value) { const MCSection &Sec = Symbol->getSection(); if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) Asm.addLocalUsedInReloc(*Symbol); } const MCSymbolData &SD = Asm.getSymbolData(*Symbol); RelSymbol = Asm.getAtom(&SD); // Relocations inside debug sections always use local relocations when // possible. This seems to be done because the debugger doesn't fully // understand x86_64 relocation entries, and expects to find values that // have already been fixed up. if (Symbol->isInSection()) { const MCSectionMachO &Section = static_cast<const MCSectionMachO&>( Fragment->getParent()->getSection()); if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) RelSymbol = nullptr; } // x86_64 almost always uses external relocations, except when there is no // symbol to use as a base address (a local symbol with no preceding // non-local symbol). if (RelSymbol) { // Add the local offset, if needed. if (&RelSymbol->getData() != &SD) Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(&RelSymbol->getData()); } else if (Symbol->isInSection() && !Symbol->isVariable()) { // The index is the section ordinal (1-based). Index = SD.getFragment()->getParent()->getOrdinal() + 1; Value += Writer->getSymbolAddress(&SD, Layout); if (IsPCRel) Value -= FixupAddress + (1 << Log2Size); } else if (Symbol->isVariable()) { const MCExpr *Value = Symbol->getVariableValue(); int64_t Res; bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, Writer->getSectionAddressMap()); if (isAbs) { FixedValue = Res; return; } else { report_fatal_error("unsupported relocation of variable '" + Symbol->getName() + "'", false); } } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'", false); } MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); if (IsPCRel) { if (IsRIPRel) { if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { // x86_64 distinguishes movq foo@GOTPCREL so that the linker can // rewrite the movq to an leaq at link time if the symbol ends up in // the same linkage unit. if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) Type = MachO::X86_64_RELOC_GOT_LOAD; else Type = MachO::X86_64_RELOC_GOT; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { Type = MachO::X86_64_RELOC_TLV; } else if (Modifier != MCSymbolRefExpr::VK_None) { report_fatal_error("unsupported symbol modifier in relocation", false); } else { Type = MachO::X86_64_RELOC_SIGNED; // The Darwin x86_64 relocation format has a problem where it cannot // encode an address (L<foo> + <constant>) which is outside the atom // containing L<foo>. Generally, this shouldn't occur but it does // happen when we have a RIPrel instruction with data following the // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel // adjustment Darwin x86_64 uses, the offset is still negative and the // linker has no way to recognize this. // // To work around this, Darwin uses several special relocation types // to indicate the offsets. However, the specification or // implementation of these seems to also be incomplete; they should // adjust the addend as well based on the actual encoded instruction // (the additional bias), but instead appear to just look at the final // offset. switch (-(Target.getConstant() + (1LL << Log2Size))) { case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break; case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break; case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break; } } } else { if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in branch " "relocation", false); Type = MachO::X86_64_RELOC_BRANCH; } } else { if (Modifier == MCSymbolRefExpr::VK_GOT) { Type = MachO::X86_64_RELOC_GOT; } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which // case all we do is set the PCrel bit in the relocation entry; this is // used with exception handling, for example. The source is required to // include any necessary offset directly. Type = MachO::X86_64_RELOC_GOT; IsPCRel = 1; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { report_fatal_error("TLVP symbol modifier should have been rip-rel", false); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation", false); else { Type = MachO::X86_64_RELOC_UNSIGNED; unsigned Kind = Fixup.getKind(); if (Kind == X86::reloc_signed_4byte) report_fatal_error("32-bit absolute addressing is not supported in " "64-bit mode", false); } } } // x86_64 always writes custom values into the fixups. FixedValue = Value; // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (IsExtern << 27) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // If this is a 32-bit TLVP reloc it's handled a bit differently. if (Target.getSymA() && Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { RecordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } // If this is a difference or a defined symbol plus an offset, then we need a // scattered relocation entry. Differences always require scattered // relocations. if (Target.getSymB()) { RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, Log2Size, FixedValue); return; } // Get the symbol data, if any. const MCSymbolData *SD = nullptr; if (Target.getSymA()) SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); // If this is an internal relocation with an offset, it also needs a scattered // relocation entry. uint32_t Offset = Target.getConstant(); if (IsPCRel) Offset += 1 << Log2Size; // Try to record the scattered relocation if needed. Fall back to non // scattered if necessary (see comments in RecordScatteredRelocation() // for details). if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD) && RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, Log2Size, FixedValue)) return; // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned Index = 0; unsigned Type = 0; const MCSymbol *RelSymbol = nullptr; if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. // // FIXME: Currently, these are never generated (see code below). I cannot // find a case where they are actually emitted. Type = MachO::GENERIC_RELOC_VANILLA; } else { // Resolve constant variables. if (SD->getSymbol().isVariable()) { int64_t Res; if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } } // Check whether we need an external or internal relocation. if (Writer->doesSymbolRequireExternRelocation(SD)) { RelSymbol = &SD->getSymbol(); // For external relocations, make sure to offset the fixup value to // compensate for the addend of the symbol address, if it was // undefined. This occurs with weak definitions, for example. if (!SD->getSymbol().isUndefined()) FixedValue -= Layout.getSymbolOffset(SD); } else { // The index is the section ordinal (1-based). const MCSectionData &SymSD = Asm.getSectionData( SD->getSymbol().getSection()); Index = SymSD.getOrdinal() + 1; FixedValue += Writer->getSectionAddress(&SymSD); } if (IsPCRel) FixedValue -= Writer->getSectionAddress(Fragment->getParent()); Type = MachO::GENERIC_RELOC_VANILLA; } // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
bool X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, unsigned Log2Size, uint64_t &FixedValue) { uint64_t OriginalFixedValue = FixedValue; uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Type = MachO::GENERIC_RELOC_VANILLA; // See <reloc.h>. const MCSymbol *A = &Target.getSymA()->getSymbol(); const MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression", false); uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) report_fatal_error("symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression", false); // Select the appropriate difference relocation type. // // Note that there is no longer any semantic difference between these two // relocation types from the linkers point of view, this is done solely for // pedantic compatibility with 'as'. Type = A_SD->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; Value2 = Writer->getSymbolAddress(B_SD, Layout); FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); } // Relocations are written out in reverse order, so the PAIR comes first. if (Type == MachO::GENERIC_RELOC_SECTDIFF || Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) { // If the offset is too large to fit in a scattered relocation, // we're hosed. It's an unfortunate limitation of the MachO format. if (FixupOffset > 0xffffff) { char Buffer[32]; format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); Asm.getContext().FatalError(Fixup.getLoc(), Twine("Section too large, can't encode " "r_address (") + Buffer + ") into 24 bits of scattered " "relocation entry."); llvm_unreachable("fatal error returned?!"); } MachO::any_relocation_info MRE; MRE.r_word0 = ((0 << 0) | // r_address (MachO::GENERIC_RELOC_PAIR << 24) | // r_type (Log2Size << 28) | (IsPCRel << 30) | MachO::R_SCATTERED); MRE.r_word1 = Value2; Writer->addRelocation(nullptr, Fragment->getParent(), MRE); } else { // If the offset is more than 24-bits, it won't fit in a scattered // relocation offset field, so we fall back to using a non-scattered // relocation. This is a bit risky, as if the offset reaches out of // the block and the linker is doing scattered loading on this // symbol, things can go badly. // // Required for 'as' compatibility. if (FixupOffset > 0xffffff) { FixedValue = OriginalFixedValue; return false; } } MachO::any_relocation_info MRE; MRE.r_word0 = ((FixupOffset << 0) | (Type << 24) | (Log2Size << 28) | (IsPCRel << 30) | MachO::R_SCATTERED); MRE.r_word1 = Value; Writer->addRelocation(nullptr, Fragment->getParent(), MRE); return true; }
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 = alignTo(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); MachO::LoadCommandType LCType; switch (VersionInfo.Kind) { case MCVM_OSXVersionMin: LCType = MachO::LC_VERSION_MIN_MACOSX; break; case MCVM_IOSVersionMin: LCType = MachO::LC_VERSION_MIN_IPHONEOS; break; case MCVM_TvOSVersionMin: LCType = MachO::LC_VERSION_MIN_TVOS; break; case MCVM_WatchOSVersionMin: LCType = MachO::LC_VERSION_MIN_WATCHOS; break; } write32(LCType); 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(); } }