#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/MCSymbolMachO.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
// References to weak definitions require external relocation entries; the
// definition may not always be the one in the same object file.
- if (S.getFlags() & SF_WeakDefinition)
+ if (cast<MCSymbolMachO>(S).isWeakDefinition())
return true;
// Otherwise, we can use an internal relocation.
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 '" +
return OffsetToAlignment(EndAddr, NextSec.getAlignment());
}
-void MachObjectWriter::WriteHeader(unsigned NumLoadCommands,
+void MachObjectWriter::writeHeader(MachO::HeaderFileType Type,
+ unsigned NumLoadCommands,
unsigned LoadCommandsSize,
bool SubsectionsViaSymbols) {
uint32_t Flags = 0;
// struct mach_header (28 bytes) or
// struct mach_header_64 (32 bytes)
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
write32(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC);
write32(TargetObjectWriter->getCPUType());
write32(TargetObjectWriter->getCPUSubtype());
- write32(MachO::MH_OBJECT);
+ write32(Type);
write32(NumLoadCommands);
write32(LoadCommandsSize);
write32(Flags);
if (is64Bit())
write32(0); // reserved
- assert(OS.tell() - Start ==
- (is64Bit()?sizeof(MachO::mach_header_64): sizeof(MachO::mach_header)));
+ assert(
+ getStream().tell() - Start ==
+ (is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header)));
}
-/// WriteSegmentLoadCommand - Write a segment load command.
+/// writeSegmentLoadCommand - Write a segment load command.
///
/// \param NumSections The number of sections in this segment.
/// \param SectionDataSize The total size of the sections.
-void MachObjectWriter::WriteSegmentLoadCommand(unsigned NumSections,
- uint64_t VMSize,
- uint64_t SectionDataStartOffset,
- uint64_t SectionDataSize) {
+void MachObjectWriter::writeSegmentLoadCommand(
+ StringRef Name, unsigned NumSections, uint64_t VMAddr, uint64_t VMSize,
+ uint64_t SectionDataStartOffset, uint64_t SectionDataSize, uint32_t MaxProt,
+ uint32_t InitProt) {
// struct segment_command (56 bytes) or
// struct segment_command_64 (72 bytes)
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
unsigned SegmentLoadCommandSize =
NumSections * (is64Bit() ? sizeof(MachO::section_64) :
sizeof(MachO::section)));
- writeBytes("", 16);
+ assert(Name.size() <= 16);
+ writeBytes(Name, 16);
if (is64Bit()) {
- write64(0); // vmaddr
+ write64(VMAddr); // vmaddr
write64(VMSize); // vmsize
write64(SectionDataStartOffset); // file offset
write64(SectionDataSize); // file size
} else {
- write32(0); // vmaddr
+ write32(VMAddr); // vmaddr
write32(VMSize); // vmsize
write32(SectionDataStartOffset); // file offset
write32(SectionDataSize); // file size
}
// maxprot
- write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
+ write32(MaxProt);
// initprot
- write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
+ write32(InitProt);
write32(NumSections);
write32(0); // flags
- assert(OS.tell() - Start == SegmentLoadCommandSize);
+ assert(getStream().tell() - Start == SegmentLoadCommandSize);
}
-void MachObjectWriter::WriteSection(const MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCSection &Sec, uint64_t FileOffset,
+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);
// struct section (68 bytes) or
// struct section_64 (80 bytes)
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
writeBytes(Section.getSectionName(), 16);
writeBytes(Section.getSegmentName(), 16);
if (is64Bit()) {
- write64(getSectionAddress(&Sec)); // address
+ write64(VMAddr); // address
write64(SectionSize); // size
} else {
- write32(getSectionAddress(&Sec)); // address
+ write32(VMAddr); // address
write32(SectionSize); // size
}
write32(FileOffset);
- unsigned Flags = Section.getTypeAndAttributes();
- if (Section.hasInstructions())
- Flags |= MachO::S_ATTR_SOME_INSTRUCTIONS;
-
assert(isPowerOf2_32(Section.getAlignment()) && "Invalid alignment!");
write32(Log2_32(Section.getAlignment()));
write32(NumRelocations ? RelocationsStart : 0);
if (is64Bit())
write32(0); // reserved3
- assert(OS.tell() - Start == (is64Bit() ? sizeof(MachO::section_64) :
- sizeof(MachO::section)));
+ assert(getStream().tell() - Start ==
+ (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section)));
}
-void MachObjectWriter::WriteSymtabLoadCommand(uint32_t SymbolOffset,
+void MachObjectWriter::writeSymtabLoadCommand(uint32_t SymbolOffset,
uint32_t NumSymbols,
uint32_t StringTableOffset,
uint32_t StringTableSize) {
// struct symtab_command (24 bytes)
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
write32(MachO::LC_SYMTAB);
write32(StringTableOffset);
write32(StringTableSize);
- assert(OS.tell() - Start == sizeof(MachO::symtab_command));
+ assert(getStream().tell() - Start == sizeof(MachO::symtab_command));
}
-void MachObjectWriter::WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
+void MachObjectWriter::writeDysymtabLoadCommand(uint32_t FirstLocalSymbol,
uint32_t NumLocalSymbols,
uint32_t FirstExternalSymbol,
uint32_t NumExternalSymbols,
uint32_t NumIndirectSymbols) {
// struct dysymtab_command (80 bytes)
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
write32(MachO::LC_DYSYMTAB);
write32(0); // locreloff
write32(0); // nlocrel
- assert(OS.tell() - Start == sizeof(MachO::dysymtab_command));
+ assert(getStream().tell() - Start == sizeof(MachO::dysymtab_command));
}
MachObjectWriter::MachSymbolData *
return *S;
}
-void MachObjectWriter::WriteNlist(MachSymbolData &MSD,
+void MachObjectWriter::writeNlist(MachSymbolData &MSD,
const MCAsmLayout &Layout) {
const MCSymbol *Symbol = MSD.Symbol;
const MCSymbol &Data = *Symbol;
const MCSymbol *AliasedSymbol = &findAliasedSymbol(*Symbol);
uint8_t SectionIndex = MSD.SectionIndex;
uint8_t Type = 0;
- uint16_t Flags = Symbol->getFlags();
uint64_t Address = 0;
bool IsAlias = Symbol != AliasedSymbol;
// Common symbols are encoded with the size in the address
// field, and their alignment in the flags.
Address = Symbol->getCommonSize();
-
- // Common alignment is packed into the 'desc' bits.
- if (unsigned Align = Symbol->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);
- // FIXME: Keep this mask with the SymbolFlags enumeration.
- Flags = (Flags & 0xF0FF) | (Log2Size << 8);
- }
}
- if (Layout.getAssembler().isThumbFunc(Symbol))
- Flags |= SF_ThumbFunc;
-
// struct nlist (12 bytes)
write32(MSD.StringIndex);
// The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
// value.
- write16(Flags);
+ write16(cast<MCSymbolMachO>(Symbol)->getEncodedFlags());
if (is64Bit())
write64(Address);
else
write32(Address);
}
-void MachObjectWriter::WriteLinkeditLoadCommand(uint32_t Type,
+void MachObjectWriter::writeLinkeditLoadCommand(uint32_t Type,
uint32_t DataOffset,
uint32_t DataSize) {
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
write32(Type);
write32(DataOffset);
write32(DataSize);
- assert(OS.tell() - Start == sizeof(MachO::linkedit_data_command));
+ assert(getStream().tell() - Start == sizeof(MachO::linkedit_data_command));
}
static unsigned ComputeLinkerOptionsLoadCommandSize(
return RoundUpToAlignment(Size, is64Bit ? 8 : 4);
}
-void MachObjectWriter::WriteLinkerOptionsLoadCommand(
+void MachObjectWriter::writeLinkerOptionsLoadCommand(
const std::vector<std::string> &Options)
{
unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit());
- uint64_t Start = OS.tell();
+ uint64_t Start = getStream().tell();
(void) Start;
write32(MachO::LC_LINKER_OPTION);
// Pad to a multiple of the pointer size.
writeBytes("", OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4));
- assert(OS.tell() - Start == Size);
+ assert(getStream().tell() - Start == Size);
}
void MachObjectWriter::recordRelocation(MCAssembler &Asm,
Target, FixedValue);
}
-void MachObjectWriter::BindIndirectSymbols(MCAssembler &Asm) {
+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
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");
+ MCSymbol &Symbol = *it->Symbol;
+ report_fatal_error("indirect symbol '" + Symbol.getName() +
+ "' not in a symbol pointer or stub section");
}
}
bool Created;
Asm.registerSymbol(*it->Symbol, &Created);
if (Created)
- it->Symbol->setFlags(it->Symbol->getFlags() | 0x0001);
+ cast<MCSymbolMachO>(it->Symbol)->setReferenceTypeUndefinedLazy(true);
}
}
-/// ComputeSymbolTable - Compute the symbol table data
-void MachObjectWriter::ComputeSymbolTable(
+/// computeSymbolTable - Compute the symbol table data
+void MachObjectWriter::computeSymbolTable(
MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData,
std::vector<MachSymbolData> &ExternalSymbolData,
std::vector<MachSymbolData> &UndefinedSymbolData) {
}
}
-void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm,
+void MachObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
computeSectionAddresses(Asm, Layout);
// Create symbol data for any indirect symbols.
- BindIndirectSymbols(Asm);
+ bindIndirectSymbols(Asm);
+}
+
+bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &A, const MCSymbol &B,
+ bool InSet) const {
+ // FIXME: We don't handle things like
+ // foo = .
+ // creating atoms.
+ if (A.isVariable() || B.isVariable())
+ return false;
+ return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, A, B,
+ InSet);
}
bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
void MachObjectWriter::writeObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// Compute symbol table information and bind symbol indices.
- ComputeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
+ computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
UndefinedSymbolData);
unsigned NumSections = Asm.size();
++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) :
SectionDataFileSize += SectionDataPadding;
// Write the prolog, starting with the header and load command...
- WriteHeader(NumLoadCommands, LoadCommandsSize,
+ writeHeader(MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize,
Asm.getSubsectionsViaSymbols());
- WriteSegmentLoadCommand(NumSections, VMSize,
- SectionDataStart, SectionDataSize);
+ 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 &Sec : Asm) {
+ 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);
- WriteSection(Asm, Layout, Sec, SectionStart, RelocTableEnd, NumRelocs);
+ 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);
}
if (NumDataRegions) {
uint64_t DataRegionsOffset = RelocTableEnd;
uint64_t DataRegionsSize = NumDataRegions * 8;
- WriteLinkeditLoadCommand(MachO::LC_DATA_IN_CODE, DataRegionsOffset,
+ 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,
+ writeLinkeditLoadCommand(MachO::LC_LINKER_OPTIMIZATION_HINT,
DataInCodeTableEnd, LOHSize);
// Write the symbol table load command, if used.
SymbolTableOffset + NumSymTabSymbols * (is64Bit() ?
sizeof(MachO::nlist_64) :
sizeof(MachO::nlist));
- WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
+ writeSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
StringTableOffset, StringTable.data().size());
- WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
+ writeDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
FirstExternalSymbol, NumExternalSymbols,
FirstUndefinedSymbol, NumUndefinedSymbols,
IndirectSymbolOffset, NumIndirectSymbols);
// Write the linker options load commands.
for (const auto &Option : Asm.getLinkerOptions())
- WriteLinkerOptionsLoadCommand(Option);
+ writeLinkerOptionsLoadCommand(Option);
// Write the actual section data.
for (const MCSection &Sec : Asm) {
// Write out the loh commands, if there is one.
if (LOHSize) {
#ifndef NDEBUG
- unsigned Start = OS.tell();
+ 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(OS.tell() - Start == LOHSize);
+ assert(getStream().tell() - Start == LOHSize);
}
// Write the symbol table data, if used.
for (auto *SymbolData :
{&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
for (MachSymbolData &Entry : *SymbolData)
- WriteNlist(Entry, Layout);
+ writeNlist(Entry, Layout);
// Write the string table.
- OS << StringTable.data();
+ getStream() << StringTable.data();
}
}