X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FMachOWriter.cpp;h=92b3eb4311c348c4b72115baaf5aa827446236a6;hb=420cdebbcb95f3881ab3518fd3bb670837669e43;hp=d4addf2a382856b308f38ca2c3eb8617310543c7;hpb=47857812e29324a9d1560796a05b53d3a9217fd9;p=oota-llvm.git diff --git a/lib/CodeGen/MachOWriter.cpp b/lib/CodeGen/MachOWriter.cpp index d4addf2a382..92b3eb4311c 100644 --- a/lib/CodeGen/MachOWriter.cpp +++ b/lib/CodeGen/MachOWriter.cpp @@ -2,8 +2,8 @@ // // 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 is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -22,23 +22,34 @@ // //===----------------------------------------------------------------------===// +#include "MachOWriter.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/FileWriters.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" -#include "llvm/CodeGen/MachOWriter.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetJITInfo.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/OutputBuffer.h" #include "llvm/Support/Streams.h" #include - using namespace llvm; +/// AddMachOWriter - Concrete function to add the Mach-O writer to the function +/// pass manager. +MachineCodeEmitter *llvm::AddMachOWriter(FunctionPassManager &FPM, + std::ostream &O, + TargetMachine &TM) { + MachOWriter *MOW = new MachOWriter(O, TM); + FPM.add(MOW); + return &MOW->getMachineCodeEmitter(); +} + //===----------------------------------------------------------------------===// // MachOCodeEmitter Implementation //===----------------------------------------------------------------------===// @@ -49,6 +60,13 @@ namespace llvm { class MachOCodeEmitter : public MachineCodeEmitter { MachOWriter &MOW; + /// Target machine description. + TargetMachine &TM; + + /// is64Bit/isLittleEndian - This information is inferred from the target + /// machine directly, indicating what header values and flags to set. + bool is64Bit, isLittleEndian; + /// Relocations - These are the relocations that the function needs, as /// emitted. std::vector Relocations; @@ -71,10 +89,13 @@ namespace llvm { std::vector MBBLocations; public: - MachOCodeEmitter(MachOWriter &mow) : MOW(mow) {} + MachOCodeEmitter(MachOWriter &mow) : MOW(mow), TM(MOW.TM) { + is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; + isLittleEndian = TM.getTargetData()->isLittleEndian(); + } - virtual void startFunction(MachineFunction &F); - virtual bool finishFunction(MachineFunction &F); + virtual void startFunction(MachineFunction &MF); + virtual bool finishFunction(MachineFunction &MF); virtual void addRelocation(const MachineRelocation &MR) { Relocations.push_back(MR); @@ -104,6 +125,20 @@ namespace llvm { return MBBLocations[MBB->getNumber()]; } + virtual intptr_t getLabelAddress(uint64_t Label) const { + assert(0 && "get Label not implemented"); + abort(); + return 0; + } + + virtual void emitLabel(uint64_t LabelID) { + assert(0 && "emit Label not implemented"); + abort(); + } + + + virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) { } + /// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE! virtual void startFunctionStub(unsigned StubSize, unsigned Alignment = 1) { assert(0 && "JIT specific function called!"); @@ -119,12 +154,15 @@ namespace llvm { /// startFunction - This callback is invoked when a new machine function is /// about to be emitted. -void MachOCodeEmitter::startFunction(MachineFunction &F) { +void MachOCodeEmitter::startFunction(MachineFunction &MF) { + const TargetData *TD = TM.getTargetData(); + const Function *F = MF.getFunction(); + // Align the output buffer to the appropriate alignment, power of 2. - // FIXME: MachineFunction or TargetData should probably carry an alignment - // field for functions that we can query here instead of hard coding 4 in both - // the object writer and asm printer. - unsigned Align = 4; + unsigned FnAlign = F->getAlignment(); + unsigned TDAlign = TD->getPrefTypeAlignment(F->getType()); + unsigned Align = Log2_32(std::max(FnAlign, TDAlign)); + assert(!(Align & (Align-1)) && "Alignment is not a power of two!"); // Get the Mach-O Section that this function belongs in. MachOWriter::MachOSection *MOS = MOW.getTextSection(); @@ -134,6 +172,15 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { BufferBegin = &MOS->SectionData[0]; BufferEnd = BufferBegin + MOS->SectionData.capacity(); + // Upgrade the section alignment if required. + if (MOS->align < Align) MOS->align = Align; + + // Round the size up to the correct alignment for starting the new function. + if ((MOS->size & ((1 << Align) - 1)) != 0) { + MOS->size += (1 << Align); + MOS->size &= ~((1 << Align) - 1); + } + // FIXME: Using MOS->size directly here instead of calculating it from the // output buffer size (impossible because the code emitter deals only in raw // bytes) forces us to manually synchronize size and write padding zero bytes @@ -143,9 +190,6 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { // AddSymbolToSection to prevent calling it on the text section. CurBufferPtr = BufferBegin + MOS->size; - // Upgrade the section alignment if required. - if (MOS->align < Align) MOS->align = Align; - // Clear per-function data structures. CPLocations.clear(); CPSections.clear(); @@ -155,21 +199,24 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { /// finishFunction - This callback is invoked after the function is completely /// finished. -bool MachOCodeEmitter::finishFunction(MachineFunction &F) { +bool MachOCodeEmitter::finishFunction(MachineFunction &MF) { // Get the Mach-O Section that this function belongs in. MachOWriter::MachOSection *MOS = MOW.getTextSection(); - MOS->size += CurBufferPtr - BufferBegin; - // Get a symbol for the function to add to the symbol table - const GlobalValue *FuncV = F.getFunction(); - MachOSym FnSym(FuncV, MOW.Mang->getValueName(FuncV), MOS->Index, MOW.TM); - + // FIXME: it seems like we should call something like AddSymbolToSection + // in startFunction rather than changing the section size and symbol n_value + // here. + const GlobalValue *FuncV = MF.getFunction(); + MachOSym FnSym(FuncV, MOW.Mang->getValueName(FuncV), MOS->Index, TM); + FnSym.n_value = MOS->size; + MOS->size = CurBufferPtr - BufferBegin; + // Emit constant pool to appropriate section(s) - emitConstantPool(F.getConstantPool()); + emitConstantPool(MF.getConstantPool()); // Emit jump tables to appropriate section - emitJumpTables(F.getJumpTableInfo()); + emitJumpTables(MF.getJumpTableInfo()); // If we have emitted any relocations to function-specific objects such as // basic blocks, constant pools entries, or jump tables, record their @@ -191,7 +238,10 @@ bool MachOCodeEmitter::finishFunction(MachineFunction &F) { Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex()); MR.setConstantVal(CPSections[MR.getConstantPoolIndex()]); MR.setResultPointer((void*)Addr); - } else if (!MR.isGlobalValue()) { + } else if (MR.isGlobalValue()) { + // FIXME: This should be a set or something that uniques + MOW.PendingGlobals.push_back(MR.getGlobalValue()); + } else { assert(0 && "Unhandled relocation type"); } MOS->Relocations.push_back(MR); @@ -211,7 +261,7 @@ void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { if (CP.empty()) return; // FIXME: handle PIC codegen - bool isPIC = MOW.TM.getRelocationModel() == Reloc::PIC_; + bool isPIC = TM.getRelocationModel() == Reloc::PIC_; assert(!isPIC && "PIC codegen not yet handled for mach-o jump tables!"); // Although there is no strict necessity that I am aware of, we will do what @@ -223,9 +273,11 @@ void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { // "giant object for PIC" optimization. for (unsigned i = 0, e = CP.size(); i != e; ++i) { const Type *Ty = CP[i].getType(); - unsigned Size = MOW.TM.getTargetData()->getTypeSize(Ty); + unsigned Size = TM.getTargetData()->getABITypeSize(Ty); + + MachOWriter::MachOSection *Sec = MOW.getConstSection(CP[i].Val.ConstVal); + OutputBuffer SecDataOut(Sec->SectionData, is64Bit, isLittleEndian); - MachOWriter::MachOSection *Sec = MOW.getConstSection(Ty); CPLocations.push_back(Sec->SectionData.size()); CPSections.push_back(Sec->Index); @@ -236,10 +288,10 @@ void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { // FIXME: need alignment? // FIXME: share between here and AddSymbolToSection? for (unsigned j = 0; j < Size; ++j) - MOW.outbyte(Sec->SectionData, 0); + SecDataOut.outbyte(0); MOW.InitMem(CP[i].Val.ConstVal, &Sec->SectionData[0], CPLocations[i], - MOW.TM.getTargetData(), Sec->Relocations); + TM.getTargetData(), Sec->Relocations); } } @@ -250,11 +302,12 @@ void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { if (JT.empty()) return; // FIXME: handle PIC codegen - bool isPIC = MOW.TM.getRelocationModel() == Reloc::PIC_; + bool isPIC = TM.getRelocationModel() == Reloc::PIC_; assert(!isPIC && "PIC codegen not yet handled for mach-o jump tables!"); MachOWriter::MachOSection *Sec = MOW.getJumpTableSection(); unsigned TextSecIndex = MOW.getTextSection()->Index; + OutputBuffer SecDataOut(Sec->SectionData, is64Bit, isLittleEndian); for (unsigned i = 0, e = JT.size(); i != e; ++i) { // For each jump table, record its offset from the start of the section, @@ -267,7 +320,7 @@ void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { MR.setResultPointer((void *)JTLocations[i]); MR.setConstantVal(TextSecIndex); Sec->Relocations.push_back(MR); - MOW.outaddr(Sec->SectionData, 0); + SecDataOut.outaddr(0); } } // FIXME: remove when we have unified size + output buffer @@ -278,7 +331,9 @@ void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { // MachOWriter Implementation //===----------------------------------------------------------------------===// -MachOWriter::MachOWriter(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { +char MachOWriter::ID = 0; +MachOWriter::MachOWriter(std::ostream &o, TargetMachine &tm) + : MachineFunctionPass((intptr_t)&ID), O(o), TM(tm) { is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; isLittleEndian = TM.getTargetData()->isLittleEndian(); @@ -292,16 +347,14 @@ MachOWriter::~MachOWriter() { void MachOWriter::AddSymbolToSection(MachOSection *Sec, GlobalVariable *GV) { const Type *Ty = GV->getType()->getElementType(); - unsigned Size = TM.getTargetData()->getTypeSize(Ty); - unsigned Align = GV->getAlignment(); - if (Align == 0) - Align = TM.getTargetData()->getTypeAlignment(Ty); - - MachOSym Sym(GV, Mang->getValueName(GV), Sec->Index, TM); - + unsigned Size = TM.getTargetData()->getABITypeSize(Ty); + unsigned Align = TM.getTargetData()->getPreferredAlignment(GV); + // Reserve space in the .bss section for this symbol while maintaining the // desired section alignment, which must be at least as much as required by // this symbol. + OutputBuffer SecDataOut(Sec->SectionData, is64Bit, isLittleEndian); + if (Align) { uint64_t OrigSize = Sec->size; Align = Log2_32(Align); @@ -312,14 +365,19 @@ void MachOWriter::AddSymbolToSection(MachOSection *Sec, GlobalVariable *GV) { // FIXME: remove when we have unified size + output buffer unsigned AlignedSize = Sec->size - OrigSize; for (unsigned i = 0; i < AlignedSize; ++i) - outbyte(Sec->SectionData, 0); + SecDataOut.outbyte(0); + } + // Globals without external linkage apparently do not go in the symbol table. + if (GV->getLinkage() != GlobalValue::InternalLinkage) { + MachOSym Sym(GV, Mang->getValueName(GV), Sec->Index, TM); + Sym.n_value = Sec->size; + SymbolTable.push_back(Sym); } + // Record the offset of the symbol, and then allocate space for it. // FIXME: remove when we have unified size + output buffer - Sym.n_value = Sec->size; Sec->size += Size; - SymbolTable.push_back(Sym); - + // Now that we know what section the GlovalVariable is going to be emitted // into, update our mappings. // FIXME: We may also need to update this when outputting non-GlobalVariable @@ -329,12 +387,12 @@ void MachOWriter::AddSymbolToSection(MachOSection *Sec, GlobalVariable *GV) { // Allocate space in the section for the global. for (unsigned i = 0; i < Size; ++i) - outbyte(Sec->SectionData, 0); + SecDataOut.outbyte(0); } void MachOWriter::EmitGlobal(GlobalVariable *GV) { const Type *Ty = GV->getType()->getElementType(); - unsigned Size = TM.getTargetData()->getTypeSize(Ty); + unsigned Size = TM.getTargetData()->getABITypeSize(Ty); bool NoInit = !GV->hasInitializer(); // If this global has a zero initializer, it is part of the .bss or common @@ -348,12 +406,9 @@ void MachOWriter::EmitGlobal(GlobalVariable *GV) { // For undefined (N_UNDF) external (N_EXT) types, n_value is the size in // bytes of the symbol. ExtOrCommonSym.n_value = Size; - // If the symbol is external, we'll put it on a list of symbols whose - // addition to the symbol table is being pended until we find a reference - if (NoInit) - PendingSyms.push_back(ExtOrCommonSym); - else - SymbolTable.push_back(ExtOrCommonSym); + SymbolTable.push_back(ExtOrCommonSym); + // Remember that we've seen this symbol + GVOffset[GV] = Size; return; } // Otherwise, this symbol is part of the .bss section. @@ -365,7 +420,8 @@ void MachOWriter::EmitGlobal(GlobalVariable *GV) { // Scalar read-only data goes in a literal section if the scalar is 4, 8, or // 16 bytes, or a cstring. Other read only data goes into a regular const // section. Read-write data goes in the data section. - MachOSection *Sec = GV->isConstant() ? getConstSection(Ty) : getDataSection(); + MachOSection *Sec = GV->isConstant() ? getConstSection(GV->getInitializer()) : + getDataSection(); AddSymbolToSection(Sec, GV); InitMem(GV->getInitializer(), &Sec->SectionData[0], GVOffset[GV], TM.getTargetData(), Sec->Relocations); @@ -442,15 +498,17 @@ void MachOWriter::EmitHeaderAndLoadCommands() { // 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); + OutputBuffer FHOut(FH, is64Bit, isLittleEndian); + + FHOut.outword(Header.magic); + FHOut.outword(TM.getMachOWriterInfo()->getCPUType()); + FHOut.outword(TM.getMachOWriterInfo()->getCPUSubType()); + FHOut.outword(Header.filetype); + FHOut.outword(Header.ncmds); + FHOut.outword(Header.sizeofcmds); + FHOut.outword(Header.flags); if (is64Bit) - outword(FH, Header.reserved); + FHOut.outword(Header.reserved); // Step #4: Finish filling in the segment load command and write it out for (std::vector::iterator I = SectionList.begin(), @@ -460,17 +518,17 @@ void MachOWriter::EmitHeaderAndLoadCommands() { 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); + FHOut.outword(SEG.cmd); + FHOut.outword(SEG.cmdsize); + FHOut.outstring(SEG.segname, 16); + FHOut.outaddr(SEG.vmaddr); + FHOut.outaddr(SEG.vmsize); + FHOut.outaddr(SEG.fileoff); + FHOut.outaddr(SEG.filesize); + FHOut.outword(SEG.maxprot); + FHOut.outword(SEG.initprot); + FHOut.outword(SEG.nsects); + FHOut.outword(SEG.flags); // Step #5: Finish filling in the fields of the MachOSections uint64_t currentAddr = 0; @@ -484,7 +542,13 @@ void MachOWriter::EmitHeaderAndLoadCommands() { currentAddr += MOS->size; } - // Step #6: Calculate the number of relocations for each section and write out + // Step #6: Emit the symbol table to temporary buffers, so that we know the + // size of the string table when we write the next load command. This also + // sorts and assigns indices to each of the symbols, which is necessary for + // emitting relocations to externally-defined objects. + BufferSymbolAndStringTable(); + + // Step #7: Calculate the number of relocations for each section and write out // the section commands for each section currentAddr += SEG.fileoff; for (std::vector::iterator I = SectionList.begin(), @@ -497,60 +561,56 @@ void MachOWriter::EmitHeaderAndLoadCommands() { currentAddr += MOS->nreloc * 8; // write the finalized section command to the output buffer - outstring(FH, MOS->sectname, 16); - outstring(FH, MOS->segname, 16); - outaddr(FH, MOS->addr); - outaddr(FH, MOS->size); - outword(FH, MOS->offset); - outword(FH, MOS->align); - outword(FH, MOS->reloff); - outword(FH, MOS->nreloc); - outword(FH, MOS->flags); - outword(FH, MOS->reserved1); - outword(FH, MOS->reserved2); + FHOut.outstring(MOS->sectname, 16); + FHOut.outstring(MOS->segname, 16); + FHOut.outaddr(MOS->addr); + FHOut.outaddr(MOS->size); + FHOut.outword(MOS->offset); + FHOut.outword(MOS->align); + FHOut.outword(MOS->reloff); + FHOut.outword(MOS->nreloc); + FHOut.outword(MOS->flags); + FHOut.outword(MOS->reserved1); + FHOut.outword(MOS->reserved2); if (is64Bit) - outword(FH, MOS->reserved3); + FHOut.outword(MOS->reserved3); } - // Step #7: Emit the symbol table to temporary buffers, so that we know the - // size of the string table when we write the next load command. - BufferSymbolAndStringTable(); - // Step #8: Emit LC_SYMTAB/LC_DYSYMTAB load commands SymTab.symoff = currentAddr; SymTab.nsyms = SymbolTable.size(); SymTab.stroff = SymTab.symoff + SymT.size(); SymTab.strsize = StrT.size(); - outword(FH, SymTab.cmd); - outword(FH, SymTab.cmdsize); - outword(FH, SymTab.symoff); - outword(FH, SymTab.nsyms); - outword(FH, SymTab.stroff); - outword(FH, SymTab.strsize); + FHOut.outword(SymTab.cmd); + FHOut.outword(SymTab.cmdsize); + FHOut.outword(SymTab.symoff); + FHOut.outword(SymTab.nsyms); + FHOut.outword(SymTab.stroff); + FHOut.outword(SymTab.strsize); // FIXME: set DySymTab fields appropriately // We should probably just update these in BufferSymbolAndStringTable since // thats where we're partitioning up the different kinds of symbols. - 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); + FHOut.outword(DySymTab.cmd); + FHOut.outword(DySymTab.cmdsize); + FHOut.outword(DySymTab.ilocalsym); + FHOut.outword(DySymTab.nlocalsym); + FHOut.outword(DySymTab.iextdefsym); + FHOut.outword(DySymTab.nextdefsym); + FHOut.outword(DySymTab.iundefsym); + FHOut.outword(DySymTab.nundefsym); + FHOut.outword(DySymTab.tocoff); + FHOut.outword(DySymTab.ntoc); + FHOut.outword(DySymTab.modtaboff); + FHOut.outword(DySymTab.nmodtab); + FHOut.outword(DySymTab.extrefsymoff); + FHOut.outword(DySymTab.nextrefsyms); + FHOut.outword(DySymTab.indirectsymoff); + FHOut.outword(DySymTab.nindirectsyms); + FHOut.outword(DySymTab.extreloff); + FHOut.outword(DySymTab.nextrel); + FHOut.outword(DySymTab.locreloff); + FHOut.outword(DySymTab.nlocrel); O.write((char*)&FH[0], FH.size()); } @@ -590,6 +650,17 @@ void MachOWriter::BufferSymbolAndStringTable() { // 2. defined external symbols (sorted by name) // 3. undefined external symbols (sorted by name) + // Before sorting the symbols, check the PendingGlobals for any undefined + // globals that need to be put in the symbol table. + for (std::vector::iterator I = PendingGlobals.begin(), + E = PendingGlobals.end(); I != E; ++I) { + if (GVOffset[*I] == 0 && GVSection[*I] == 0) { + MachOSym UndfSym(*I, Mang->getValueName(*I), MachOSym::NO_SECT, TM); + SymbolTable.push_back(UndfSym); + GVOffset[*I] = -1; + } + } + // Sort the symbols by name, so that when we partition the symbols by scope // of definition, we won't have to sort by name within each partition. std::sort(SymbolTable.begin(), SymbolTable.end(), MachOSymCmp()); @@ -617,6 +688,7 @@ void MachOWriter::BufferSymbolAndStringTable() { if (PartitionByLocal(*I)) { ++DySymTab.nlocalsym; ++DySymTab.iextdefsym; + ++DySymTab.iundefsym; } else if (PartitionByDefined(*I)) { ++DySymTab.nextdefsym; ++DySymTab.iundefsym; @@ -627,7 +699,8 @@ void MachOWriter::BufferSymbolAndStringTable() { // Write out a leading zero byte when emitting string table, for n_strx == 0 // which means an empty string. - outbyte(StrT, 0); + OutputBuffer StrTOut(StrT, is64Bit, isLittleEndian); + StrTOut.outbyte(0); // The order of the string table is: // 1. strings for external symbols @@ -640,25 +713,30 @@ void MachOWriter::BufferSymbolAndStringTable() { I->n_strx = 0; } else { I->n_strx = StrT.size(); - outstring(StrT, I->GVName, I->GVName.length()+1); + StrTOut.outstring(I->GVName, I->GVName.length()+1); } } + OutputBuffer SymTOut(SymT, is64Bit, isLittleEndian); + + unsigned index = 0; for (std::vector::iterator I = SymbolTable.begin(), - E = SymbolTable.end(); I != E; ++I) { + E = SymbolTable.end(); I != E; ++I, ++index) { // Add the section base address to the section offset in the n_value field // to calculate the full address. // FIXME: handle symbols where the n_value field is not the address GlobalValue *GV = const_cast(I->GV); if (GV && GVSection[GV]) I->n_value += GVSection[GV]->addr; + if (GV && (GVOffset[GV] == -1)) + GVOffset[GV] = index; // Emit nlist to buffer - outword(SymT, I->n_strx); - outbyte(SymT, I->n_type); - outbyte(SymT, I->n_sect); - outhalf(SymT, I->n_desc); - outaddr(SymT, I->n_value); + SymTOut.outword(I->n_strx); + SymTOut.outbyte(I->n_type); + SymTOut.outbyte(I->n_sect); + SymTOut.outhalf(I->n_desc); + SymTOut.outaddr(I->n_value); } } @@ -671,22 +749,49 @@ void MachOWriter::CalculateRelocations(MachOSection &MOS) { for (unsigned i = 0, e = MOS.Relocations.size(); i != e; ++i) { MachineRelocation &MR = MOS.Relocations[i]; unsigned TargetSection = MR.getConstantVal(); - + unsigned TargetAddr = 0; + unsigned TargetIndex = 0; + + // This is a scattered relocation entry if it points to a global value with + // a non-zero offset. + bool Scattered = false; + bool Extern = false; + // Since we may not have seen the GlobalValue we were interested in yet at // the time we emitted the relocation for it, fix it up now so that it // points to the offset into the correct section. if (MR.isGlobalValue()) { GlobalValue *GV = MR.getGlobalValue(); MachOSection *MOSPtr = GVSection[GV]; - intptr_t offset = GVOffset[GV]; + intptr_t Offset = GVOffset[GV]; - assert(MOSPtr && "Trying to relocate unknown global!"); - - TargetSection = MOSPtr->Index; - MR.setResultPointer((void*)offset); + // If we have never seen the global before, it must be to a symbol + // defined in another module (N_UNDF). + if (!MOSPtr) { + // FIXME: need to append stub suffix + Extern = true; + TargetAddr = 0; + TargetIndex = GVOffset[GV]; + } else { + Scattered = TargetSection != 0; + TargetSection = MOSPtr->Index; + } + MR.setResultPointer((void*)Offset); } - GetTargetRelocation(MR, MOS, *SectionList[TargetSection-1]); + // If the symbol is locally defined, pass in the address of the section and + // the section index to the code which will generate the target relocation. + if (!Extern) { + MachOSection &To = *SectionList[TargetSection - 1]; + TargetAddr = To.addr; + TargetIndex = To.Index; + } + + OutputBuffer RelocOut(MOS.RelocBuffer, is64Bit, isLittleEndian); + OutputBuffer SecOut(MOS.SectionData, is64Bit, isLittleEndian); + + MOS.nreloc += GetTargetRelocation(MR, MOS.Index, TargetAddr, TargetIndex, + RelocOut, SecOut, Scattered, Extern); } } @@ -700,6 +805,8 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, WorkList.push_back(CPair(C,(intptr_t)Addr + Offset)); + intptr_t ScatteredOffset = 0; + while (!WorkList.empty()) { const Constant *PC = WorkList.back().first; intptr_t PA = WorkList.back().second; @@ -707,9 +814,9 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, if (isa(PC)) { continue; - } else if (const ConstantPacked *CP = dyn_cast(PC)) { - unsigned ElementSize = - CP->getType()->getElementType()->getPrimitiveSize(); + } else if (const ConstantVector *CP = dyn_cast(PC)) { + unsigned ElementSize = + TD->getABITypeSize(CP->getType()->getElementType()); for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) WorkList.push_back(CPair(CP->getOperand(i), PA+i*ElementSize)); } else if (const ConstantExpr *CE = dyn_cast(PC)) { @@ -717,7 +824,13 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, // FIXME: Handle ConstantExpression. See EE::getConstantValue() // switch (CE->getOpcode()) { - case Instruction::GetElementPtr: + case Instruction::GetElementPtr: { + SmallVector Indices(CE->op_begin()+1, CE->op_end()); + ScatteredOffset = TD->getIndexedOffset(CE->getOperand(0)->getType(), + &Indices[0], Indices.size()); + WorkList.push_back(CPair(CE->getOperand(0), PA)); + break; + } case Instruction::Add: default: cerr << "ConstantExpr not handled as global var init: " << *CE << "\n"; @@ -726,27 +839,43 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, } } else if (PC->getType()->isFirstClassType()) { unsigned char *ptr = (unsigned char *)PA; - uint64_t val; - switch (PC->getType()->getTypeID()) { - case Type::BoolTyID: - case Type::Int8TyID: - ptr[0] = cast(PC)->getZExtValue(); - break; - case Type::Int16TyID: - val = cast(PC)->getZExtValue(); - if (TD->isBigEndian()) - val = ByteSwap_16(val); - ptr[0] = val; - ptr[1] = val >> 8; - break; - case Type::Int32TyID: - case Type::FloatTyID: - if (PC->getType()->getTypeID() == Type::FloatTyID) { - val = FloatToBits(cast(PC)->getValue()); + case Type::IntegerTyID: { + unsigned NumBits = cast(PC->getType())->getBitWidth(); + uint64_t val = cast(PC)->getZExtValue(); + if (NumBits <= 8) + ptr[0] = val; + else if (NumBits <= 16) { + if (TD->isBigEndian()) + val = ByteSwap_16(val); + ptr[0] = val; + ptr[1] = val >> 8; + } else if (NumBits <= 32) { + if (TD->isBigEndian()) + val = ByteSwap_32(val); + ptr[0] = val; + ptr[1] = val >> 8; + ptr[2] = val >> 16; + ptr[3] = val >> 24; + } else if (NumBits <= 64) { + if (TD->isBigEndian()) + val = ByteSwap_64(val); + ptr[0] = val; + ptr[1] = val >> 8; + ptr[2] = val >> 16; + ptr[3] = val >> 24; + ptr[4] = val >> 32; + ptr[5] = val >> 40; + ptr[6] = val >> 48; + ptr[7] = val >> 56; } else { - val = cast(PC)->getZExtValue(); + assert(0 && "Not implemented: bit widths > 64"); } + break; + } + case Type::FloatTyID: { + uint32_t val = cast(PC)->getValueAPF().convertToAPInt(). + getZExtValue(); if (TD->isBigEndian()) val = ByteSwap_32(val); ptr[0] = val; @@ -754,13 +883,10 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, ptr[2] = val >> 16; ptr[3] = val >> 24; break; - case Type::DoubleTyID: - case Type::Int64TyID: - if (PC->getType()->getTypeID() == Type::DoubleTyID) { - val = DoubleToBits(cast(PC)->getValue()); - } else { - val = cast(PC)->getZExtValue(); - } + } + case Type::DoubleTyID: { + uint64_t val = cast(PC)->getValueAPF().convertToAPInt(). + getZExtValue(); if (TD->isBigEndian()) val = ByteSwap_64(val); ptr[0] = val; @@ -772,15 +898,18 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, ptr[6] = val >> 48; ptr[7] = val >> 56; break; + } case Type::PointerTyID: - if (isa(C)) + if (isa(PC)) memset(ptr, 0, TD->getPointerSize()); - else if (const GlobalValue* GV = dyn_cast(C)) + else if (const GlobalValue* GV = dyn_cast(PC)) { // FIXME: what about function stubs? MRs.push_back(MachineRelocation::getGV(PA-(intptr_t)Addr, MachineRelocation::VANILLA, - const_cast(GV))); - else + const_cast(GV), + ScatteredOffset)); + ScatteredOffset = 0; + } else assert(0 && "Unknown constant pointer type!"); break; default: @@ -788,17 +917,18 @@ void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, abort(); } } else if (isa(PC)) { - memset((void*)PA, 0, (size_t)TD->getTypeSize(PC->getType())); + memset((void*)PA, 0, (size_t)TD->getABITypeSize(PC->getType())); } else if (const ConstantArray *CPA = dyn_cast(PC)) { - unsigned ElementSize = - CPA->getType()->getElementType()->getPrimitiveSize(); + unsigned ElementSize = + TD->getABITypeSize(CPA->getType()->getElementType()); for (unsigned i = 0, e = CPA->getNumOperands(); i != e; ++i) WorkList.push_back(CPair(CPA->getOperand(i), PA+i*ElementSize)); } else if (const ConstantStruct *CPS = dyn_cast(PC)) { const StructLayout *SL = TD->getStructLayout(cast(CPS->getType())); for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) - WorkList.push_back(CPair(CPS->getOperand(i), PA+SL->MemberOffsets[i])); + WorkList.push_back(CPair(CPS->getOperand(i), + PA+SL->getElementOffset(i))); } else { cerr << "Bad Type: " << *PC->getType() << "\n"; assert(0 && "Unknown constant type to initialize memory with!"); @@ -822,10 +952,10 @@ MachOSym::MachOSym(const GlobalValue *gv, std::string name, uint8_t sect, assert(!isa(gv) && "Unexpected linkage type for Function!"); case GlobalValue::ExternalLinkage: GVName = TAI->getGlobalPrefix() + name; - n_type |= N_EXT; + n_type |= GV->hasHiddenVisibility() ? N_PEXT : N_EXT; break; case GlobalValue::InternalLinkage: - GVName = TAI->getPrivateGlobalPrefix() + name; + GVName = TAI->getGlobalPrefix() + name; break; } }