//===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachOWriterInfo.h" using namespace llvm; namespace { class MachObjectWriter { // See . enum { Header_Magic32 = 0xFEEDFACE, Header_Magic64 = 0xFEEDFACF }; static const unsigned Header32Size = 28; static const unsigned Header64Size = 32; static const unsigned SegmentLoadCommand32Size = 56; static const unsigned Section32Size = 68; enum HeaderFileType { HFT_Object = 0x1 }; enum LoadCommandType { LCT_Segment = 0x1 }; raw_ostream &OS; bool IsLSB; public: MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) : OS(_OS), IsLSB(_IsLSB) { } /// @name Helper Methods /// @{ void Write32(uint32_t Value) { if (IsLSB) { OS << char(Value >> 0); OS << char(Value >> 8); OS << char(Value >> 16); OS << char(Value >> 24); } else { OS << char(Value >> 24); OS << char(Value >> 16); OS << char(Value >> 8); OS << char(Value >> 0); } } void WriteZeros(unsigned N) { const char Zeros[16] = { 0 }; for (unsigned i = 0, e = N / 16; i != e; ++i) OS << StringRef(Zeros, 16); OS << StringRef(Zeros, N % 16); } void WriteString(const StringRef &Str, unsigned ZeroFillSize = 0) { OS << Str; if (ZeroFillSize) WriteZeros(ZeroFillSize - Str.size()); } /// @} static unsigned getPrologSize32(unsigned NumSections) { return Header32Size + SegmentLoadCommand32Size + NumSections * Section32Size; } void WriteHeader32(unsigned NumSections) { // struct mach_header (28 bytes) uint64_t Start = OS.tell(); (void) Start; Write32(Header_Magic32); // FIXME: Support cputype. Write32(TargetMachOWriterInfo::HDR_CPU_TYPE_I386); // FIXME: Support cpusubtype. Write32(TargetMachOWriterInfo::HDR_CPU_SUBTYPE_I386_ALL); Write32(HFT_Object); // Object files have a single load command, the segment. Write32(1); Write32(SegmentLoadCommand32Size + NumSections * Section32Size); Write32(0); // Flags assert(OS.tell() - Start == Header32Size); } void WriteLoadCommandHeader(uint32_t Cmd, uint32_t CmdSize) { assert((CmdSize & 0x3) == 0 && "Invalid size!"); Write32(Cmd); Write32(CmdSize); } void WriteSegmentLoadCommand32(unsigned NumSections) { // struct segment_command (56 bytes) uint64_t Start = OS.tell(); (void) Start; Write32(LCT_Segment); Write32(SegmentLoadCommand32Size + NumSections * Section32Size); WriteString("", 16); Write32(0); // vmaddr Write32(0); // vmsize Write32(Header32Size + SegmentLoadCommand32Size + NumSections * Section32Size); // file offset Write32(0); // file size Write32(0x7); // maxprot Write32(0x7); // initprot Write32(NumSections); Write32(0); // flags assert(OS.tell() - Start == SegmentLoadCommand32Size); } void WriteSection32(const MCSectionData &SD) { // struct section (68 bytes) uint64_t Start = OS.tell(); (void) Start; // FIXME: cast<> support! const MCSectionMachO &Section = static_cast(SD.getSection()); WriteString(Section.getSectionName(), 16); WriteString(Section.getSegmentName(), 16); Write32(0); // address Write32(SD.getFileSize()); // size Write32(SD.getFileOffset()); assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); Write32(Log2_32(SD.getAlignment())); Write32(0); // file offset of relocation entries Write32(0); // number of relocation entrions Write32(Section.getTypeAndAttributes()); Write32(0); // reserved1 Write32(Section.getStubSize()); // reserved2 assert(OS.tell() - Start == Section32Size); } }; } /* *** */ MCFragment::MCFragment(MCSectionData *SD) { if (SD) SD->getFragmentList().push_back(this); } /* *** */ MCSectionData::MCSectionData() : Section(*(MCSection*)0) {} MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(_Section), Alignment(1), FileOffset(0), FileSize(0) { if (A) A->getSectionList().push_back(this); } void MCSectionData::WriteFileData(raw_ostream &OS) const { } /* *** */ MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {} MCAssembler::~MCAssembler() { } void MCAssembler::Finish() { unsigned NumSections = Sections.size(); // Compute the file offsets so we can write in a single pass. uint64_t Offset = MachObjectWriter::getPrologSize32(NumSections); for (iterator it = begin(), ie = end(); it != ie; ++it) { it->setFileOffset(Offset); Offset += it->getFileSize(); } MachObjectWriter MOW(OS); // Write the prolog, starting with the header and load command... MOW.WriteHeader32(NumSections); MOW.WriteSegmentLoadCommand32(NumSections); // ... and then the section headers. for (iterator it = begin(), ie = end(); it != ie; ++it) MOW.WriteSection32(*it); // Finally, write the section data. for (iterator it = begin(), ie = end(); it != ie; ++it) it->WriteFileData(OS); OS.flush(); }