From 019f851ab26511c089e41b61901f743e75f90714 Mon Sep 17 00:00:00 2001 From: Nate Begeman Date: Sun, 10 Sep 2006 23:03:44 +0000 Subject: [PATCH] Behold, more work on relocations. Things are looking pretty good now. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30240 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/MachOWriter.h | 47 ++++++-- lib/CodeGen/MachOWriter.cpp | 144 ++++++++++++++++++------- lib/ExecutionEngine/JIT/JITEmitter.cpp | 2 +- lib/Target/PowerPC/PPCMachOWriter.cpp | 106 +++++++++++------- lib/Target/PowerPC/PPCRelocations.h | 4 + 5 files changed, 213 insertions(+), 90 deletions(-) diff --git a/include/llvm/CodeGen/MachOWriter.h b/include/llvm/CodeGen/MachOWriter.h index bb20f7bbbcb..a5e3520eaea 100644 --- a/include/llvm/CodeGen/MachOWriter.h +++ b/include/llvm/CodeGen/MachOWriter.h @@ -344,6 +344,10 @@ namespace llvm { /// SectionData - The actual data for this section which we are building /// up for emission to the file. DataBuffer SectionData; + + /// RelocBuffer - A buffer to hold the mach-o relocations before we write + /// them out at the appropriate location in the file. + DataBuffer RelocBuffer; /// Relocations - The relocations that we have encountered so far in this /// section that we will need to convert to MachORelocation entries when @@ -421,7 +425,7 @@ namespace llvm { } MachOSection(const std::string &seg, const std::string §) - : sectname(sect), segname(seg), addr(0), size(0), offset(0), align(0), + : sectname(sect), segname(seg), addr(0), size(0), offset(0), align(2), reloff(0), nreloc(0), flags(0), reserved1(0), reserved2(0), reserved3(0) { } }; @@ -449,10 +453,13 @@ namespace llvm { SN->flags = MachOSection::S_REGULAR | Flags; return *SN; } - MachOSection &getTextSection() { - return getSection("__TEXT", "__text", - MachOSection::S_ATTR_PURE_INSTRUCTIONS | - MachOSection::S_ATTR_SOME_INSTRUCTIONS); + MachOSection &getTextSection(bool isCode = true) { + if (isCode) + return getSection("__TEXT", "__text", + MachOSection::S_ATTR_PURE_INSTRUCTIONS | + MachOSection::S_ATTR_SOME_INSTRUCTIONS); + else + return getSection("__TEXT", "__text"); } MachOSection &getBSSSection() { return getSection("__DATA", "__bss", MachOSection::S_ZEROFILL); @@ -479,6 +486,12 @@ namespace llvm { } return getSection("__TEXT", "__const"); } + MachOSection &getJumpTableSection() { + if (TM.getRelocationModel() == Reloc::PIC_) + return getTextSection(false); + else + return getSection("__TEXT", "__const"); + } /// MachOSymTab - This struct contains information about the offsets and /// size of symbol table information. @@ -563,10 +576,6 @@ namespace llvm { /// local symbols first in the list). std::vector SymbolTable; - /// RelocBuffer - A buffer to hold the mach-o relocations before we write - /// them out at the appropriate location in the file. - DataBuffer RelocBuffer; - /// SymT - A buffer to hold the symbol table before we write it out at the /// appropriate location in the file. DataBuffer SymT; @@ -666,15 +675,31 @@ namespace llvm { outbyte(Output, 0); } + void fixhalf(DataBuffer &Output, unsigned short X, unsigned Offset) { + unsigned char *P = &Output[Offset]; + P[0] = (X >> (isLittleEndian ? 0 : 8)) & 255; + P[1] = (X >> (isLittleEndian ? 8 : 0)) & 255; + } + void fixword(DataBuffer &Output, unsigned X, unsigned Offset) { + unsigned char *P = &Output[Offset]; + P[0] = (X >> (isLittleEndian ? 0 : 24)) & 255; + P[1] = (X >> (isLittleEndian ? 8 : 16)) & 255; + P[2] = (X >> (isLittleEndian ? 16 : 8)) & 255; + P[3] = (X >> (isLittleEndian ? 24 : 0)) & 255; + } + private: void AddSymbolToSection(MachOSection &MOS, GlobalVariable *GV); void EmitGlobal(GlobalVariable *GV); void EmitHeaderAndLoadCommands(); void EmitSections(); void BufferSymbolAndStringTable(); + void CalculateRelocations(MachOSection &MOS, unsigned RelOffset); - virtual void GetTargetRelocation(MachOSection &MOS, MachineRelocation &MR, - uint64_t Addr) = 0; + virtual MachineRelocation GetJTRelocation(unsigned Offset, + MachineBasicBlock *MBB) = 0; + virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS, + unsigned ToIndex) = 0; }; } diff --git a/lib/CodeGen/MachOWriter.cpp b/lib/CodeGen/MachOWriter.cpp index 5ffd978f340..be21f5ce429 100644 --- a/lib/CodeGen/MachOWriter.cpp +++ b/lib/CodeGen/MachOWriter.cpp @@ -25,6 +25,7 @@ #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/TargetJITInfo.h" @@ -50,6 +51,14 @@ namespace llvm { /// Relocations - These are the relocations that the function needs, as /// emitted. std::vector Relocations; + + /// CPLocations - This is a map of constant pool indices to offsets from the + /// start of the section for that constant pool index. + std::vector CPLocations; + + /// JTLocations - This is a map of jump table indices to offsets from the + /// start of the section for that jump table index. + std::vector JTLocations; /// MBBLocations - This vector is a mapping from MBB ID's to their address. /// It is filled in by the StartMachineBasicBlock callback and queried by @@ -66,19 +75,22 @@ namespace llvm { 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(); - } - + void emitConstantPool(MachineConstantPool *MCP); + void emitJumpTables(MachineJumpTableInfo *MJTI); + 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; + assert(JTLocations.size() > Index && "JT not emitted!"); + return JTLocations[Index]; + } + + virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) { + if (MBBLocations.size() <= (unsigned)MBB->getNumber()) + MBBLocations.resize((MBB->getNumber()+1)*2); + MBBLocations[MBB->getNumber()] = getCurrentPCOffset(); } virtual intptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const { @@ -119,7 +131,9 @@ void MachOCodeEmitter::startFunction(MachineFunction &F) { // Upgrade the section alignment if required. if (MOS->align < Align) MOS->align = Align; - // Make sure we only relocate to this function's MBBs. + // Clear per-function data structures. + CPLocations.clear(); + JTLocations.clear(); MBBLocations.clear(); } @@ -132,26 +146,31 @@ bool MachOCodeEmitter::finishFunction(MachineFunction &F) { const GlobalValue *FuncV = F.getFunction(); MachOSym FnSym(FuncV, MOW.Mang->getValueName(FuncV), MOS->Index); - // FIXME: emit constant pool to appropriate section(s) - // FIXME: emit jump table to appropriate section + // Emit constant pool to appropriate section(s) + emitConstantPool(F.getConstantPool()); + + // Emit jump tables to appropriate section + emitJumpTables(F.getJumpTableInfo()); - // Resolve the function's relocations either to concrete pointers in the case - // of branches from one block to another, or to target relocation entries. + // If we have emitted any relocations to function-specific objects such as + // basic blocks, constant pools entries, or jump tables, record their + // addresses now so that we can rewrite them with the correct addresses + // later. for (unsigned i = 0, e = Relocations.size(); i != e; ++i) { MachineRelocation &MR = Relocations[i]; + intptr_t Addr; if (MR.isBasicBlock()) { - void *MBBAddr = (void *)getMachineBasicBlockAddress(MR.getBasicBlock()); - MR.setResultPointer(MBBAddr); - MOW.TM.getJITInfo()->relocate(BufferBegin, &MR, 1, 0); - } else if (MR.isConstantPoolIndex() || MR.isJumpTableIndex()) { - // Get the address of the index. - uint64_t Addr = 0; - // Generate the relocation(s) for the index. - MOW.GetTargetRelocation(*MOS, MR, Addr); - } else { - // Handle other types later once we've finalized the sections in the file. - MOS->Relocations.push_back(MR); + Addr = getMachineBasicBlockAddress(MR.getBasicBlock()); + MR.setResultPointer((void *)Addr); + } else if (MR.isConstantPoolIndex()) { + Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex()); + MR.setResultPointer((void *)Addr); + } else if (MR.isJumpTableIndex()) { + // FIXME: handle PIC codegen + Addr = getJumpTableEntryAddress(MR.getJumpTableIndex()); + MR.setResultPointer((void *)Addr); } + MOS->Relocations.push_back(MR); } Relocations.clear(); @@ -160,6 +179,42 @@ bool MachOCodeEmitter::finishFunction(MachineFunction &F) { return false; } +/// emitConstantPool - For each constant pool entry, figure out which section +/// the constant should live in, allocate space for it, and emit it to the +/// Section data buffer. +void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { +} + +/// emitJumpTables - Emit all the jump tables for a given jump table info +/// record to the appropriate section. +void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { + const std::vector &JT = MJTI->getJumpTables(); + if (JT.empty()) return; + + bool isPIC = MOW.TM.getRelocationModel() == Reloc::PIC_; + assert(!isPIC && "PIC codegen not yet handled for mach-o jump tables!"); + + MachOWriter::MachOSection &Sec = MOW.getJumpTableSection(); + + 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 &MBBs = JT[i].MBBs; + JTLocations.push_back(Sec.SectionData.size()); + for (unsigned mi = 0, me = MBBs.size(); mi != me; ++mi) { + MachineRelocation MR(MOW.GetJTRelocation(Sec.SectionData.size(), + MBBs[mi])); + MR.setResultPointer((void *)JTLocations[i]); + 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(); +} + //===----------------------------------------------------------------------===// // MachOWriter Implementation //===----------------------------------------------------------------------===// @@ -294,12 +349,9 @@ bool MachOWriter::doFinalization(Module &M) { // Emit the header and load commands. EmitHeaderAndLoadCommands(); - // Emit the text and data sections. + // Emit the various sections and their relocation info. EmitSections(); - // Emit the relocation entry data for each section. - O.write((char*)&RelocBuffer[0], RelocBuffer.size()); - // Write the symbol table and the string table to the end of the file. O.write((char*)&SymT[0], SymT.size()); O.write((char*)&StrT[0], StrT.size()); @@ -370,6 +422,7 @@ void MachOWriter::EmitHeaderAndLoadCommands() { E = SectionList.end(); I != E; ++I) { I->addr = currentAddr; I->offset = currentAddr + SEG.fileoff; + // FIXME: do we need to do something with alignment here? currentAddr += I->size; } @@ -380,14 +433,8 @@ void MachOWriter::EmitHeaderAndLoadCommands() { for (std::list::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) { // calculate the relocation info for this section command - // FIXME: this could get complicated calculating the address argument, we - // should probably split this out into its own function. - for (unsigned i = 0, e = I->Relocations.size(); i != e; ++i) - GetTargetRelocation(*I, I->Relocations[i], 0); - if (I->nreloc != 0) { - I->reloff = currentAddr; - currentAddr += I->nreloc * 8; - } + CalculateRelocations(*I, currentAddr); + currentAddr += I->nreloc * 8; // write the finalized section command to the output buffer outstring(FH, I->sectname, 16); @@ -449,9 +496,13 @@ void MachOWriter::EmitHeaderAndLoadCommands() { /// commands, emit the data for each section to the file. void MachOWriter::EmitSections() { for (std::list::iterator I = SectionList.begin(), - E = SectionList.end(); I != E; ++I) { + E = SectionList.end(); I != E; ++I) + // Emit the contents of each section O.write((char*)&I->SectionData[0], I->size); - } + for (std::list::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()); } /// PartitionByLocal - Simple boolean predicate that returns true if Sym is @@ -526,6 +577,23 @@ void MachOWriter::BufferSymbolAndStringTable() { } } +/// CalculateRelocations - For each MachineRelocation in the current section, +/// calculate the index of the section containing the object to be relocated, +/// 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) { + 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); + } + 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) { diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index e266c7555ae..91ae641c2e6 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -673,7 +673,7 @@ namespace { /// void *ConstantPoolBase; - /// ConstantPool - The constant pool for the current function. + /// JumpTable - The jump tables for the current function. /// MachineJumpTableInfo *JumpTable; diff --git a/lib/Target/PowerPC/PPCMachOWriter.cpp b/lib/Target/PowerPC/PPCMachOWriter.cpp index f82ee340e13..8d6de73372f 100644 --- a/lib/Target/PowerPC/PPCMachOWriter.cpp +++ b/lib/Target/PowerPC/PPCMachOWriter.cpp @@ -31,9 +31,15 @@ namespace { Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL; } - virtual void GetTargetRelocation(MachOSection &MOS, MachineRelocation &MR, - uint64_t Addr); + virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS, + unsigned ToIndex); + virtual MachineRelocation GetJTRelocation(unsigned Offset, + MachineBasicBlock *MBB); + virtual const char *getPassName() const { + return "PowerPC Mach-O Writer"; + } + // Constants for the relocation r_type field. // see enum { PPC_RELOC_VANILLA, // generic relocation @@ -53,73 +59,93 @@ namespace { /// void llvm::addPPCMachOObjectWriterPass(FunctionPassManager &FPM, std::ostream &O, PPCTargetMachine &TM) { - PPCMachOWriter *EW = new PPCMachOWriter(O, TM); - FPM.add(EW); - FPM.add(createPPCCodeEmitterPass(TM, EW->getMachineCodeEmitter())); + PPCMachOWriter *MOW = new PPCMachOWriter(O, TM); + FPM.add(MOW); + FPM.add(createPPCCodeEmitterPass(TM, MOW->getMachineCodeEmitter())); } /// GetTargetRelocation - For the MachineRelocation MR, convert it to one or /// more PowerPC MachORelocation(s), add the new relocations to the /// MachOSection, and rewrite the instruction at the section offset if required /// by that relocation type. -void PPCMachOWriter::GetTargetRelocation(MachOSection &MOS, - MachineRelocation &MR, - uint64_t Addr) { +void PPCMachOWriter::GetTargetRelocation(MachineRelocation &MR, + MachOSection &MOS, + unsigned ToIndex) { + uint64_t Addr = 0; + // Keep track of whether or not this is an externally defined relocation. - uint32_t index = MOS.Index; bool isExtern = false; - // Get the address of the instruction to rewrite - unsigned char *RelocPos = &MOS.SectionData[0] + MR.getMachineCodeOffset(); - // Get the address of whatever it is we're relocating, if possible. - if (MR.isGlobalValue()) { - // determine whether or not its external and then figure out what section - // we put it in if it's a locally defined symbol. - } else if (MR.isString()) { - // lookup in global values? - } else { - assert((MR.isConstantPoolIndex() || MR.isJumpTableIndex()) && - "Unhandled MachineRelocation type!"); - } - + if (!isExtern) + Addr = (uintptr_t)MR.getResultPointer(); + switch ((PPC::RelocationType)MR.getRelocationType()) { default: assert(0 && "Unknown PPC relocation type!"); - case PPC::reloc_pcrel_bx: - case PPC::reloc_pcrel_bcx: case PPC::reloc_absolute_low_ix: assert(0 && "Unhandled PPC relocation type!"); break; + case PPC::reloc_vanilla: + { + // FIXME: need to handle 64 bit vanilla relocs + MachORelocation VANILLA(MR.getMachineCodeOffset(), ToIndex, false, 2, + isExtern, PPC_RELOC_VANILLA); + outword(MOS.RelocBuffer, VANILLA.r_address); + outword(MOS.RelocBuffer, VANILLA.getPackedFields()); + } + MOS.nreloc += 1; + fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset()); + break; + case PPC::reloc_pcrel_bx: + Addr -= MR.getMachineCodeOffset(); + Addr >>= 2; + Addr & 0xFFFFFF; + Addr <<= 2; + Addr |= (MOS.SectionData[MR.getMachineCodeOffset()] << 24); + fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset()); + break; + case PPC::reloc_pcrel_bcx: + Addr -= MR.getMachineCodeOffset(); + Addr &= 0xFFFC; + fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2); + break; case PPC::reloc_absolute_high: { - MachORelocation HA16(MR.getMachineCodeOffset(), index, false, 2, isExtern, - PPC_RELOC_HA16); + MachORelocation HA16(MR.getMachineCodeOffset(), ToIndex, false, 2, + isExtern, PPC_RELOC_HA16); MachORelocation PAIR(Addr & 0xFFFF, 0xFFFFFF, false, 2, isExtern, PPC_RELOC_PAIR); - outword(RelocBuffer, HA16.r_address); - outword(RelocBuffer, HA16.getPackedFields()); - outword(RelocBuffer, PAIR.r_address); - outword(RelocBuffer, PAIR.getPackedFields()); + outword(MOS.RelocBuffer, HA16.r_address); + outword(MOS.RelocBuffer, HA16.getPackedFields()); + outword(MOS.RelocBuffer, PAIR.r_address); + outword(MOS.RelocBuffer, PAIR.getPackedFields()); } + printf("ha16: %x\n", (unsigned)Addr); MOS.nreloc += 2; Addr += 0x8000; - *(unsigned *)RelocPos &= 0xFFFF0000; - *(unsigned *)RelocPos |= ((Addr >> 16) & 0xFFFF); + fixhalf(MOS.SectionData, Addr >> 16, MR.getMachineCodeOffset() + 2); break; case PPC::reloc_absolute_low: { - MachORelocation LO16(MR.getMachineCodeOffset(), index, false, 2, isExtern, - PPC_RELOC_LO16); + MachORelocation LO16(MR.getMachineCodeOffset(), ToIndex, false, 2, + isExtern, PPC_RELOC_LO16); MachORelocation PAIR(Addr >> 16, 0xFFFFFF, false, 2, isExtern, PPC_RELOC_PAIR); - outword(RelocBuffer, LO16.r_address); - outword(RelocBuffer, LO16.getPackedFields()); - outword(RelocBuffer, PAIR.r_address); - outword(RelocBuffer, PAIR.getPackedFields()); + outword(MOS.RelocBuffer, LO16.r_address); + outword(MOS.RelocBuffer, LO16.getPackedFields()); + outword(MOS.RelocBuffer, PAIR.r_address); + outword(MOS.RelocBuffer, PAIR.getPackedFields()); } + printf("lo16: %x\n", (unsigned)Addr); MOS.nreloc += 2; - *(unsigned *)RelocPos &= 0xFFFF0000; - *(unsigned *)RelocPos |= (Addr & 0xFFFF); + fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2); break; } } + +MachineRelocation PPCMachOWriter::GetJTRelocation(unsigned Offset, + MachineBasicBlock *MBB) { + // FIXME: do something about PIC + return MachineRelocation::getBB(Offset, PPC::reloc_vanilla, MBB); +} + diff --git a/lib/Target/PowerPC/PPCRelocations.h b/lib/Target/PowerPC/PPCRelocations.h index 21c688de2c5..261622f9051 100644 --- a/lib/Target/PowerPC/PPCRelocations.h +++ b/lib/Target/PowerPC/PPCRelocations.h @@ -25,6 +25,10 @@ namespace llvm { namespace PPC { enum RelocationType { + // reloc_vanilla - A standard relocation, where the address of the + // relocated object completely overwrites the address of the relocation. + reloc_vanilla, + // reloc_pcrel_bx - PC relative relocation, for the b or bl instructions. reloc_pcrel_bx,