From eb883af3903286ac20f5bbf549c555c9ef961e14 Mon Sep 17 00:00:00 2001 From: Nate Begeman Date: Wed, 23 Aug 2006 21:08:52 +0000 Subject: [PATCH] Initial checkin of the Mach-O emitter. There's plenty of fixmes, but it does emit linkable .o files in very simple cases. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29850 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/MachOWriter.h | 600 ++++++++++++++++++++++++ lib/CodeGen/MachOWriter.cpp | 428 +++++++++++++++++ lib/Target/PowerPC/PPC.h | 9 +- lib/Target/PowerPC/PPCCodeEmitter.cpp | 56 +-- lib/Target/PowerPC/PPCMachOWriter.cpp | 41 ++ lib/Target/PowerPC/PPCTargetMachine.cpp | 26 +- lib/Target/X86/X86TargetMachine.cpp | 2 +- tools/llc/llc.cpp | 3 - 8 files changed, 1118 insertions(+), 47 deletions(-) create mode 100644 include/llvm/CodeGen/MachOWriter.h create mode 100644 lib/CodeGen/MachOWriter.cpp create mode 100644 lib/Target/PowerPC/PPCMachOWriter.cpp diff --git a/include/llvm/CodeGen/MachOWriter.h b/include/llvm/CodeGen/MachOWriter.h new file mode 100644 index 00000000000..37fa005b8ea --- /dev/null +++ b/include/llvm/CodeGen/MachOWriter.h @@ -0,0 +1,600 @@ +//=== MachOWriter.h - Target-independent Mach-O writer support --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chris Lattner and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MachOWriter class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHOWRITER_H +#define LLVM_CODEGEN_MACHOWRITER_H + +#include "llvm/CodeGen/MachineRelocation.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include + +namespace llvm { + class GlobalVariable; + class Mangler; + class MachineCodeEmitter; + class MachOCodeEmitter; + + /// MachOWriter - This class implements the common target-independent code for + /// writing Mach-O files. Targets should derive a class from this to + /// parameterize the output format. + /// + class MachOWriter : public MachineFunctionPass { + friend class MachOCodeEmitter; + public: + MachineCodeEmitter &getMachineCodeEmitter() const { + return *(MachineCodeEmitter*)MCE; + } + + ~MachOWriter(); + + typedef std::vector DataBuffer; + + protected: + MachOWriter(std::ostream &O, TargetMachine &TM); + + /// Output stream to send the resultant object file to. + /// + std::ostream &O; + + /// Target machine description. + /// + TargetMachine &TM; + + /// Mang - The object used to perform name mangling for this module. + /// + Mangler *Mang; + + /// MCE - The MachineCodeEmitter object that we are exposing to emit machine + /// code for functions to the .o file. + MachOCodeEmitter *MCE; + + /// is64Bit/isLittleEndian - This information is inferred from the target + /// machine directly, indicating what header values and flags to set. + bool is64Bit, isLittleEndian; + + /// doInitialization - Emit the file header and all of the global variables + /// for the module to the Mach-O file. + bool doInitialization(Module &M); + + bool runOnMachineFunction(MachineFunction &MF); + + /// doFinalization - Now that the module has been completely processed, emit + /// the Mach-O file to 'O'. + bool doFinalization(Module &M); + + /// MachOHeader - This struct contains the header information about a + /// specific architecture type/subtype pair that is emitted to the file. + struct MachOHeader { + uint32_t magic; // mach magic number identifier + uint32_t cputype; // cpu specifier + uint32_t cpusubtype; // machine specifier + uint32_t filetype; // type of file + uint32_t ncmds; // number of load commands + uint32_t sizeofcmds; // the size of all the load commands + uint32_t flags; // flags + uint32_t reserved; // 64-bit only + + /// HeaderData - The actual data for the header which we are building + /// up for emission to the file. + DataBuffer HeaderData; + + // Constants for the cputype field + // see + enum { CPU_TYPE_I386 = 7, + CPU_TYPE_X86_64 = 7 | 0x1000000, + CPU_TYPE_ARM = 12, + CPU_TYPE_SPARC = 14, + CPU_TYPE_POWERPC = 18, + CPU_TYPE_POWERPC64 = 18 | 0x1000000 + }; + + // Constants for the cpusubtype field + // see + enum { CPU_SUBTYPE_I386_ALL = 3, + CPU_SUBTYPE_X86_64_ALL = 3, + CPU_SUBTYPE_ARM_ALL = 0, + CPU_SUBTYPE_SPARC_ALL = 0, + CPU_SUBTYPE_POWERPC_ALL = 0 + }; + + // Constants for the filetype field + // see for additional info on the various types + enum { MH_OBJECT = 1, // relocatable object file + MH_EXECUTE = 2, // demand paged executable file + MH_FVMLIB = 3, // fixed VM shared library file + MH_CORE = 4, // core file + MH_PRELOAD = 5, // preloaded executable file + MH_DYLIB = 6, // dynamically bound shared library + MH_DYLINKER = 7, // dynamic link editor + MH_BUNDLE = 8, // dynamically bound bundle file + MH_DYLIB_STUB = 9, // shared library stub for static linking only + MH_DSYM = 10 // companion file wiht only debug sections + }; + + // Constants for the flags field + enum { MH_NOUNDEFS = 1 << 0, + // the object file has no undefined references + MH_INCRLINK = 1 << 1, + // the object file is the output of an incremental link against + // a base file and cannot be link edited again + MH_DYLDLINK = 1 << 2, + // the object file is input for the dynamic linker and cannot be + // statically link edited again. + MH_BINDATLOAD = 1 << 3, + // the object file's undefined references are bound by the + // dynamic linker when loaded. + MH_PREBOUND = 1 << 4, + // the file has its dynamic undefined references prebound + MH_SPLIT_SEGS = 1 << 5, + // the file has its read-only and read-write segments split + // see + MH_LAZY_INIT = 1 << 6, + // the shared library init routine is to be run lazily via + // catching memory faults to its writable segments (obsolete) + MH_TWOLEVEL = 1 << 7, + // the image is using two-level namespace bindings + MH_FORCE_FLAT = 1 << 8, + // the executable is forcing all images to use flat namespace + // bindings. + MH_NOMULTIDEFS = 1 << 8, + // this umbrella guarantees no multiple definitions of symbols + // in its sub-images so the two-level namespace hints can + // always be used. + MH_NOFIXPREBINDING = 1 << 10, + // do not have dyld notify the prebidning agent about this + // executable. + MH_PREBINDABLE = 1 << 11, + // the binary is not prebound but can have its prebinding + // redone. only used when MH_PREBOUND is not set. + MH_ALLMODSBOUND = 1 << 12, + // indicates that this binary binds to all two-level namespace + // modules of its dependent libraries. Only used when + // MH_PREBINDABLE and MH_TWOLEVEL are both set. + MH_SUBSECTIONS_VIA_SYMBOLS = 1 << 13, + // safe to divide up the sections into sub-sections via symbols + // for dead code stripping. + MH_CANONICAL = 1 << 14, + // the binary has been canonicalized via the unprebind operation + MH_WEAK_DEFINES = 1 << 15, + // the final linked image contains external weak symbols + MH_BINDS_TO_WEAK = 1 << 16, + // the final linked image uses weak symbols + MH_ALLOW_STACK_EXECUTION = 1 << 17 + // When this bit is set, all stacks in the task will be given + // stack execution privilege. Only used in MH_EXECUTE filetype + }; + + MachOHeader() : magic(0), cputype(0), cpusubtype(0), filetype(0), + ncmds(0), sizeofcmds(0), flags(0), reserved(0) { } + + /// cmdSize - This routine returns the size of the MachOSection as written + /// to disk, depending on whether the destination is a 64 bit Mach-O file. + unsigned cmdSize(bool is64Bit) const { + if (is64Bit) + return 8 * sizeof(uint32_t); + else + return 7 * sizeof(uint32_t); + } + + /// setMagic - This routine sets the appropriate value for the 'magic' + /// field based on pointer size and endianness. + void setMagic(bool isLittleEndian, bool is64Bit) { + if (isLittleEndian) + if (is64Bit) magic = 0xcffaedfe; + else magic = 0xcefaedfe; + else + if (is64Bit) magic = 0xfeedfacf; + else magic = 0xfeedface; + } + }; + + /// Header - An instance of MachOHeader that we will update while we build + /// the file, and then emit during finalization. + MachOHeader Header; + + private: + + /// MachOSegment - This struct contains the necessary information to + /// emit the load commands for each section in the file. + struct MachOSegment { + uint32_t cmd; // LC_SEGMENT or LC_SEGMENT_64 + uint32_t cmdsize; // Total size of this struct and section commands + std::string segname; // segment name + uint64_t vmaddr; // address of this segment + uint64_t vmsize; // size of this segment, may be larger than filesize + uint64_t fileoff; // offset in file + uint64_t filesize; // amount to read from file + uint32_t maxprot; // maximum VM protection + uint32_t initprot; // initial VM protection + uint32_t nsects; // number of sections in this segment + uint32_t flags; // flags + + // Constants for the vm protection fields + // see + enum { VM_PROT_NONE = 0x00, + VM_PROT_READ = 0x01, // read permission + VM_PROT_WRITE = 0x02, // write permission + VM_PROT_EXECUTE = 0x04, // execute permission, + VM_PROT_ALL = 0x07 + }; + + // Constants for the cmd field + // see + enum { LC_SEGMENT = 0x01, // segment of this file to be mapped + LC_SEGMENT_64 = 0x19 // 64-bit segment of this file to be mapped + }; + + /// cmdSize - This routine returns the size of the MachOSection as written + /// to disk, depending on whether the destination is a 64 bit Mach-O file. + unsigned cmdSize(bool is64Bit) const { + if (is64Bit) + return 6 * sizeof(uint32_t) + 4 * sizeof(uint64_t) + 16; + else + return 10 * sizeof(uint32_t) + 16; // addresses only 32 bits + } + + MachOSegment(const std::string &seg, bool is64Bit) + : cmd(is64Bit ? LC_SEGMENT_64 : LC_SEGMENT), cmdsize(0), segname(seg), + vmaddr(0), vmsize(0), fileoff(0), filesize(0), maxprot(VM_PROT_ALL), + initprot(VM_PROT_ALL), nsects(0), flags(0) { } + }; + + /// MachOSection - This struct contains information about each section in a + /// particular segment that is emitted to the file. This is eventually + /// turned into the SectionCommand in the load command for a particlar + /// segment. + struct MachOSection { + std::string sectname; // name of this section, + std::string segname; // segment this section goes in + uint64_t addr; // memory address of this section + uint64_t size; // size in bytes of this section + uint32_t offset; // file offset of this section + uint32_t align; // section alignment (power of 2) + uint32_t reloff; // file offset of relocation entries + uint32_t nreloc; // number of relocation entries + uint32_t flags; // flags (section type and attributes) + uint32_t reserved1; // reserved (for offset or index) + uint32_t reserved2; // reserved (for count or sizeof) + uint32_t reserved3; // reserved (64 bit only) + + /// A unique number for this section, which will be used to match symbols + /// to the correct section. + uint32_t Index; + + /// SectionData - The actual data for this section which we are building + /// up for emission to the file. + DataBuffer SectionData; + + // Constants for the section types (low 8 bits of flags field) + // see + enum { S_REGULAR = 0, + // regular section + S_ZEROFILL = 1, + // zero fill on demand section + S_CSTRING_LITERALS = 2, + // section with only literal C strings + S_4BYTE_LITERALS = 3, + // section with only 4 byte literals + S_8BYTE_LITERALS = 4, + // section with only 8 byte literals + S_LITERAL_POINTERS = 5, + // section with only pointers to literals + S_NON_LAZY_SYMBOL_POINTERS = 6, + // section with only non-lazy symbol pointers + S_LAZY_SYMBOL_POINTERS = 7, + // section with only lazy symbol pointers + S_SYMBOL_STUBS = 8, + // section with only symbol stubs + // byte size of stub in the reserved2 field + S_MOD_INIT_FUNC_POINTERS = 9, + // section with only function pointers for initialization + S_MOD_TERM_FUNC_POINTERS = 10, + // section with only function pointers for termination + S_COALESCED = 11, + // section contains symbols that are coalesced + S_GB_ZEROFILL = 12, + // zero fill on demand section (that can be larger than 4GB) + S_INTERPOSING = 13, + // section with only pairs of function pointers for interposing + S_16BYTE_LITERALS = 14 + // section with only 16 byte literals + }; + + // Constants for the section flags (high 24 bits of flags field) + // see + enum { S_ATTR_PURE_INSTRUCTIONS = 1 << 31, + // section contains only true machine instructions + S_ATTR_NO_TOC = 1 << 30, + // section contains coalesced symbols that are not to be in a + // ranlib table of contents + S_ATTR_STRIP_STATIC_SYMS = 1 << 29, + // ok to strip static symbols in this section in files with the + // MY_DYLDLINK flag + S_ATTR_NO_DEAD_STRIP = 1 << 28, + // no dead stripping + S_ATTR_LIVE_SUPPORT = 1 << 27, + // blocks are live if they reference live blocks + S_ATTR_SELF_MODIFYING_CODE = 1 << 26, + // used with i386 code stubs written on by dyld + S_ATTR_DEBUG = 1 << 25, + // a debug section + S_ATTR_SOME_INSTRUCTIONS = 1 << 10, + // section contains some machine instructions + S_ATTR_EXT_RELOC = 1 << 9, + // section has external relocation entries + S_ATTR_LOC_RELOC = 1 << 8 + // section has local relocation entries + }; + + /// cmdSize - This routine returns the size of the MachOSection as written + /// to disk, depending on whether the destination is a 64 bit Mach-O file. + unsigned cmdSize(bool is64Bit) const { + if (is64Bit) + return 7 * sizeof(uint32_t) + 2 * sizeof(uint64_t) + 32; + else + return 9 * sizeof(uint32_t) + 32; // addresses only 32 bits + } + + MachOSection(const std::string &seg, const std::string §) + : sectname(sect), segname(seg), addr(0), size(0), offset(0), align(0), + reloff(0), nreloc(0), flags(0), reserved1(0), reserved2(0), + reserved3(0) { } + }; + + /// SectionList - This is the list of sections that we have emitted to the + /// file. Once the file has been completely built, the segment load command + /// SectionCommands are constructed from this info. + std::list SectionList; + + /// SectionLookup - This is a mapping from section name to SectionList entry + std::map SectionLookup; + + /// getSection - Return the section with the specified name, creating a new + /// section if one does not already exist. + MachOSection &getSection(const std::string &seg, const std::string §, + unsigned Flags = 0) { + MachOSection *&SN = SectionLookup[seg+sect]; + if (SN) return *SN; + + SectionList.push_back(MachOSection(seg, sect)); + SN = &SectionList.back(); + SN->Index = SectionList.size(); + SN->flags = MachOSection::S_REGULAR | Flags; + return *SN; + } + MachOSection &getTextSection() { + return getSection("__TEXT", "__text", + MachOSection::S_ATTR_PURE_INSTRUCTIONS | + MachOSection::S_ATTR_SOME_INSTRUCTIONS); + } + + /// MachOSymTab - This struct contains information about the offsets and + /// size of symbol table information. + /// segment. + struct MachOSymTab { + uint32_t cmd; // LC_SYMTAB + uint32_t cmdsize; // sizeof( MachOSymTab ) + uint32_t symoff; // symbol table offset + uint32_t nsyms; // number of symbol table entries + uint32_t stroff; // string table offset + uint32_t strsize; // string table size in bytes + + // Constants for the cmd field + // see + enum { LC_SYMTAB = 0x02 // link-edit stab symbol table info + }; + + MachOSymTab() : cmd(LC_SYMTAB), cmdsize(6 * sizeof(uint32_t)), symoff(0), + nsyms(0), stroff(0), strsize(0) { } + }; + + /// MachOSymTab - This struct contains information about the offsets and + /// size of symbol table information. + /// segment. + struct MachODySymTab { + uint32_t cmd; // LC_DYSYMTAB + uint32_t cmdsize; // sizeof( MachODySymTab ) + uint32_t ilocalsym; // index to local symbols + uint32_t nlocalsym; // number of local symbols + uint32_t iextdefsym; // index to externally defined symbols + uint32_t nextdefsym; // number of externally defined symbols + uint32_t iundefsym; // index to undefined symbols + uint32_t nundefsym; // number of undefined symbols + uint32_t tocoff; // file offset to table of contents + uint32_t ntoc; // number of entries in table of contents + uint32_t modtaboff; // file offset to module table + uint32_t nmodtab; // number of module table entries + uint32_t extrefsymoff; // offset to referenced symbol table + uint32_t nextrefsyms; // number of referenced symbol table entries + uint32_t indirectsymoff; // file offset to the indirect symbol table + uint32_t nindirectsyms; // number of indirect symbol table entries + uint32_t extreloff; // offset to external relocation entries + uint32_t nextrel; // number of external relocation entries + uint32_t locreloff; // offset to local relocation entries + uint32_t nlocrel; // number of local relocation entries + + // Constants for the cmd field + // see + enum { LC_DYSYMTAB = 0x0B // dynamic link-edit symbol table info + }; + + MachODySymTab() : cmd(LC_DYSYMTAB), cmdsize(20 * sizeof(uint32_t)), + ilocalsym(0), nlocalsym(0), iextdefsym(0), nextdefsym(0), + iundefsym(0), nundefsym(0), tocoff(0), ntoc(0), modtaboff(0), + nmodtab(0), extrefsymoff(0), nextrefsyms(0), indirectsymoff(0), + nindirectsyms(0), extreloff(0), nextrel(0), locreloff(0), nlocrel(0) { } + }; + + /// SymTab - The "stab" style symbol table information + MachOSymTab SymTab; + /// DySymTab - symbol table info for the dynamic link editor + MachODySymTab DySymTab; + + /// MachOSym - This struct contains information about each symbol that is + /// added to logical symbol table for the module. This is eventually + /// turned into a real symbol table in the file. + struct MachOSym { + const GlobalValue *GV; // The global value this corresponds to. + uint32_t n_strx; // index into the string table + uint8_t n_type; // type flag + uint8_t n_sect; // section number or NO_SECT + int16_t n_desc; // see + uint64_t n_value; // value for this symbol (or stab offset) + + // Constants for the n_sect field + // see + enum { NO_SECT = 0 }; // symbol is not in any section + + // Constants for the n_type field + // see + enum { N_UNDF = 0x0, // undefined, n_sect == NO_SECT + N_ABS = 0x2, // absolute, n_sect == NO_SECT + N_SECT = 0xe, // defined in section number n_sect + N_PBUD = 0xc, // prebound undefined (defined in a dylib) + N_INDR = 0xa // indirect + }; + // The following bits are OR'd into the types above. For example, a type + // of 0x0f would be an external N_SECT symbol (0x0e | 0x01). + enum { N_EXT = 0x01, // external symbol bit + N_PEXT = 0x10 // private external symbol bit + }; + + // Constants for the n_desc field + // see + enum { REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0, + REFERENCE_FLAG_UNDEFINED_LAZY = 1, + REFERENCE_FLAG_DEFINED = 2, + REFERENCE_FLAG_PRIVATE_DEFINED = 3, + REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4, + REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5 + }; + enum { N_NO_DEAD_STRIP = 0x0020, // symbol is not to be dead stripped + N_WEAK_REF = 0x0040, // symbol is weak referenced + N_WEAK_DEF = 0x0080 // coalesced symbol is a weak definition + }; + + /// entrySize - This routine returns the size of a symbol table entry as + /// written to disk. + static unsigned entrySize() { return 12; } + + MachOSym(const GlobalValue *gv, uint8_t sect) : GV(gv), n_strx(0), + n_type(N_UNDF), n_sect(sect), n_desc(0), n_value(0) {} + }; + + /// SymbolTable - This is the list of symbols we have emitted to the file. + /// This actually gets rearranged before emission to the file (to put the + /// local symbols first in the list). + std::vector SymbolTable; + + /// DynamicSymbolTable - This is just a vector of indices into + /// SymbolTable to aid in emitting the DYSYMTAB load command. + std::vector DynamicSymbolTable; + + /// StringTable - The table of strings referenced by SymbolTable entries + std::vector StringTable; + + // align - Emit padding into the file until the current output position is + // aligned to the specified power of two boundary. + static void align(DataBuffer &Output, unsigned Boundary) { + assert(Boundary && (Boundary & (Boundary-1)) == 0 && + "Must align to 2^k boundary"); + size_t Size = Output.size(); + if (Size & (Boundary-1)) { + // Add padding to get alignment to the correct place. + size_t Pad = Boundary-(Size & (Boundary-1)); + Output.resize(Size+Pad); + } + } + + void outbyte(DataBuffer &Output, unsigned char X) { + Output.push_back(X); + } + void outhalf(DataBuffer &Output, unsigned short X) { + if (isLittleEndian) { + Output.push_back(X&255); + Output.push_back(X >> 8); + } else { + Output.push_back(X >> 8); + Output.push_back(X&255); + } + } + void outword(DataBuffer &Output, unsigned X) { + if (isLittleEndian) { + Output.push_back((X >> 0) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 24) & 255); + } else { + Output.push_back((X >> 24) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 0) & 255); + } + } + void outxword(DataBuffer &Output, uint64_t X) { + if (isLittleEndian) { + Output.push_back(unsigned(X >> 0) & 255); + Output.push_back(unsigned(X >> 8) & 255); + Output.push_back(unsigned(X >> 16) & 255); + Output.push_back(unsigned(X >> 24) & 255); + Output.push_back(unsigned(X >> 32) & 255); + Output.push_back(unsigned(X >> 40) & 255); + Output.push_back(unsigned(X >> 48) & 255); + Output.push_back(unsigned(X >> 56) & 255); + } else { + Output.push_back(unsigned(X >> 56) & 255); + Output.push_back(unsigned(X >> 48) & 255); + Output.push_back(unsigned(X >> 40) & 255); + Output.push_back(unsigned(X >> 32) & 255); + Output.push_back(unsigned(X >> 24) & 255); + Output.push_back(unsigned(X >> 16) & 255); + Output.push_back(unsigned(X >> 8) & 255); + Output.push_back(unsigned(X >> 0) & 255); + } + } + void outaddr32(DataBuffer &Output, unsigned X) { + outword(Output, X); + } + void outaddr64(DataBuffer &Output, uint64_t X) { + outxword(Output, X); + } + void outaddr(DataBuffer &Output, uint64_t X) { + if (!is64Bit) + outword(Output, (unsigned)X); + else + outxword(Output, X); + } + void outstring(DataBuffer &Output, std::string &S, unsigned Length) { + char *buffer = (char *)calloc(1, Length); + unsigned i; + // FIXME: it is unclear if mach-o requires null terminated strings, or + // if a string of 16 bytes with no null terminator is ok. If so, + // we should switch to strncpy. + strlcpy(buffer, S.c_str(), Length); + + for (i = 0; i < Length; ++i) + outbyte(Output, buffer[i]); + + free(buffer); + } + private: + void EmitGlobal(GlobalVariable *GV); + void EmitHeaderAndLoadCommands(); + void EmitSections(); + void EmitRelocations(); + void EmitSymbolTable(); + void EmitStringTable(); + }; +} + +#endif diff --git a/lib/CodeGen/MachOWriter.cpp b/lib/CodeGen/MachOWriter.cpp new file mode 100644 index 00000000000..e3228cb5c77 --- /dev/null +++ b/lib/CodeGen/MachOWriter.cpp @@ -0,0 +1,428 @@ +//===-- MachOWriter.cpp - Target-independent Mach-O Writer code -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Nate Begeman and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the target-independent Mach-O writer. This file writes +// out the Mach-O file in the following order: +// +// #1 FatHeader (universal-only) +// #2 FatArch (universal-only, 1 per universal arch) +// Per arch: +// #3 Header +// #4 Load Commands +// #5 Sections +// #6 Relocations +// #7 Symbols +// #8 Strings +// +//===----------------------------------------------------------------------===// + +#include "llvm/Module.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineRelocation.h" +#include "llvm/CodeGen/MachOWriter.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetJITInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Mangler.h" +#include +using namespace llvm; + +//===----------------------------------------------------------------------===// +// MachOCodeEmitter Implementation +//===----------------------------------------------------------------------===// + +namespace llvm { + /// MachOCodeEmitter - This class is used by the MachOWriter to emit the code + /// for functions to the Mach-O file. + class MachOCodeEmitter : public MachineCodeEmitter { + MachOWriter &MOW; + + /// MOS - The current section we're writing to + MachOWriter::MachOSection *MOS; + + /// Relocations - These are the relocations that the function needs, as + /// emitted. + std::vector Relocations; + + /// MBBLocations - This vector is a mapping from MBB ID's to their address. + /// It is filled in by the StartMachineBasicBlock callback and queried by + /// the getMachineBasicBlockAddress callback. + std::vector MBBLocations; + + public: + MachOCodeEmitter(MachOWriter &mow) : MOW(mow) {} + + void startFunction(MachineFunction &F); + bool finishFunction(MachineFunction &F); + + void addRelocation(const MachineRelocation &MR) { + Relocations.push_back(MR); + } + + virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) { + if (MBBLocations.size() <= (unsigned)MBB->getNumber()) + MBBLocations.resize((MBB->getNumber()+1)*2); + MBBLocations[MBB->getNumber()] = getCurrentPCValue(); + } + + virtual intptr_t getConstantPoolEntryAddress(unsigned Index) const { + assert(0 && "CP not implementated yet!"); + return 0; + } + virtual intptr_t getJumpTableEntryAddress(unsigned Index) const { + assert(0 && "JT not implementated yet!"); + return 0; + } + + virtual intptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const { + assert(MBBLocations.size() > (unsigned)MBB->getNumber() && + MBBLocations[MBB->getNumber()] && "MBB not emitted!"); + return MBBLocations[MBB->getNumber()]; + } + + /// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE! + void startFunctionStub(unsigned StubSize) { + assert(0 && "JIT specific function called!"); + abort(); + } + void *finishFunctionStub(const Function *F) { + assert(0 && "JIT specific function called!"); + abort(); + return 0; + } + }; +} + +/// startFunction - This callback is invoked when a new machine function is +/// about to be emitted. +void MachOCodeEmitter::startFunction(MachineFunction &F) { + // Align the output buffer to the appropriate alignment, power of 2. + // FIXME: GENERICIZE!! + unsigned Align = 4; + + // Get the Mach-O Section that this function belongs in. + MOS = &MOW.getTextSection(); + + // FIXME: better memory management + MOS->SectionData.reserve(4096); + BufferBegin = &(MOS->SectionData[0]); + BufferEnd = BufferBegin + MOS->SectionData.capacity(); + CurBufferPtr = BufferBegin + MOS->size; + + // Upgrade the section alignment if required. + if (MOS->align < Align) MOS->align = Align; + + // Make sure we only relocate to this function's MBBs. + MBBLocations.clear(); +} + +/// finishFunction - This callback is invoked after the function is completely +/// finished. +bool MachOCodeEmitter::finishFunction(MachineFunction &F) { + MOS->size += CurBufferPtr - BufferBegin; + + // Get a symbol for the function to add to the symbol table + MachOWriter::MachOSym FnSym(F.getFunction(), MOS->Index); + + // Figure out the binding (linkage) of the symbol. + switch (F.getFunction()->getLinkage()) { + default: + // appending linkage is illegal for functions. + assert(0 && "Unknown linkage type!"); + case GlobalValue::ExternalLinkage: + FnSym.n_type = MachOWriter::MachOSym::N_SECT | MachOWriter::MachOSym::N_EXT; + break; + case GlobalValue::InternalLinkage: + FnSym.n_type = MachOWriter::MachOSym::N_SECT; + break; + } + + // Resolve the function's relocations either to concrete pointers in the case + // of branches from one block to another, or to target relocation entries. + for (unsigned i = 0, e = Relocations.size(); i != e; ++i) { + MachineRelocation &MR = Relocations[i]; + if (MR.isBasicBlock()) { + void *MBBAddr = (void *)getMachineBasicBlockAddress(MR.getBasicBlock()); + MR.setResultPointer(MBBAddr); + MOW.TM.getJITInfo()->relocate(BufferBegin, &MR, 1, 0); + // FIXME: we basically want the JITInfo relocate() function to rewrite + // this guy right now, so we just write the correct displacement + // to the file. + } else { + // isString | isGV | isCPI | isJTI + // FIXME: do something smart here. We won't be able to relocate these + // until the sections are all layed out, but we still need to + // record them. Maybe emit TargetRelocations and then resolve + // those at file writing time? + std::cerr << "whee!\n"; + } + } + Relocations.clear(); + + // Finally, add it to the symtab. + MOW.SymbolTable.push_back(FnSym); + return false; +} + +//===----------------------------------------------------------------------===// +// MachOWriter Implementation +//===----------------------------------------------------------------------===// + +MachOWriter::MachOWriter(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { + // FIXME: set cpu type and cpu subtype somehow from TM + is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; + isLittleEndian = TM.getTargetData()->isLittleEndian(); + + // Create the machine code emitter object for this target. + MCE = new MachOCodeEmitter(*this); +} + +MachOWriter::~MachOWriter() { + delete MCE; +} + +void MachOWriter::EmitGlobal(GlobalVariable *GV) { + // FIXME: do something smart here. +} + + +bool MachOWriter::runOnMachineFunction(MachineFunction &MF) { + // Nothing to do here, this is all done through the MCE object. + return false; +} + +bool MachOWriter::doInitialization(Module &M) { + // Set the magic value, now that we know the pointer size and endianness + Header.setMagic(isLittleEndian, is64Bit); + + // Set the file type + // FIXME: this only works for object files, we do not support the creation + // of dynamic libraries or executables at this time. + Header.filetype = MachOHeader::MH_OBJECT; + + Mang = new Mangler(M); + return false; +} + +/// doFinalization - Now that the module has been completely processed, emit +/// the Mach-O file to 'O'. +bool MachOWriter::doFinalization(Module &M) { + // Okay, the.text section has been completed, build the .data, .bss, and + // "common" sections next. + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) + EmitGlobal(I); + + // Emit the header and load commands. + EmitHeaderAndLoadCommands(); + + // Emit the text and data sections. + EmitSections(); + + // Emit the relocation entry data for each section. + // FIXME: presumably this should be a virtual method, since different targets + // have different relocation types. + EmitRelocations(); + + // Emit the symbol table. + // FIXME: we don't handle debug info yet, we should probably do that. + EmitSymbolTable(); + + // Emit the string table for the sections we have. + EmitStringTable(); + + // We are done with the abstract symbols. + SectionList.clear(); + SymbolTable.clear(); + DynamicSymbolTable.clear(); + + // Release the name mangler object. + delete Mang; Mang = 0; + return false; +} + +void MachOWriter::EmitHeaderAndLoadCommands() { + // Step #0: Fill in the segment load command size, since we need it to figure + // out the rest of the header fields + MachOSegment SEG("", is64Bit); + SEG.nsects = SectionList.size(); + SEG.cmdsize = SEG.cmdSize(is64Bit) + + SEG.nsects * SectionList.begin()->cmdSize(is64Bit); + + // Step #1: calculate the number of load commands. We always have at least + // one, for the LC_SEGMENT load command, plus two for the normal + // and dynamic symbol tables, if there are any symbols. + Header.ncmds = SymbolTable.empty() ? 1 : 3; + + // Step #2: calculate the size of the load commands + Header.sizeofcmds = SEG.cmdsize; + if (!SymbolTable.empty()) + Header.sizeofcmds += SymTab.cmdsize + DySymTab.cmdsize; + + // Step #3: write the header to the file + // Local alias to shortenify coming code. + DataBuffer &FH = Header.HeaderData; + outword(FH, Header.magic); + outword(FH, Header.cputype); + outword(FH, Header.cpusubtype); + outword(FH, Header.filetype); + outword(FH, Header.ncmds); + outword(FH, Header.sizeofcmds); + outword(FH, Header.flags); + if (is64Bit) + outword(FH, Header.reserved); + + // Step #4: Finish filling in the segment load command and write it out + for (std::list::iterator I = SectionList.begin(), + E = SectionList.end(); I != E; ++I) + SEG.filesize += I->size; + SEG.vmsize = SEG.filesize; + SEG.fileoff = Header.cmdSize(is64Bit) + Header.sizeofcmds; + + outword(FH, SEG.cmd); + outword(FH, SEG.cmdsize); + outstring(FH, SEG.segname, 16); + outaddr(FH, SEG.vmaddr); + outaddr(FH, SEG.vmsize); + outaddr(FH, SEG.fileoff); + outaddr(FH, SEG.filesize); + outword(FH, SEG.maxprot); + outword(FH, SEG.initprot); + outword(FH, SEG.nsects); + outword(FH, SEG.flags); + + // Step #5: Write out the section commands for each section + for (std::list::iterator I = SectionList.begin(), + E = SectionList.end(); I != E; ++I) { + I->offset = SEG.fileoff; // FIXME: separate offset + outstring(FH, I->sectname, 16); + outstring(FH, I->segname, 16); + outaddr(FH, I->addr); + outaddr(FH, I->size); + outword(FH, I->offset); + outword(FH, I->align); + outword(FH, I->reloff); + outword(FH, I->nreloc); + outword(FH, I->flags); + outword(FH, I->reserved1); + outword(FH, I->reserved2); + if (is64Bit) + outword(FH, I->reserved3); + } + + // Step #6: Emit LC_SYMTAB/LC_DYSYMTAB load commands + // FIXME: We'll need to scan over the symbol table and possibly do the sort + // here so that we can set the proper indices in the dysymtab load command for + // the index and number of external symbols defined in this module. + // FIXME: We'll also need to scan over all the symbols so that we can + // calculate the size of the string table. + // FIXME: add size of relocs + SymTab.symoff = SEG.fileoff + SEG.filesize; + SymTab.nsyms = SymbolTable.size(); + SymTab.stroff = SymTab.symoff + SymTab.nsyms * MachOSym::entrySize(); + SymTab.strsize = 10; + outword(FH, SymTab.cmd); + outword(FH, SymTab.cmdsize); + outword(FH, SymTab.symoff); + outword(FH, SymTab.nsyms); + outword(FH, SymTab.stroff); + outword(FH, SymTab.strsize); + + // FIXME: set DySymTab fields appropriately + outword(FH, DySymTab.cmd); + outword(FH, DySymTab.cmdsize); + outword(FH, DySymTab.ilocalsym); + outword(FH, DySymTab.nlocalsym); + outword(FH, DySymTab.iextdefsym); + outword(FH, DySymTab.nextdefsym); + outword(FH, DySymTab.iundefsym); + outword(FH, DySymTab.nundefsym); + outword(FH, DySymTab.tocoff); + outword(FH, DySymTab.ntoc); + outword(FH, DySymTab.modtaboff); + outword(FH, DySymTab.nmodtab); + outword(FH, DySymTab.extrefsymoff); + outword(FH, DySymTab.nextrefsyms); + outword(FH, DySymTab.indirectsymoff); + outword(FH, DySymTab.nindirectsyms); + outword(FH, DySymTab.extreloff); + outword(FH, DySymTab.nextrel); + outword(FH, DySymTab.locreloff); + outword(FH, DySymTab.nlocrel); + + O.write((char*)&FH[0], FH.size()); +} + +/// EmitSections - Now that we have constructed the file header and load +/// commands, emit the data for each section to the file. +void MachOWriter::EmitSections() { + for (std::list::iterator I = SectionList.begin(), + E = SectionList.end(); I != E; ++I) { + O.write((char*)&I->SectionData[0], I->size); + } +} + +void MachOWriter::EmitRelocations() { + // FIXME: this should probably be a pure virtual function, since the + // relocation types and layout of the relocations themselves are target + // specific. +} + +/// EmitSymbolTable - Sort the symbols we encountered and assign them each a +/// string table index so that they appear in the correct order in the output +/// file. +void MachOWriter::EmitSymbolTable() { + // The order of the symbol table is: + // local symbols + // defined external symbols (sorted by name) + // undefined external symbols (sorted by name) + DataBuffer ST; + + // FIXME: enforce the above ordering, presumably by sorting by name, + // then partitioning twice. + unsigned stringIndex; + for (std::vector::iterator I = SymbolTable.begin(), + E = SymbolTable.end(); I != E; ++I) { + // FIXME: remove when we actually calculate these correctly + I->n_strx = 1; + StringTable.push_back(Mang->getValueName(I->GV)); + // Emit nlist to buffer + outword(ST, I->n_strx); + outbyte(ST, I->n_type); + outbyte(ST, I->n_sect); + outhalf(ST, I->n_desc); + outaddr(ST, I->n_value); + } + + O.write((char*)&ST[0], ST.size()); +} + +/// EmitStringTable - This method adds and emits a section for the Mach-O +/// string table. +void MachOWriter::EmitStringTable() { + // The order of the string table is: + // strings for external symbols + // strings for local symbols + // This is the symbol table, but backwards. This allows us to avoid a sorting + // the symbol table again; all we have to do is use a reverse iterator. + DataBuffer ST; + + // Write out a leading zero byte when emitting string table, for n_strx == 0 + // which means an empty string. + outbyte(ST, 0); + + for (std::vector::iterator I = StringTable.begin(), + E = StringTable.end(); I != E; ++I) { + // FIXME: do not arbitrarily cap symbols to 16 characters + // FIXME: do something more efficient than outstring + outstring(ST, *I, 16); + } + O.write((char*)&ST[0], ST.size()); +} diff --git a/lib/Target/PowerPC/PPC.h b/lib/Target/PowerPC/PPC.h index 5e8e15cc3b4..f34b9b08a09 100644 --- a/lib/Target/PowerPC/PPC.h +++ b/lib/Target/PowerPC/PPC.h @@ -19,11 +19,18 @@ namespace llvm { -class FunctionPass; class PPCTargetMachine; +class PassManager; +class FunctionPass; +class MachineCodeEmitter; + FunctionPass *createPPCBranchSelectionPass(); FunctionPass *createPPCISelDag(PPCTargetMachine &TM); FunctionPass *createDarwinAsmPrinter(std::ostream &OS, PPCTargetMachine &TM); +FunctionPass *createPPCCodeEmitterPass(PPCTargetMachine &TM, + MachineCodeEmitter &MCE); +void addPPCMachOObjectWriterPass(PassManager &FPM, std::ostream &o, + PPCTargetMachine &tm); } // end namespace llvm; // GCC #defines PPC on Linux but we use it as our namespace name diff --git a/lib/Target/PowerPC/PPCCodeEmitter.cpp b/lib/Target/PowerPC/PPCCodeEmitter.cpp index 49d3f25f8c2..85697f938b5 100644 --- a/lib/Target/PowerPC/PPCCodeEmitter.cpp +++ b/lib/Target/PowerPC/PPCCodeEmitter.cpp @@ -21,7 +21,7 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/Support/Debug.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Visibility.h" #include "llvm/Target/TargetOptions.h" #include @@ -62,19 +62,11 @@ namespace { }; } -/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get -/// machine code emitted. This uses a MachineCodeEmitter object to handle -/// actually outputting the machine code and resolving things like the address -/// of functions. This method should returns true if machine code emission is -/// not supported. -/// -bool PPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, - MachineCodeEmitter &MCE) { - // Machine code emitter pass for PowerPC - PM.add(new PPCCodeEmitter(*this, MCE)); - // Delete machine code for this function after emitting it - PM.add(createMachineCodeDeleter()); - return false; +/// createPPCCodeEmitterPass - Return a pass that emits the collected PPC code +/// to the specified MCE object. +FunctionPass *llvm::createPPCCodeEmitterPass(PPCTargetMachine &TM, + MachineCodeEmitter &MCE) { + return new PPCCodeEmitter(TM, MCE); } #ifdef __APPLE__ @@ -132,7 +124,8 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) { } } else if (MO.isImmediate()) { rv = MO.getImmedValue(); - } else if (MO.isGlobalAddress() || MO.isExternalSymbol()) { + } else if (MO.isGlobalAddress() || MO.isExternalSymbol() || + MO.isConstantPoolIndex() || MO.isJumpTableIndex()) { unsigned Reloc = 0; if (MI.getOpcode() == PPC::BL) Reloc = PPC::reloc_pcrel_bx; @@ -141,6 +134,7 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) { default: DEBUG(MI.dump()); assert(0 && "Unknown instruction for relocation!"); case PPC::LIS: case PPC::LIS8: + case PPC::ADDIS: case PPC::ADDIS8: Reloc = PPC::reloc_absolute_high; // Pointer to symbol break; @@ -176,9 +170,17 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) { if (MO.isGlobalAddress()) MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, MO.getGlobal(), 0)); - else + else if (MO.isExternalSymbol()) MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), Reloc, MO.getSymbolName(), 0)); + else if (MO.isConstantPoolIndex()) + MCE.addRelocation(MachineRelocation::getConstPool( + MCE.getCurrentPCOffset(), + Reloc, MO.getConstantPoolIndex(), 0)); + else // isJumpTableIndex + MCE.addRelocation(MachineRelocation::getJumpTable( + MCE.getCurrentPCOffset(), + Reloc, MO.getJumpTableIndex(), 0)); } else if (MO.isMachineBasicBlock()) { unsigned Reloc = 0; unsigned Opcode = MI.getOpcode(); @@ -190,28 +192,6 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), Reloc, MO.getMachineBasicBlock())); - } else if (MO.isConstantPoolIndex() || MO.isJumpTableIndex()) { - if (MO.isConstantPoolIndex()) - rv = MCE.getConstantPoolEntryAddress(MO.getConstantPoolIndex()); - else - rv = MCE.getJumpTableEntryAddress(MO.getJumpTableIndex()); - - unsigned Opcode = MI.getOpcode(); - if (Opcode == PPC::LIS || Opcode == PPC::LIS8 || - Opcode == PPC::ADDIS || Opcode == PPC::ADDIS8) { - // lis wants hi16(addr) - if ((short)rv < 0) rv += 1 << 16; - rv >>= 16; - } else if (Opcode == PPC::LWZ || Opcode == PPC::LWZ8 || - Opcode == PPC::LA || - Opcode == PPC::LI || Opcode == PPC::LI8 || - Opcode == PPC::LFS || Opcode == PPC::LFD) { - // These load opcodes want lo16(addr) - rv &= 0xffff; - } else { - MI.dump(); - assert(0 && "Unknown constant pool or jump table using instruction!"); - } } else { std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n"; abort(); diff --git a/lib/Target/PowerPC/PPCMachOWriter.cpp b/lib/Target/PowerPC/PPCMachOWriter.cpp new file mode 100644 index 00000000000..29f823829d8 --- /dev/null +++ b/lib/Target/PowerPC/PPCMachOWriter.cpp @@ -0,0 +1,41 @@ +//===-- PPCMachOWriter.cpp - Emit a Mach-O file for the PowerPC backend ---===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Nate Begeman and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a Mach-O writer for the PowerPC backend. The public +// interface to this file is the createPPCMachOObjectWriterPass function. +// +//===----------------------------------------------------------------------===// + +#include "PPCTargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/MachOWriter.h" +#include "llvm/Support/Visibility.h" +using namespace llvm; + +namespace { + class VISIBILITY_HIDDEN PPCMachOWriter : public MachOWriter { + public: + PPCMachOWriter(std::ostream &O, PPCTargetMachine &TM) : MachOWriter(O, TM) { + // FIMXE: choose ppc64 when appropriate + Header.cputype = MachOHeader::CPU_TYPE_POWERPC; + Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL; + } + + }; +} + +/// addPPCMachOObjectWriterPass - Returns a pass that outputs the generated code +/// as a Mach-O object file. +/// +void llvm::addPPCMachOObjectWriterPass(PassManager &FPM, + std::ostream &O, PPCTargetMachine &TM) { + PPCMachOWriter *EW = new PPCMachOWriter(O, TM); + FPM.add(EW); + FPM.add(createPPCCodeEmitterPass(TM, EW->getMachineCodeEmitter())); +} diff --git a/lib/Target/PowerPC/PPCTargetMachine.cpp b/lib/Target/PowerPC/PPCTargetMachine.cpp index deb479a4c34..e360f37f3a6 100644 --- a/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -109,11 +109,11 @@ PPC64TargetMachine::PPC64TargetMachine(const Module &M, const std::string &FS) /// addPassesToEmitFile - Add passes to the specified pass manager to implement /// a static compiler for this target. /// -bool PPCTargetMachine::addPassesToEmitFile(PassManager &PM, - std::ostream &Out, +bool PPCTargetMachine::addPassesToEmitFile(PassManager &PM, std::ostream &Out, CodeGenFileType FileType, bool Fast) { - if (FileType != TargetMachine::AssemblyFile) return true; + if (FileType != TargetMachine::AssemblyFile && + FileType != TargetMachine::ObjectFile) return true; // Run loop strength reduction before anything else. if (!Fast) PM.add(createLoopStrengthReducePass(&TLInfo)); @@ -146,7 +146,11 @@ bool PPCTargetMachine::addPassesToEmitFile(PassManager &PM, // Must run branch selection immediately preceding the asm printer PM.add(createPPCBranchSelectionPass()); - PM.add(createDarwinAsmPrinter(Out, *this)); + if (FileType == TargetMachine::AssemblyFile) + PM.add(createDarwinAsmPrinter(Out, *this)); + else + // FIXME: support PPC ELF files at some point + addPPCMachOObjectWriterPass(PM, Out, *this); PM.add(createMachineCodeDeleter()); return false; @@ -184,3 +188,17 @@ void PPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { PM.add(createMachineFunctionPrinterPass(&std::cerr)); } +/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get +/// machine code emitted. This uses a MachineCodeEmitter object to handle +/// actually outputting the machine code and resolving things like the address +/// of functions. This method should returns true if machine code emission is +/// not supported. +/// +bool PPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE) { + // Machine code emitter pass for PowerPC + PM.add(createPPCCodeEmitterPass(*this, MCE)); + // Delete machine code for this function after emitting it + PM.add(createMachineCodeDeleter()); + return false; +} diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index 90175acd1d6..9616dc18f27 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -136,7 +136,7 @@ bool X86TargetMachine::addPassesToEmitFile(PassManager &PM, std::ostream &Out, case TargetMachine::ObjectFile: // FIXME: We only support emission of ELF files for now, this should check // the target triple and decide on the format to write (e.g. COFF on - // win32). + // win32 or Mach-O on darwin). addX86ELFObjectWriterPass(PM, Out, *this); break; } diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 93391e9f704..3ec213b2086 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -219,9 +219,6 @@ int main(int argc, char **argv) { } } - if (FileType != TargetMachine::AssemblyFile) - std::cerr << "WARNING: only -filetype=asm is currently supported.\n"; - // Ask the target to add backend passes as necessary. if (Target.addPassesToEmitFile(Passes, *Out, FileType, Fast)) { std::cerr << argv[0] << ": target '" << Target.getName()