diff options
author | Nate Begeman <natebegeman@mac.com> | 2006-12-11 02:20:45 +0000 |
---|---|---|
committer | Nate Begeman <natebegeman@mac.com> | 2006-12-11 02:20:45 +0000 |
commit | bfaaaa6e0f105cc57933afa9a380763fe87a5ff3 (patch) | |
tree | 494b4bd3bac7c029637631aa0dce61cfeaa195c8 /lib/CodeGen/MachOWriter.cpp | |
parent | 5381baa051562f0ec14ffa97072c0a9adfe87bf0 (diff) |
Properly mangles symbol table names
Supports constant pools
Supports relocations to jump tables
Supports relocations within the data segment (global = address of global)
Allocates memory in a non-hacky for all non-code objects.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@32430 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/MachOWriter.cpp')
-rw-r--r-- | lib/CodeGen/MachOWriter.cpp | 445 |
1 files changed, 333 insertions, 112 deletions
diff --git a/lib/CodeGen/MachOWriter.cpp b/lib/CodeGen/MachOWriter.cpp index 390676973f..924ef91642 100644 --- a/lib/CodeGen/MachOWriter.cpp +++ b/lib/CodeGen/MachOWriter.cpp @@ -22,16 +22,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" #include "llvm/Module.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/Streams.h" #include <algorithm> + using namespace llvm; //===----------------------------------------------------------------------===// @@ -43,9 +48,6 @@ namespace llvm { /// 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. @@ -55,6 +57,10 @@ namespace llvm { /// start of the section for that constant pool index. std::vector<intptr_t> CPLocations; + /// CPSections - This is a map of constant pool indices to the MachOSection + /// containing the constant pool entry for that index. + std::vector<unsigned> CPSections; + /// JTLocations - This is a map of jump table indices to offsets from the /// start of the section for that jump table index. std::vector<intptr_t> JTLocations; @@ -67,10 +73,10 @@ namespace llvm { public: MachOCodeEmitter(MachOWriter &mow) : MOW(mow) {} - void startFunction(MachineFunction &F); - bool finishFunction(MachineFunction &F); + virtual void startFunction(MachineFunction &F); + virtual bool finishFunction(MachineFunction &F); - void addRelocation(const MachineRelocation &MR) { + virtual void addRelocation(const MachineRelocation &MR) { Relocations.push_back(MR); } @@ -78,8 +84,8 @@ namespace llvm { void emitJumpTables(MachineJumpTableInfo *MJTI); virtual intptr_t getConstantPoolEntryAddress(unsigned Index) const { - assert(0 && "CP not implementated yet!"); - return 0; + assert(CPLocations.size() > Index && "CP not emitted!"); + return CPLocations[Index]; } virtual intptr_t getJumpTableEntryAddress(unsigned Index) const { assert(JTLocations.size() > Index && "JT not emitted!"); @@ -99,11 +105,11 @@ namespace llvm { } /// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE! - void startFunctionStub(unsigned StubSize, unsigned Alignment = 1) { + virtual void startFunctionStub(unsigned StubSize, unsigned Alignment = 1) { assert(0 && "JIT specific function called!"); abort(); } - void *finishFunctionStub(const Function *F) { + virtual void *finishFunctionStub(const Function *F) { assert(0 && "JIT specific function called!"); abort(); return 0; @@ -115,16 +121,26 @@ namespace llvm { /// about to be emitted. void MachOCodeEmitter::startFunction(MachineFunction &F) { // Align the output buffer to the appropriate alignment, power of 2. - // FIXME: GENERICIZE!! + // 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; // Get the Mach-O Section that this function belongs in. - MOS = &MOW.getTextSection(); + MachOWriter::MachOSection *MOS = MOW.getTextSection(); - // FIXME: better memory management + // FIXME: better memory management MOS->SectionData.reserve(4096); - BufferBegin = &(MOS->SectionData[0]); + BufferBegin = &MOS->SectionData[0]; BufferEnd = BufferBegin + MOS->SectionData.capacity(); + + // 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 + // to the output buffer for all non-text sections. For text sections, we do + // not synchonize the output buffer, and we just blow up if anyone tries to + // write non-code to it. An assert should probably be added to + // AddSymbolToSection to prevent calling it on the text section. CurBufferPtr = BufferBegin + MOS->size; // Upgrade the section alignment if required. @@ -132,6 +148,7 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { // Clear per-function data structures. CPLocations.clear(); + CPSections.clear(); JTLocations.clear(); MBBLocations.clear(); } @@ -139,11 +156,14 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { /// finishFunction - This callback is invoked after the function is completely /// finished. bool MachOCodeEmitter::finishFunction(MachineFunction &F) { + // 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); + MachOSym FnSym(FuncV, MOW.Mang->getValueName(FuncV), MOS->Index, MOW.TM); // Emit constant pool to appropriate section(s) emitConstantPool(F.getConstantPool()); @@ -158,16 +178,21 @@ bool MachOCodeEmitter::finishFunction(MachineFunction &F) { for (unsigned i = 0, e = Relocations.size(); i != e; ++i) { MachineRelocation &MR = Relocations[i]; intptr_t Addr; + if (MR.isBasicBlock()) { Addr = getMachineBasicBlockAddress(MR.getBasicBlock()); - MR.setResultPointer((void *)Addr); - } else if (MR.isConstantPoolIndex()) { - Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex()); - MR.setResultPointer((void *)Addr); + MR.setConstantVal(MOS->Index); + MR.setResultPointer((void*)Addr); } else if (MR.isJumpTableIndex()) { - // FIXME: handle PIC codegen Addr = getJumpTableEntryAddress(MR.getJumpTableIndex()); - MR.setResultPointer((void *)Addr); + MR.setConstantVal(MOW.getJumpTableSection()->Index); + MR.setResultPointer((void*)Addr); + } else if (MR.isConstantPoolIndex()) { + Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex()); + MR.setConstantVal(CPSections[MR.getConstantPoolIndex()]); + MR.setResultPointer((void*)Addr); + } else if (!MR.isGlobalValue()) { + assert(0 && "Unhandled relocation type"); } MOS->Relocations.push_back(MR); } @@ -182,6 +207,40 @@ bool MachOCodeEmitter::finishFunction(MachineFunction &F) { /// the constant should live in, allocate space for it, and emit it to the /// Section data buffer. void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { + const std::vector<MachineConstantPoolEntry> &CP = MCP->getConstants(); + if (CP.empty()) return; + + // FIXME: handle PIC codegen + bool isPIC = MOW.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 + // gcc for OS X does and put each constant pool entry in a section of constant + // objects of a certain size. That means that float constants go in the + // literal4 section, and double objects go in literal8, etc. + // + // FIXME: revisit this decision if we ever do the "stick everything into one + // "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); + + MachOWriter::MachOSection *Sec = MOW.getConstSection(Ty); + CPLocations.push_back(Sec->SectionData.size()); + CPSections.push_back(Sec->Index); + + // FIXME: remove when we have unified size + output buffer + Sec->size += Size; + + // Allocate space in the section for the global. + // FIXME: need alignment? + // FIXME: share between here and AddSymbolToSection? + for (unsigned j = 0; j < Size; ++j) + MOW.outbyte(Sec->SectionData, 0); + + MOW.InitMem(CP[i].Val.ConstVal, &Sec->SectionData[0], CPLocations[i], + MOW.TM.getTargetData(), Sec->Relocations); + } } /// emitJumpTables - Emit all the jump tables for a given jump table info @@ -190,28 +249,29 @@ void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); if (JT.empty()) return; + // FIXME: handle PIC codegen bool isPIC = MOW.TM.getRelocationModel() == Reloc::PIC_; assert(!isPIC && "PIC codegen not yet handled for mach-o jump tables!"); - MachOWriter::MachOSection &Sec = MOW.getJumpTableSection(); + MachOWriter::MachOSection *Sec = MOW.getJumpTableSection(); + unsigned TextSecIndex = MOW.getTextSection()->Index; for (unsigned i = 0, e = JT.size(); i != e; ++i) { // For each jump table, record its offset from the start of the section, // reserve space for the relocations to the MBBs, and add the relocations. const std::vector<MachineBasicBlock*> &MBBs = JT[i].MBBs; - JTLocations.push_back(Sec.SectionData.size()); + JTLocations.push_back(Sec->SectionData.size()); for (unsigned mi = 0, me = MBBs.size(); mi != me; ++mi) { - MachineRelocation MR(MOW.GetJTRelocation(Sec.SectionData.size(), + MachineRelocation MR(MOW.GetJTRelocation(Sec->SectionData.size(), MBBs[mi])); MR.setResultPointer((void *)JTLocations[i]); - Sec.Relocations.push_back(MR); - MOW.outaddr(Sec.SectionData, 0); + MR.setConstantVal(TextSecIndex); + Sec->Relocations.push_back(MR); + MOW.outaddr(Sec->SectionData, 0); } } - // FIXME: it really seems like keeping these in sync is redundant, someone - // should do something about that (never access section size directly, only - // look at buffer size). - Sec.size = Sec.SectionData.size(); + // FIXME: remove when we have unified size + output buffer + Sec->size = Sec->SectionData.size(); } //===----------------------------------------------------------------------===// @@ -230,33 +290,46 @@ MachOWriter::~MachOWriter() { delete MCE; } -void MachOWriter::AddSymbolToSection(MachOSection &Sec, GlobalVariable *GV) { +void MachOWriter::AddSymbolToSection(MachOSection *Sec, GlobalVariable *GV) { const Type *Ty = GV->getType()->getElementType(); unsigned Size = TM.getTargetData()->getTypeSize(Ty); - unsigned Align = Log2_32(TM.getTargetData()->getTypeAlignment(Ty)); + unsigned Align = GV->getAlignment(); + if (Align == 0) + Align = TM.getTargetData()->getTypeAlignment(Ty); + + MachOSym Sym(GV, Mang->getValueName(GV), Sec->Index, TM); - MachOSym Sym(GV, Mang->getValueName(GV), Sec.Index); // 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. if (Align) { - Sec.align = std::max(unsigned(Sec.align), Align); - Sec.size = (Sec.size + Align - 1) & ~(Align-1); + uint64_t OrigSize = Sec->size; + Align = Log2_32(Align); + Sec->align = std::max(unsigned(Sec->align), Align); + Sec->size = (Sec->size + Align - 1) & ~(Align-1); + + // Add alignment padding to buffer as well. + // 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); } // Record the offset of the symbol, and then allocate space for it. - Sym.n_value = Sec.size; - Sec.size += Size; - - switch (GV->getLinkage()) { - default: // weak/linkonce handled above - assert(0 && "Unexpected linkage type!"); - case GlobalValue::ExternalLinkage: - Sym.n_type |= MachOSym::N_EXT; - break; - case GlobalValue::InternalLinkage: - break; - } + // 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 + // GlobalValues such as functions. + GVSection[GV] = Sec; + GVOffset[GV] = Sec->SectionData.size(); + + // Allocate space in the section for the global. + for (unsigned i = 0; i < Size; ++i) + outbyte(Sec->SectionData, 0); } void MachOWriter::EmitGlobal(GlobalVariable *GV) { @@ -271,7 +344,7 @@ void MachOWriter::EmitGlobal(GlobalVariable *GV) { // part of the common block if they are zero initialized and allowed to be // merged with other symbols. if (NoInit || GV->hasLinkOnceLinkage() || GV->hasWeakLinkage()) { - MachOSym ExtOrCommonSym(GV, Mang->getValueName(GV), MachOSym::NO_SECT); + MachOSym ExtOrCommonSym(GV, Mang->getValueName(GV), MachOSym::NO_SECT,TM); // For undefined (N_UNDF) external (N_EXT) types, n_value is the size in // bytes of the symbol. ExtOrCommonSym.n_value = Size; @@ -284,7 +357,7 @@ void MachOWriter::EmitGlobal(GlobalVariable *GV) { return; } // Otherwise, this symbol is part of the .bss section. - MachOSection &BSS = getBSSSection(); + MachOSection *BSS = getBSSSection(); AddSymbolToSection(BSS, GV); return; } @@ -292,23 +365,10 @@ 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(Ty) : getDataSection(); AddSymbolToSection(Sec, GV); - - // FIXME: A couple significant changes are required for this to work, even for - // trivial cases such as a constant integer: - // 0. InitializeMemory needs to be split out of ExecutionEngine. We don't - // want to have to create an ExecutionEngine such as JIT just to write - // some bytes into a buffer. The only thing necessary for - // InitializeMemory to function properly should be TargetData. - // - // 1. InitializeMemory needs to be enhanced to return MachineRelocations - // rather than accessing the address of objects such basic blocks, - // constant pools, and jump tables. The client of InitializeMemory such - // as an object writer or jit emitter should then handle these relocs - // appropriately. - // - // FIXME: need to allocate memory for the global initializer. + InitMem(GV->getInitializer(), &Sec->SectionData[0], GVOffset[GV], + TM.getTargetData(), Sec->Relocations); } @@ -341,10 +401,6 @@ bool MachOWriter::doFinalization(Module &M) { I != E; ++I) EmitGlobal(I); - // Emit the symbol table to temporary buffers, so that we know the size of - // the string table when we write the load commands in the next phase. - BufferSymbolAndStringTable(); - // Emit the header and load commands. EmitHeaderAndLoadCommands(); @@ -371,7 +427,7 @@ void MachOWriter::EmitHeaderAndLoadCommands() { MachOSegment SEG("", is64Bit); SEG.nsects = SectionList.size(); SEG.cmdsize = SEG.cmdSize(is64Bit) + - SEG.nsects * SectionList.begin()->cmdSize(is64Bit); + SEG.nsects * SectionList[0]->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 @@ -397,9 +453,10 @@ void MachOWriter::EmitHeaderAndLoadCommands() { 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(), + for (std::vector<MachOSection*>::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) - SEG.filesize += I->size; + SEG.filesize += (*I)->size; + SEG.vmsize = SEG.filesize; SEG.fileoff = Header.cmdSize(is64Bit) + Header.sizeofcmds; @@ -417,42 +474,49 @@ void MachOWriter::EmitHeaderAndLoadCommands() { // Step #5: Finish filling in the fields of the MachOSections uint64_t currentAddr = 0; - for (std::list<MachOSection>::iterator I = SectionList.begin(), + for (std::vector<MachOSection*>::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) { - I->addr = currentAddr; - I->offset = currentAddr + SEG.fileoff; + MachOSection *MOS = *I; + MOS->addr = currentAddr; + MOS->offset = currentAddr + SEG.fileoff; // FIXME: do we need to do something with alignment here? - currentAddr += I->size; + currentAddr += MOS->size; } // Step #6: Calculate the number of relocations for each section and write out // the section commands for each section currentAddr += SEG.fileoff; - for (std::list<MachOSection>::iterator I = SectionList.begin(), + for (std::vector<MachOSection*>::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) { - // calculate the relocation info for this section command - CalculateRelocations(*I, currentAddr); - currentAddr += I->nreloc * 8; + MachOSection *MOS = *I; + // Convert the relocations to target-specific relocations, and fill in the + // relocation offset for this section. + CalculateRelocations(*MOS); + MOS->reloff = MOS->nreloc ? currentAddr : 0; + currentAddr += MOS->nreloc * 8; // write the finalized section command to the output buffer - 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); + 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); if (is64Bit) - outword(FH, I->reserved3); + outword(FH, MOS->reserved3); } - // Step #7: Emit LC_SYMTAB/LC_DYSYMTAB load commands - // FIXME: add size of relocs + // 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(); @@ -494,20 +558,19 @@ void MachOWriter::EmitHeaderAndLoadCommands() { /// 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(), + for (std::vector<MachOSection*>::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) // Emit the contents of each section - O.write((char*)&I->SectionData[0], I->size); - for (std::list<MachOSection>::iterator I = SectionList.begin(), + O.write((char*)&(*I)->SectionData[0], (*I)->size); + for (std::vector<MachOSection*>::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) // Emit the relocation entry data for each section. - O.write((char*)&I->RelocBuffer[0], I->RelocBuffer.size()); + O.write((char*)&(*I)->RelocBuffer[0], (*I)->RelocBuffer.size()); } /// PartitionByLocal - Simple boolean predicate that returns true if Sym is /// a local symbol rather than an external symbol. bool MachOWriter::PartitionByLocal(const MachOSym &Sym) { - // FIXME: Not totally sure if private extern counts as external return (Sym.n_type & (MachOSym::N_EXT | MachOSym::N_PEXT)) == 0; } @@ -545,6 +608,22 @@ void MachOWriter::BufferSymbolAndStringTable() { break; } } + + // Calculate the starting index for each of the local, extern defined, and + // undefined symbols, as well as the number of each to put in the LC_DYSYMTAB + // load command. + for (std::vector<MachOSym>::iterator I = SymbolTable.begin(), + E = SymbolTable.end(); I != E; ++I) { + if (PartitionByLocal(*I)) { + ++DySymTab.nlocalsym; + ++DySymTab.iextdefsym; + } else if (PartitionByDefined(*I)) { + ++DySymTab.nextdefsym; + ++DySymTab.iundefsym; + } else { + ++DySymTab.nundefsym; + } + } // Write out a leading zero byte when emitting string table, for n_strx == 0 // which means an empty string. @@ -567,6 +646,13 @@ void MachOWriter::BufferSymbolAndStringTable() { for (std::vector<MachOSym>::iterator I = SymbolTable.begin(), E = SymbolTable.end(); I != E; ++I) { + // 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<GlobalValue*>(I->GV); + if (GV && GVSection[GV]) + I->n_value += GVSection[GV]->addr; + // Emit nlist to buffer outword(SymT, I->n_strx); outbyte(SymT, I->n_type); @@ -581,23 +667,156 @@ void MachOWriter::BufferSymbolAndStringTable() { /// and the offset into that section. From this information, create the /// appropriate target-specific MachORelocation type and add buffer it to be /// written out after we are finished writing out sections. -void MachOWriter::CalculateRelocations(MachOSection &MOS, unsigned RelOffset) { +void MachOWriter::CalculateRelocations(MachOSection &MOS) { for (unsigned i = 0, e = MOS.Relocations.size(); i != e; ++i) { - // FIXME: calculate the correct offset and section index for relocated - // object. - // FIXME: somehow convey the fact that the relocation might be external - // to the relocating code. - GetTargetRelocation(MOS.Relocations[i], MOS, MOS.Index); + MachineRelocation &MR = MOS.Relocations[i]; + unsigned TargetSection = MR.getConstantVal(); + + // 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]; + + assert(MOSPtr && "Trying to relocate unknown global!"); + + TargetSection = MOSPtr->Index; + MR.setResultPointer((void*)offset); + } + + GetTargetRelocation(MR, MOS, *SectionList[TargetSection-1]); } - if (MOS.nreloc != 0) - MOS.reloff = RelOffset; } -MachOSym::MachOSym(const GlobalValue *gv, std::string name, uint8_t sect) : - GV(gv), GVName(name), n_strx(0), n_type(sect == NO_SECT ? N_UNDF : N_SECT), - n_sect(sect), n_desc(0), n_value(0) { - // FIXME: take a target machine, and then add the appropriate prefix for - // the linkage type based on the TargetAsmInfo +// InitMem - Write the value of a Constant to the specified memory location, +// converting it into bytes and relocations. +void MachOWriter::InitMem(const Constant *C, void *Addr, intptr_t Offset, + const TargetData *TD, + std::vector<MachineRelocation> &MRs) { + typedef std::pair<const Constant*, intptr_t> CPair; + std::vector<CPair> WorkList; + + WorkList.push_back(CPair(C,(intptr_t)Addr + Offset)); + + while (!WorkList.empty()) { + const Constant *PC = WorkList.back().first; + intptr_t PA = WorkList.back().second; + WorkList.pop_back(); + + if (isa<UndefValue>(PC)) { + continue; + } else if (const ConstantPacked *CP = dyn_cast<ConstantPacked>(PC)) { + unsigned ElementSize = + CP->getType()->getElementType()->getPrimitiveSize(); + 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<ConstantExpr>(PC)) { + // + // FIXME: Handle ConstantExpression. See EE::getConstantValue() + // + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: + case Instruction::Add: + default: + cerr << "ConstantExpr not handled as global var init: " << *CE << "\n"; + abort(); + break; + } + } else if (PC->getType()->isFirstClassType()) { + unsigned char *ptr = (unsigned char *)PA; + uint64_t val; + + switch (PC->getType()->getTypeID()) { + case Type::BoolTyID: + case Type::UByteTyID: + case Type::SByteTyID: + ptr[0] = cast<ConstantInt>(PC)->getZExtValue(); + break; + case Type::UShortTyID: + case Type::ShortTyID: + val = cast<ConstantInt>(PC)->getZExtValue(); + if (TD->isBigEndian()) + val = ByteSwap_16(val); + ptr[0] = val; + ptr[1] = val >> 8; + break; + case Type::UIntTyID: + case Type::IntTyID: + case Type::FloatTyID: + if (PC->getType()->getTypeID() == Type::FloatTyID) { + val = FloatToBits(cast<ConstantFP>(PC)->getValue()); + } else { + val = cast<ConstantInt>(PC)->getZExtValue(); + } + if (TD->isBigEndian()) + val = ByteSwap_32(val); + ptr[0] = val; + ptr[1] = val >> 8; + ptr[2] = val >> 16; + ptr[3] = val >> 24; + break; + case Type::DoubleTyID: + case Type::ULongTyID: + case Type::LongTyID: + if (PC->getType()->getTypeID() == Type::DoubleTyID) { + val = DoubleToBits(cast<ConstantFP>(PC)->getValue()); + } else { + val = cast<ConstantInt>(PC)->getZExtValue(); + } + 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; + break; + case Type::PointerTyID: + if (isa<ConstantPointerNull>(C)) + memset(ptr, 0, TD->getPointerSize()); + else if (const GlobalValue* GV = dyn_cast<GlobalValue>(C)) + // FIXME: what about function stubs? + MRs.push_back(MachineRelocation::getGV(PA-(intptr_t)Addr, + MachineRelocation::VANILLA, + const_cast<GlobalValue*>(GV))); + else + assert(0 && "Unknown constant pointer type!"); + break; + default: + cerr << "ERROR: Constant unimp for type: " << *PC->getType() << "\n"; + abort(); + } + } else if (isa<ConstantAggregateZero>(PC)) { + memset((void*)PA, 0, (size_t)TD->getTypeSize(PC->getType())); + } else if (const ConstantArray *CPA = dyn_cast<ConstantArray>(PC)) { + unsigned ElementSize = + CPA->getType()->getElementType()->getPrimitiveSize(); + 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<ConstantStruct>(PC)) { + const StructLayout *SL = + TD->getStructLayout(cast<StructType>(CPS->getType())); + for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) + WorkList.push_back(CPair(CPS->getOperand(i), PA+SL->MemberOffsets[i])); + } else { + cerr << "Bad Type: " << *PC->getType() << "\n"; + assert(0 && "Unknown constant type to initialize memory with!"); + } + } +} + +MachOSym::MachOSym(const GlobalValue *gv, std::string name, uint8_t sect, + TargetMachine &TM) : + GV(gv), n_strx(0), n_type(sect == NO_SECT ? N_UNDF : N_SECT), n_sect(sect), + n_desc(0), n_value(0) { + + const TargetAsmInfo *TAI = TM.getTargetAsmInfo(); + switch (GV->getLinkage()) { default: assert(0 && "Unexpected linkage type!"); @@ -606,9 +825,11 @@ MachOSym::MachOSym(const GlobalValue *gv, std::string name, uint8_t sect) : case GlobalValue::LinkOnceLinkage: assert(!isa<Function>(gv) && "Unexpected linkage type for Function!"); case GlobalValue::ExternalLinkage: + GVName = TAI->getGlobalPrefix() + name; n_type |= N_EXT; break; case GlobalValue::InternalLinkage: + GVName = TAI->getPrivateGlobalPrefix() + name; break; } } |