From 0b1308f18998344aa707594839a5b7c4618f4762 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Fri, 3 Jul 2009 04:36:26 +0000 Subject: [PATCH] Factor some code out and support for Jump Table relocations git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74760 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/ELFCodeEmitter.cpp | 66 +++++++++++++++++++++++++++++++++- lib/CodeGen/ELFCodeEmitter.h | 31 +++++++++------- lib/CodeGen/ELFWriter.cpp | 48 ++++++++++++++----------- lib/CodeGen/ELFWriter.h | 39 +++++++++++++++----- 4 files changed, 142 insertions(+), 42 deletions(-) diff --git a/lib/CodeGen/ELFCodeEmitter.cpp b/lib/CodeGen/ELFCodeEmitter.cpp index 57b75a37f23..691f19408d4 100644 --- a/lib/CodeGen/ELFCodeEmitter.cpp +++ b/lib/CodeGen/ELFCodeEmitter.cpp @@ -97,6 +97,9 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Emit constant pool to appropriate section(s) emitConstantPool(MF.getConstantPool()); + // Emit jump tables to appropriate section + emitJumpTables(MF.getJumpTableInfo()); + // Relocations // ----------- // If we have emitted any relocations to function-specific objects such as @@ -116,13 +119,22 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex()); MR.setConstantVal(CPSections[MR.getConstantPoolIndex()]); MR.setResultPointer((void*)Addr); + } else if (MR.isJumpTableIndex()) { + Addr = getJumpTableEntryAddress(MR.getJumpTableIndex()); + MR.setResultPointer((void*)Addr); + MR.setConstantVal(JumpTableSectionIdx); } else { assert(0 && "Unhandled relocation type"); } ES->addRelocation(MR); } - Relocations.clear(); + // Clear per-function data structures. + Relocations.clear(); + CPLocations.clear(); + CPSections.clear(); + JTLocations.clear(); + MBBLocations.clear(); return false; } @@ -158,4 +170,56 @@ void ELFCodeEmitter::emitConstantPool(MachineConstantPool *MCP) { } } +/// emitJumpTables - Emit all the jump tables for a given jump table info +/// record to the appropriate section. +void ELFCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) { + const std::vector &JT = MJTI->getJumpTables(); + if (JT.empty()) return; + + // FIXME: handle PIC codegen + assert(TM.getRelocationModel() != Reloc::PIC_ && + "PIC codegen not yet handled for elf jump tables!"); + + const TargetAsmInfo *TAI = TM.getTargetAsmInfo(); + + // Get the ELF Section to emit the jump table + unsigned Align = TM.getTargetData()->getPointerABIAlignment(); + std::string JTName(TAI->getJumpTableDataSection()); + ELFSection &JTSection = EW.getJumpTableSection(JTName, Align); + JumpTableSectionIdx = JTSection.SectionIdx; + + // Entries in the JT Section are relocated against the text section + ELFSection &TextSection = EW.getTextSection(); + + // For each JT, record its offset from the start of the section + for (unsigned i = 0, e = JT.size(); i != e; ++i) { + const std::vector &MBBs = JT[i].MBBs; + + DOUT << "JTSection.size(): " << JTSection.size() << "\n"; + DOUT << "JTLocations.size: " << JTLocations.size() << "\n"; + + // Record JT 'i' offset in the JT section + JTLocations.push_back(JTSection.size()); + + // Each MBB entry in the Jump table section has a relocation entry + // against the current text section. + for (unsigned mi = 0, me = MBBs.size(); mi != me; ++mi) { + MachineRelocation MR = + MachineRelocation::getBB(JTSection.size(), + MachineRelocation::VANILLA, + MBBs[mi]); + + // Offset of JT 'i' in JT section + MR.setResultPointer((void*)getMachineBasicBlockAddress(MBBs[mi])); + MR.setConstantVal(TextSection.SectionIdx); + + // Add the relocation to the Jump Table section + JTSection.addRelocation(MR); + + // Output placeholder for MBB in the JT section + JTSection.emitWord(0); + } + } +} + } // end namespace llvm diff --git a/lib/CodeGen/ELFCodeEmitter.h b/lib/CodeGen/ELFCodeEmitter.h index e3d36184748..982aebf8fcc 100644 --- a/lib/CodeGen/ELFCodeEmitter.h +++ b/lib/CodeGen/ELFCodeEmitter.h @@ -40,6 +40,10 @@ namespace llvm { /// containing the constant pool entry for that index. std::vector 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 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 /// the getMachineBasicBlockAddress callback. @@ -48,8 +52,12 @@ namespace llvm { /// FnStartPtr - Pointer to the start location of the current function /// in the buffer uint8_t *FnStartPtr; + + /// JumpTableSectionIdx - Holds the index of the Jump Table Section + unsigned JumpTableSectionIdx; public: - explicit ELFCodeEmitter(ELFWriter &ew) : EW(ew), TM(EW.TM) {} + explicit ELFCodeEmitter(ELFWriter &ew) : EW(ew), TM(EW.TM), + JumpTableSectionIdx(0) {} void startFunction(MachineFunction &F); bool finishFunction(MachineFunction &F); @@ -64,25 +72,20 @@ namespace llvm { MBBLocations[MBB->getNumber()] = getCurrentPCOffset(); } - virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) { - assert(MBBLocations.size() > (unsigned)MBB->getNumber() && - MBBLocations[MBB->getNumber()] && "MBB not emitted!"); - return MBBLocations[MBB->getNumber()]; - } - virtual uintptr_t getConstantPoolEntryAddress(unsigned Index) const { assert(CPLocations.size() > Index && "CP not emitted!"); return CPLocations[Index]; } virtual uintptr_t getJumpTableEntryAddress(unsigned Index) const { - assert(0 && "JT not implementated yet!"); - return 0; + assert(JTLocations.size() > Index && "JT not emitted!"); + return JTLocations[Index]; } virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const { - assert(0 && "JT not implementated yet!"); - return 0; + assert(MBBLocations.size() > (unsigned)MBB->getNumber() && + MBBLocations[MBB->getNumber()] && "MBB not emitted!"); + return MBBLocations[MBB->getNumber()]; } virtual uintptr_t getLabelAddress(uint64_t Label) const { @@ -100,7 +103,11 @@ namespace llvm { /// the constant should live in and emit the constant. void emitConstantPool(MachineConstantPool *MCP); - virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) { } + /// emitJumpTables - Emit all the jump tables for a given jump table info + /// record to the appropriate section. + void emitJumpTables(MachineJumpTableInfo *MJTI); + + virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) {} /// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE! void startGVStub(const GlobalValue* F, unsigned StubSize, diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index d74e826f92e..9e915245525 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -166,43 +166,51 @@ unsigned ELFWriter::getGlobalELFLinkage(const GlobalValue *GV) { return ELFSym::STB_GLOBAL; } +// getElfSectionFlags - Get the ELF Section Header based on the +// flags defined in ELFTargetAsmInfo. +unsigned ELFWriter::getElfSectionFlags(unsigned Flags) { + unsigned ElfSectionFlags = ELFSection::SHF_ALLOC; + + if (Flags & SectionFlags::Code) + ElfSectionFlags |= ELFSection::SHF_EXECINSTR; + if (Flags & SectionFlags::Writeable) + ElfSectionFlags |= ELFSection::SHF_WRITE; + if (Flags & SectionFlags::Mergeable) + ElfSectionFlags |= ELFSection::SHF_MERGE; + if (Flags & SectionFlags::TLS) + ElfSectionFlags |= ELFSection::SHF_TLS; + if (Flags & SectionFlags::Strings) + ElfSectionFlags |= ELFSection::SHF_STRINGS; + + return ElfSectionFlags; +} + // For global symbols without a section, return the Null section as a // placeholder ELFSection &ELFWriter::getGlobalSymELFSection(const GlobalVariable *GV, ELFSym &Sym) { - const Section *S = TAI->SectionForGlobal(GV); - unsigned Flags = S->getFlags(); - unsigned SectionType = ELFSection::SHT_PROGBITS; - unsigned SHdrFlags = ELFSection::SHF_ALLOC; - DOUT << "Section " << S->getName() << " for global " << GV->getName() << "\n"; - - // If this is an external global, the symbol does not have a section. + // If this is a declaration, the symbol does not have a section. if (!GV->hasInitializer()) { Sym.SectionIdx = ELFSection::SHN_UNDEF; return getNullSection(); } + // Get the name and flags of the section for the global + const Section *S = TAI->SectionForGlobal(GV); + unsigned SectionType = ELFSection::SHT_PROGBITS; + unsigned SectionFlags = getElfSectionFlags(S->getFlags()); + DOUT << "Section " << S->getName() << " for global " << GV->getName() << "\n"; + const TargetData *TD = TM.getTargetData(); unsigned Align = TD->getPreferredAlignment(GV); Constant *CV = GV->getInitializer(); - if (Flags & SectionFlags::Code) - SHdrFlags |= ELFSection::SHF_EXECINSTR; - if (Flags & SectionFlags::Writeable) - SHdrFlags |= ELFSection::SHF_WRITE; - if (Flags & SectionFlags::Mergeable) - SHdrFlags |= ELFSection::SHF_MERGE; - if (Flags & SectionFlags::TLS) - SHdrFlags |= ELFSection::SHF_TLS; - if (Flags & SectionFlags::Strings) - SHdrFlags |= ELFSection::SHF_STRINGS; - // If this global has a zero initializer, go to .bss or common section. // Variables are part of the common block if they are zero initialized // and allowed to be merged with other symbols. if (CV->isNullValue() || isa(CV)) { SectionType = ELFSection::SHT_NOBITS; - ELFSection &ElfS = getSection(S->getName(), SectionType, SHdrFlags); + ELFSection &ElfS = getSection(S->getName(), SectionType, SectionFlags); if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() || GV->hasCommonLinkage()) { Sym.SectionIdx = ELFSection::SHN_COMMON; @@ -218,7 +226,7 @@ ELFSection &ELFWriter::getGlobalSymELFSection(const GlobalVariable *GV, } Sym.IsConstant = true; - ELFSection &ElfS = getSection(S->getName(), SectionType, SHdrFlags); + ELFSection &ElfS = getSection(S->getName(), SectionType, SectionFlags); Sym.SectionIdx = ElfS.SectionIdx; ElfS.Align = std::max(ElfS.Align, Align); return ElfS; diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index 950af90035b..bab118c6e35 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -118,19 +118,33 @@ namespace llvm { /// is seen, the symbol will move from this list to the SymbolList. SetVector PendingGlobals; + // Remove tab from section name prefix. This is necessary becase TAI + // sometimes return a section name prefixed with a "\t" char. This is + // a little bit dirty. FIXME: find a better approach, maybe add more + // methods to TAI to get the clean name? + void fixNameForSection(std::string &Name) { + size_t Pos = Name.find("\t"); + if (Pos != std::string::npos) + Name.erase(Pos, 1); + + Pos = Name.find(".section "); + if (Pos != std::string::npos) + Name.erase(Pos, 9); + + Pos = Name.find("\n"); + if (Pos != std::string::npos) + Name.erase(Pos, 1); + } + /// getSection - Return the section with the specified name, creating a new /// section if one does not already exist. ELFSection &getSection(const std::string &Name, unsigned Type, unsigned Flags = 0, unsigned Align = 0) { - ELFSection *&SN = SectionLookup[Name]; - if (SN) return *SN; - - // Remove tab from section name prefix. This is necessary becase TAI - // sometimes return a section name prefixed with a "\t" char. std::string SectionName(Name); - size_t Pos = SectionName.find("\t"); - if (Pos != std::string::npos) - SectionName.erase(Pos, 1); + fixNameForSection(SectionName); + + ELFSection *&SN = SectionLookup[SectionName]; + if (SN) return *SN; SectionList.push_back(ELFSection(SectionName, isLittleEndian, is64Bit)); SN = &SectionList.back(); @@ -149,6 +163,12 @@ namespace llvm { ELFSection::SHF_EXECINSTR | ELFSection::SHF_ALLOC); } + /// Get jump table section on the section name returned by TAI + ELFSection &getJumpTableSection(std::string SName, unsigned Align) { + return getSection(SName, ELFSection::SHT_PROGBITS, + ELFSection::SHF_ALLOC, Align); + } + /// Get a constant pool section based on the section name returned by TAI ELFSection &getConstantPoolSection(std::string SName, unsigned Align) { return getSection(SName, ELFSection::SHT_PROGBITS, @@ -197,9 +217,10 @@ namespace llvm { return getSection("", ELFSection::SHT_NULL, 0); } - // Helpers for obtaining ELF specific Linkage and Visibility info. + // Helpers for obtaining ELF specific info. unsigned getGlobalELFLinkage(const GlobalValue *GV); unsigned getGlobalELFVisibility(const GlobalValue *GV); + unsigned getElfSectionFlags(unsigned Flags); // As we complete the ELF file, we need to update fields in the ELF header // (e.g. the location of the section table). These members keep track of