aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNate Begeman <natebegeman@mac.com>2006-08-23 21:08:52 +0000
committerNate Begeman <natebegeman@mac.com>2006-08-23 21:08:52 +0000
commiteb883af3903286ac20f5bbf549c555c9ef961e14 (patch)
tree876fc716e1d1cfc6c0341ffd7a5a750b17c4d136
parent81bc5088dd783421456c298b5fcc741c45acbea0 (diff)
downloadexternal_llvm-eb883af3903286ac20f5bbf549c555c9ef961e14.zip
external_llvm-eb883af3903286ac20f5bbf549c555c9ef961e14.tar.gz
external_llvm-eb883af3903286ac20f5bbf549c555c9ef961e14.tar.bz2
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
-rw-r--r--include/llvm/CodeGen/MachOWriter.h600
-rw-r--r--lib/CodeGen/MachOWriter.cpp428
-rw-r--r--lib/Target/PowerPC/PPC.h9
-rw-r--r--lib/Target/PowerPC/PPCCodeEmitter.cpp56
-rw-r--r--lib/Target/PowerPC/PPCMachOWriter.cpp41
-rw-r--r--lib/Target/PowerPC/PPCTargetMachine.cpp26
-rw-r--r--lib/Target/X86/X86TargetMachine.cpp2
-rw-r--r--tools/llc/llc.cpp3
8 files changed, 1118 insertions, 47 deletions
diff --git a/include/llvm/CodeGen/MachOWriter.h b/include/llvm/CodeGen/MachOWriter.h
new file mode 100644
index 0000000..37fa005
--- /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 <list>
+
+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<unsigned char> 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 <mach/machine.h>
+ 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 <mach/machine.h>
+ 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 <mach-o/loader.h> 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 <mach/shared_memory_server.h>
+ 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 <mach-o/vm_prot.h>
+ 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 <mach-o/loader.h>
+ 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 <mach-o/loader.h>
+ 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 <mach-o/loader.h>
+ 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 &sect)
+ : 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<MachOSection> SectionList;
+
+ /// SectionLookup - This is a mapping from section name to SectionList entry
+ std::map<std::string, MachOSection*> 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 &sect,
+ 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 <mach-o/loader.h>
+ 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 <mach-o/loader.h>
+ 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 <mach-o/stab.h>
+ uint64_t n_value; // value for this symbol (or stab offset)
+
+ // Constants for the n_sect field
+ // see <mach-o/nlist.h>
+ enum { NO_SECT = 0 }; // symbol is not in any section
+
+ // Constants for the n_type field
+ // see <mach-o/nlist.h>
+ 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 <mach-o/loader.h>
+ 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<MachOSym> SymbolTable;
+
+ /// DynamicSymbolTable - This is just a vector of indices into
+ /// SymbolTable to aid in emitting the DYSYMTAB load command.
+ std::vector<unsigned> DynamicSymbolTable;
+
+ /// StringTable - The table of strings referenced by SymbolTable entries
+ std::vector<std::string> 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 0000000..e3228cb
--- /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 <iostream>
+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<MachineRelocation> 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<intptr_t> 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<MachOSection>::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<MachOSection>::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<MachOSection>::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<MachOSym>::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<std::string>::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 5e8e15c..f34b9b0 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 49d3f25..85697f9 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 <iostream>
@@ -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 0000000..29f8238
--- /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 deb479a..e360f37 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 90175ac..9616dc1 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 93391e9..3ec213b 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()