MachObjectWriter.cpp [plain text]
#include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCMachOSymbolFlags.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "mc"
void MachObjectWriter::reset() {
Relocations.clear();
IndirectSymBase.clear();
StringTable.clear();
LocalSymbolData.clear();
ExternalSymbolData.clear();
UndefinedSymbolData.clear();
MCObjectWriter::reset();
}
bool MachObjectWriter::
doesSymbolRequireExternRelocation(const MCSymbolData *SD) {
if (SD->getSymbol().isUndefined())
return true;
if (SD->getFlags() & SF_WeakDefinition)
return true;
return false;
}
bool MachObjectWriter::
MachSymbolData::operator<(const MachSymbolData &RHS) const {
return SymbolData->getSymbol().getName() <
RHS.SymbolData->getSymbol().getName();
}
bool MachObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) {
const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo(
(MCFixupKind) Kind);
return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel;
}
uint64_t MachObjectWriter::getFragmentAddress(const MCFragment *Fragment,
const MCAsmLayout &Layout) const {
return getSectionAddress(Fragment->getParent()) +
Layout.getFragmentOffset(Fragment);
}
uint64_t MachObjectWriter::getSymbolAddress(const MCSymbolData* SD,
const MCAsmLayout &Layout) const {
const MCSymbol &S = SD->getSymbol();
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() + "'");
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);
}
uint64_t MachObjectWriter::getPaddingSize(const MCSectionData *SD,
const MCAsmLayout &Layout) const {
uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD);
unsigned Next = SD->getLayoutOrder() + 1;
if (Next >= Layout.getSectionOrder().size())
return 0;
const MCSectionData &NextSD = *Layout.getSectionOrder()[Next];
if (NextSD.getSection().isVirtualSection())
return 0;
return OffsetToAlignment(EndAddr, NextSD.getAlignment());
}
void MachObjectWriter::WriteHeader(MachO::HeaderFileType Type,
unsigned NumLoadCommands,
unsigned LoadCommandsSize,
bool SubsectionsViaSymbols) {
uint32_t Flags = 0;
if (SubsectionsViaSymbols)
Flags |= MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
uint64_t Start = OS.tell();
(void) Start;
Write32(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC);
Write32(TargetObjectWriter->getCPUType());
Write32(TargetObjectWriter->getCPUSubtype());
Write32(Type);
Write32(NumLoadCommands);
Write32(LoadCommandsSize);
Write32(Flags);
if (is64Bit())
Write32(0);
assert(OS.tell() - Start ==
(is64Bit()?sizeof(MachO::mach_header_64): sizeof(MachO::mach_header)));
}
void MachObjectWriter::WriteSegmentLoadCommand(StringRef Name,
unsigned NumSections,
uint64_t VMSize,
uint64_t SectionDataStartOffset,
uint64_t SectionDataSize) {
uint64_t Start = OS.tell();
(void) Start;
unsigned SegmentLoadCommandSize =
is64Bit() ? sizeof(MachO::segment_command_64):
sizeof(MachO::segment_command);
Write32(is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT);
Write32(SegmentLoadCommandSize +
NumSections * (is64Bit() ? sizeof(MachO::section_64) :
sizeof(MachO::section)));
assert(Name.size() <= 16);
WriteBytes(Name, 16);
if (is64Bit()) {
Write64(0); Write64(VMSize); Write64(SectionDataStartOffset); Write64(SectionDataSize); } else {
Write32(0); Write32(VMSize); Write32(SectionDataStartOffset); Write32(SectionDataSize); }
Write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
Write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
Write32(NumSections);
Write32(0);
assert(OS.tell() - Start == SegmentLoadCommandSize);
}
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);
if (SD.getSection().isVirtualSection()) {
assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!");
FileOffset = 0;
}
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)); Write64(SectionSize); } else {
Write32(getSectionAddress(&SD)); Write32(SectionSize); }
Write32(FileOffset);
unsigned Flags = Section.getTypeAndAttributes();
if (SD.hasInstructions())
Flags |= MachO::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)); Write32(Section.getStubSize()); if (is64Bit())
Write32(0);
assert(OS.tell() - Start == (is64Bit() ? sizeof(MachO::section_64) :
sizeof(MachO::section)));
}
void MachObjectWriter::WriteSymtabLoadCommand(uint32_t SymbolOffset,
uint32_t NumSymbols,
uint32_t StringTableOffset,
uint32_t StringTableSize) {
uint64_t Start = OS.tell();
(void) Start;
Write32(MachO::LC_SYMTAB);
Write32(sizeof(MachO::symtab_command));
Write32(SymbolOffset);
Write32(NumSymbols);
Write32(StringTableOffset);
Write32(StringTableSize);
assert(OS.tell() - Start == sizeof(MachO::symtab_command));
}
void MachObjectWriter::WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
uint32_t NumLocalSymbols,
uint32_t FirstExternalSymbol,
uint32_t NumExternalSymbols,
uint32_t FirstUndefinedSymbol,
uint32_t NumUndefinedSymbols,
uint32_t IndirectSymbolOffset,
uint32_t NumIndirectSymbols) {
uint64_t Start = OS.tell();
(void) Start;
Write32(MachO::LC_DYSYMTAB);
Write32(sizeof(MachO::dysymtab_command));
Write32(FirstLocalSymbol);
Write32(NumLocalSymbols);
Write32(FirstExternalSymbol);
Write32(NumExternalSymbols);
Write32(FirstUndefinedSymbol);
Write32(NumUndefinedSymbols);
Write32(0); Write32(0); Write32(0); Write32(0); Write32(0); Write32(0); Write32(IndirectSymbolOffset);
Write32(NumIndirectSymbols);
Write32(0); Write32(0); Write32(0); Write32(0);
assert(OS.tell() - Start == sizeof(MachO::dysymtab_command));
}
MachObjectWriter::MachSymbolData *
MachObjectWriter::findSymbolData(const MCSymbol &Sym) {
for (auto &Entry : LocalSymbolData)
if (&Entry.SymbolData->getSymbol() == &Sym)
return &Entry;
for (auto &Entry : ExternalSymbolData)
if (&Entry.SymbolData->getSymbol() == &Sym)
return &Entry;
for (auto &Entry : UndefinedSymbolData)
if (&Entry.SymbolData->getSymbol() == &Sym)
return &Entry;
return nullptr;
}
void MachObjectWriter::WriteNlist(MachSymbolData &MSD,
const MCAsmLayout &Layout) {
MCSymbolData &Data = *MSD.SymbolData;
const MCSymbol *Symbol = &Data.getSymbol();
const MCSymbol *AliasedSymbol = &Symbol->AliasedSymbol();
uint8_t SectionIndex = MSD.SectionIndex;
uint8_t Type = 0;
uint16_t Flags = Data.getFlags();
uint64_t Address = 0;
bool IsAlias = Symbol != AliasedSymbol;
MachSymbolData *AliaseeInfo;
if (IsAlias) {
AliaseeInfo = findSymbolData(*AliasedSymbol);
if (AliaseeInfo)
SectionIndex = AliaseeInfo->SectionIndex;
Symbol = AliasedSymbol;
}
if (IsAlias && Symbol->isUndefined())
Type = MachO::N_INDR;
else if (Symbol->isUndefined())
Type = MachO::N_UNDF;
else if (Symbol->isAbsolute())
Type = MachO::N_ABS;
else
Type = MachO::N_SECT;
if (Data.isPrivateExtern())
Type |= MachO::N_PEXT;
if (Data.isExternal() || (!IsAlias && Symbol->isUndefined()))
Type |= MachO::N_EXT;
if (IsAlias && Symbol->isUndefined())
Address = AliaseeInfo->StringIndex;
else if (Symbol->isDefined())
Address = getSymbolAddress(&Data, Layout);
else if (Data.isCommon()) {
Address = Data.getCommonSize();
if (unsigned Align = Data.getCommonAlignment()) {
unsigned Log2Size = Log2_32(Align);
assert((1U << Log2Size) == Align && "Invalid 'common' alignment!");
if (Log2Size > 15)
report_fatal_error("invalid 'common' alignment '" +
Twine(Align) + "' for '" + Symbol->getName() + "'",
false);
Flags = (Flags & 0xF0FF) | (Log2Size << 8);
}
}
if (Layout.getAssembler().isThumbFunc(Symbol))
Flags |= SF_ThumbFunc;
Write32(MSD.StringIndex);
Write8(Type);
Write8(SectionIndex);
Write16(Flags);
if (is64Bit())
Write64(Address);
else
Write32(Address);
}
void MachObjectWriter::WriteLinkeditLoadCommand(uint32_t Type,
uint32_t DataOffset,
uint32_t DataSize) {
uint64_t Start = OS.tell();
(void) Start;
Write32(Type);
Write32(sizeof(MachO::linkedit_data_command));
Write32(DataOffset);
Write32(DataSize);
assert(OS.tell() - Start == sizeof(MachO::linkedit_data_command));
}
static unsigned ComputeLinkerOptionsLoadCommandSize(
const std::vector<std::string> &Options, bool is64Bit)
{
unsigned Size = sizeof(MachO::linker_option_command);
for (unsigned i = 0, e = Options.size(); i != e; ++i)
Size += Options[i].size() + 1;
return RoundUpToAlignment(Size, is64Bit ? 8 : 4);
}
void MachObjectWriter::WriteLinkerOptionsLoadCommand(
const std::vector<std::string> &Options)
{
unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit());
uint64_t Start = OS.tell();
(void) Start;
Write32(MachO::LC_LINKER_OPTION);
Write32(Size);
Write32(Options.size());
uint64_t BytesWritten = sizeof(MachO::linker_option_command);
for (unsigned i = 0, e = Options.size(); i != e; ++i) {
const std::string &Option = Options[i];
WriteBytes(Option.c_str(), Option.size() + 1);
BytesWritten += Option.size() + 1;
}
WriteBytes("", OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4));
assert(OS.tell() - Start == Size);
}
void MachObjectWriter::RecordRelocation(MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
bool &IsPCRel, uint64_t &FixedValue) {
TargetObjectWriter->RecordRelocation(this, Asm, Layout, Fragment, Fixup,
Target, FixedValue);
}
void MachObjectWriter::BindIndirectSymbols(MCAssembler &Asm) {
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() != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS &&
Section.getType() != MachO::S_SYMBOL_STUBS) {
MCSymbol &Symbol = *it->Symbol;
report_fatal_error("indirect symbol '" + Symbol.getName() +
"' not in a symbol pointer or stub section");
}
}
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() != MachO::S_NON_LAZY_SYMBOL_POINTERS)
continue;
IndirectSymBase.insert(std::make_pair(it->SectionData, IndirectIndex));
Asm.getOrCreateSymbolData(*it->Symbol);
}
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() != MachO::S_LAZY_SYMBOL_POINTERS &&
Section.getType() != MachO::S_SYMBOL_STUBS)
continue;
IndirectSymBase.insert(std::make_pair(it->SectionData, IndirectIndex));
bool Created;
MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created);
if (Created)
Entry.setFlags(Entry.getFlags() | 0x0001);
}
}
void MachObjectWriter::ComputeSymbolTable(
MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData,
std::vector<MachSymbolData> &ExternalSymbolData,
std::vector<MachSymbolData> &UndefinedSymbolData) {
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!");
for (MCSymbolData &SD : Asm.symbols()) {
const MCSymbol &Symbol = SD.getSymbol();
if (!Asm.isSymbolLinkerVisible(Symbol))
continue;
StringTable.add(Symbol.getName());
}
StringTable.finalize(StringTableBuilder::MachO);
for (MCSymbolData &SD : Asm.symbols()) {
const MCSymbol &Symbol = SD.getSymbol();
if (!Asm.isSymbolLinkerVisible(Symbol))
continue;
if (!SD.isExternal() && !Symbol.isUndefined())
continue;
MachSymbolData MSD;
MSD.SymbolData = &SD;
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);
}
}
for (MCSymbolData &SD : Asm.symbols()) {
const MCSymbol &Symbol = SD.getSymbol();
if (!Asm.isSymbolLinkerVisible(Symbol))
continue;
if (SD.isExternal() || Symbol.isUndefined())
continue;
MachSymbolData MSD;
MSD.SymbolData = &SD;
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);
}
}
std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end());
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++);
for (const MCSectionData &SD : Asm) {
std::vector<RelAndSymbol> &Relocs = Relocations[&SD];
for (RelAndSymbol &Rel : Relocs) {
if (!Rel.Sym)
continue;
unsigned Index = Rel.Sym->getIndex();
assert(isInt<24>(Index));
if (IsLittleEndian)
Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (-1 << 24)) | Index | (1 << 27);
else
Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4);
}
}
}
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);
StartAddress += getPaddingSize(SD, Layout);
}
}
void MachObjectWriter::markAbsoluteVariableSymbols(MCAssembler &Asm,
const MCAsmLayout &Layout) {
for (MCSymbolData &SD : Asm.symbols()) {
if (!SD.getSymbol().isVariable())
continue;
const MCExpr *Expr = SD.getSymbol().getVariableValue();
MCValue Value;
if (Expr->EvaluateAsRelocatable(Value, &Layout, nullptr)) {
if (Value.getSymA() && Value.getSymB())
const_cast<MCSymbol*>(&SD.getSymbol())->setAbsolute();
}
}
}
void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
computeSectionAddresses(Asm, Layout);
BindIndirectSymbols(Asm);
markAbsoluteVariableSymbols(Asm, Layout);
}
bool MachObjectWriter::
IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
const MCSymbolData &DataA,
const MCFragment &FB,
bool InSet,
bool IsPCRel) const {
if (InSet)
return true;
const MCSymbolData *A_Base = nullptr, *B_Base = nullptr;
const MCSymbol &SA = DataA.getSymbol().AliasedSymbol();
const MCSection &SecA = SA.getSection();
const MCSection &SecB = FB.getParent()->getSection();
if (IsPCRel) {
bool hasReliableSymbolDifference = isX86_64();
if (!hasReliableSymbolDifference) {
if (!SA.isInSection() || &SecA != &SecB ||
(!SA.isTemporary() &&
FB.getAtom() != Asm.getSymbolData(SA).getFragment()->getAtom() &&
Asm.getSubsectionsViaSymbols()))
return false;
return true;
}
else if(!FB.getAtom() &&
SA.isTemporary() && SA.isInSection() && &SecA == &SecB){
return true;
}
} else {
if (!TargetObjectWriter->useAggressiveSymbolFolding())
return false;
}
if (&SecA != &SecB)
return false;
const MCFragment *FA = Asm.getSymbolData(SA).getFragment();
if (!FA)
return false;
A_Base = FA->getAtom();
B_Base = FB.getAtom();
if (A_Base == B_Base)
return true;
return false;
}
void MachObjectWriter::WriteObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
ComputeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
UndefinedSymbolData);
unsigned NumSections = Asm.size();
const MCAssembler::VersionMinInfoType &VersionInfo =
Layout.getAssembler().getVersionMinInfo();
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);
if (VersionInfo.Major != 0) {
++NumLoadCommands;
LoadCommandsSize += sizeof(MachO::version_min_command);
}
unsigned NumDataRegions = Asm.getDataRegions().size();
if (NumDataRegions) {
++NumLoadCommands;
LoadCommandsSize += sizeof(MachO::linkedit_data_command);
}
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);
}
unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
UndefinedSymbolData.size();
if (NumSymbols) {
NumLoadCommands += 2;
LoadCommandsSize += (sizeof(MachO::symtab_command) +
sizeof(MachO::dysymtab_command));
}
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());
}
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);
}
unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4);
SectionDataFileSize += SectionDataPadding;
WriteHeader(MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize,
Asm.getSubsectionsViaSymbols());
WriteSegmentLoadCommand("", NumSections, VMSize,
SectionDataStart, SectionDataSize);
uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize;
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
std::vector<RelAndSymbol> &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);
}
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); }
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);
}
uint64_t LOHTableEnd = DataInCodeTableEnd + LOHSize;
if (LOHSize)
WriteLinkeditLoadCommand(MachO::LC_LINKER_OPTIMIZATION_HINT,
DataInCodeTableEnd, LOHSize);
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 (NumIndirectSymbols)
IndirectSymbolOffset = LOHTableEnd;
uint64_t SymbolTableOffset = LOHTableEnd + IndirectSymbolSize;
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);
}
for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) {
WriteLinkerOptionsLoadCommand(LinkerOptions[i]);
}
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);
}
WriteZeros(SectionDataPadding);
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
std::vector<RelAndSymbol> &Relocs = Relocations[it];
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
Write32(Relocs[e - i - 1].MRE.r_word0);
Write32(Relocs[e - i - 1].MRE.r_word1);
}
}
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);
}
if (LOHSize) {
#ifndef NDEBUG
unsigned Start = OS.tell();
#endif
Asm.getLOHContainer().Emit(*this, Layout);
WriteBytes("", OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4));
assert(OS.tell() - Start == LOHSize);
}
if (NumSymbols) {
for (MCAssembler::const_indirect_symbol_iterator
it = Asm.indirect_symbol_begin(),
ie = Asm.indirect_symbol_end(); it != ie; ++it) {
const MCSectionMachO &Section =
static_cast<const MCSectionMachO&>(it->SectionData->getSection());
if (Section.getType() == MachO::S_NON_LAZY_SYMBOL_POINTERS) {
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());
}
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);
OS << StringTable.data();
}
}
MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW,
raw_ostream &OS,
bool IsLittleEndian) {
return new MachObjectWriter(MOTW, OS, IsLittleEndian);
}