From a040566fec506b93d5dcff6eb720c3c7e8491858 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Mon, 22 Jun 2009 19:16:16 +0000 Subject: [PATCH] Add more methods to gather target specific elf stuff Support for .text relocations, implementing TargetELFWriter overloaded methods for x86/x86_64. Use a map to track global values to their symbol table indexes Code cleanup and small fixes llvm-svn: 73894 --- llvm/include/llvm/CodeGen/BinaryObject.h | 6 + .../include/llvm/Target/TargetELFWriterInfo.h | 23 +- llvm/lib/CodeGen/ELF.h | 48 ++- llvm/lib/CodeGen/ELFCodeEmitter.cpp | 50 ++- llvm/lib/CodeGen/ELFWriter.cpp | 325 +++++++++++------- llvm/lib/CodeGen/ELFWriter.h | 61 +++- llvm/lib/Target/X86/X86ELFWriterInfo.cpp | 46 +++ llvm/lib/Target/X86/X86ELFWriterInfo.h | 32 ++ 8 files changed, 427 insertions(+), 164 deletions(-) diff --git a/llvm/include/llvm/CodeGen/BinaryObject.h b/llvm/include/llvm/CodeGen/BinaryObject.h index 0780cd6ab4f4..4b66fe85678c 100644 --- a/llvm/include/llvm/CodeGen/BinaryObject.h +++ b/llvm/include/llvm/CodeGen/BinaryObject.h @@ -61,6 +61,11 @@ public: return Relocations; } + /// hasRelocations - Return true if 'Relocations' is not empty + bool hasRelocations() const { + return !Relocations.empty(); + } + /// emitByte - This callback is invoked when a byte needs to be /// written to the data stream. inline void emitByte(uint8_t B) { @@ -317,6 +322,7 @@ public: void addRelocation(const MachineRelocation& relocation) { Relocations.push_back(relocation); } + }; } // end namespace llvm diff --git a/llvm/include/llvm/Target/TargetELFWriterInfo.h b/llvm/include/llvm/Target/TargetELFWriterInfo.h index f7e3392577d9..c1f54d201a0e 100644 --- a/llvm/include/llvm/Target/TargetELFWriterInfo.h +++ b/llvm/include/llvm/Target/TargetELFWriterInfo.h @@ -78,11 +78,32 @@ namespace llvm { /// Symbol Table Info unsigned getSymTabEntrySize() const { return is64Bit ? 24 : 16; } - unsigned getSymTabAlignment() const { return is64Bit ? 8 : 4; } + + /// getPrefELFAlignment - Returns the preferred alignment for ELF. This + /// is used to align some sections. + unsigned getPrefELFAlignment() const { return is64Bit ? 8 : 4; } + + /// getRelocationEntrySize - Entry size used in the relocation section + unsigned getRelocationEntrySize() const { + return is64Bit ? (hasRelocationAddend() ? 24 : 16) + : (hasRelocationAddend() ? 12 : 8); + } /// getFunctionAlignment - Returns the alignment for function 'F', targets /// with different alignment constraints should overload this method virtual unsigned getFunctionAlignment(const Function *F) const; + + /// getRelocationType - Returns the target specific ELF Relocation type. + /// 'MachineRelTy' contains the object code independent relocation type + virtual unsigned getRelocationType(unsigned MachineRelTy) const = 0; + + /// hasRelocationAddend - True if the target uses an addend in the + /// ELF relocation entry. + virtual bool hasRelocationAddend() const = 0; + + /// getAddendForRelTy - Gets the addend value for an ELF relocation entry + /// based on the target relocation type. If addend is not used returns 0. + virtual long int getAddendForRelTy(unsigned RelTy) const = 0; }; } // end llvm namespace diff --git a/llvm/lib/CodeGen/ELF.h b/llvm/lib/CodeGen/ELF.h index 796bc2c3b2c0..28b6be8910e5 100644 --- a/llvm/lib/CodeGen/ELF.h +++ b/llvm/lib/CodeGen/ELF.h @@ -128,7 +128,13 @@ namespace llvm { /// added to logical symbol table for the module. This is eventually /// turned into a real symbol table in the file. struct ELFSym { - const GlobalValue *GV; // The global value this corresponds to. + // The global value this corresponds to. Global symbols can be on of the + // 3 types : if this symbol has a zero initializer, it is common or should + // be placed in bss section otherwise it's a constant. + const GlobalValue *GV; + bool IsCommon; + bool IsBss; + bool IsConstant; // ELF specific fields unsigned NameIdx; // Index in .strtab of name, once emitted. @@ -159,8 +165,9 @@ namespace llvm { STV_PROTECTED = 3 // Visible in other components but not preemptable }; - ELFSym(const GlobalValue *gv) : GV(gv), NameIdx(0), Value(0), - Size(0), Info(0), Other(0), + ELFSym(const GlobalValue *gv) : GV(gv), IsCommon(false), IsBss(false), + IsConstant(false), NameIdx(0), Value(0), + Size(0), Info(0), Other(STV_DEFAULT), SectionIdx(ELFSection::SHN_UNDEF) { if (!GV) return; @@ -180,16 +187,47 @@ namespace llvm { } } - void SetBind(unsigned X) { + unsigned getBind() { + return (Info >> 4) & 0xf; + } + + void setBind(unsigned X) { assert(X == (X & 0xF) && "Bind value out of range!"); Info = (Info & 0x0F) | (X << 4); } - void SetType(unsigned X) { + void setType(unsigned X) { assert(X == (X & 0xF) && "Type value out of range!"); Info = (Info & 0xF0) | X; } }; + /// ELFRelocation - This class contains all the information necessary to + /// to generate any 32-bit or 64-bit ELF relocation entry. + class ELFRelocation { + uint64_t r_offset; // offset in the section of the object this applies to + uint32_t r_symidx; // symbol table index of the symbol to use + uint32_t r_type; // machine specific relocation type + int64_t r_add; // explicit relocation addend + bool r_rela; // if true then the addend is part of the entry + // otherwise the addend is at the location specified + // by r_offset + public: + uint64_t getInfo(bool is64Bit) const { + if (is64Bit) + return ((uint64_t)r_symidx << 32) + ((uint64_t)r_type & 0xFFFFFFFFL); + else + return (r_symidx << 8) + (r_type & 0xFFL); + } + + uint64_t getOffset() const { return r_offset; } + int64_t getAddend() const { return r_add; } + + ELFRelocation(uint64_t off, uint32_t sym, uint32_t type, + bool rela = true, int64_t addend = 0) : + r_offset(off), r_symidx(sym), r_type(type), + r_add(addend), r_rela(rela) {} + }; + } // end namespace llvm #endif diff --git a/llvm/lib/CodeGen/ELFCodeEmitter.cpp b/llvm/lib/CodeGen/ELFCodeEmitter.cpp index ca683969e411..8cb7c94c5d0f 100644 --- a/llvm/lib/CodeGen/ELFCodeEmitter.cpp +++ b/llvm/lib/CodeGen/ELFCodeEmitter.cpp @@ -71,38 +71,37 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Update Section Size ES->Size = CurBufferPtr - BufferBegin; - // Figure out the binding (linkage) of the symbol. - switch (MF.getFunction()->getLinkage()) { - default: - // appending linkage is illegal for functions. - assert(0 && "Unknown linkage type!"); - case GlobalValue::ExternalLinkage: - FnSym.SetBind(ELFSym::STB_GLOBAL); - break; - case GlobalValue::LinkOnceAnyLinkage: - case GlobalValue::LinkOnceODRLinkage: - case GlobalValue::WeakAnyLinkage: - case GlobalValue::WeakODRLinkage: - FnSym.SetBind(ELFSym::STB_WEAK); - break; - case GlobalValue::PrivateLinkage: - assert (0 && "PrivateLinkage should not be in the symbol table."); - case GlobalValue::InternalLinkage: - FnSym.SetBind(ELFSym::STB_LOCAL); - break; - } - // Set the symbol type as a function - FnSym.SetType(ELFSym::STT_FUNC); - + FnSym.setType(ELFSym::STT_FUNC); FnSym.SectionIdx = ES->SectionIdx; FnSym.Size = CurBufferPtr-FnStartPtr; // Offset from start of Section FnSym.Value = FnStartPtr-BufferBegin; - // Finally, add it to the symtab. - EW.SymbolList.push_back(FnSym); + // Figure out the binding (linkage) of the symbol. + switch (MF.getFunction()->getLinkage()) { + default: + // appending linkage is illegal for functions. + assert(0 && "Unknown linkage type!"); + case GlobalValue::ExternalLinkage: + FnSym.setBind(ELFSym::STB_GLOBAL); + EW.SymbolList.push_back(FnSym); + break; + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + FnSym.setBind(ELFSym::STB_WEAK); + EW.SymbolList.push_back(FnSym); + break; + case GlobalValue::PrivateLinkage: + assert (0 && "PrivateLinkage should not be in the symbol table."); + case GlobalValue::InternalLinkage: + FnSym.setBind(ELFSym::STB_LOCAL); + EW.SymbolList.push_front(FnSym); + break; + } // Relocations // ----------- @@ -113,7 +112,6 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { 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.setConstantVal(ES->SectionIdx); diff --git a/llvm/lib/CodeGen/ELFWriter.cpp b/llvm/lib/CodeGen/ELFWriter.cpp index aeccefbd3e80..281cf2fa11e7 100644 --- a/llvm/lib/CodeGen/ELFWriter.cpp +++ b/llvm/lib/CodeGen/ELFWriter.cpp @@ -136,105 +136,41 @@ bool ELFWriter::doInitialization(Module &M) { ElfHdr.emitWord16(0); // Placeholder // Add the null section, which is required to be first in the file. - getSection("", ELFSection::SHT_NULL, 0); - - // Start up the symbol table. The first entry in the symtab is the null - // entry. - SymbolList.push_back(ELFSym(0)); + getNullSection(); return false; } -void ELFWriter::EmitGlobal(GlobalVariable *GV) { +unsigned ELFWriter::getGlobalELFLinkage(const GlobalVariable *GV) { + if (GV->hasInternalLinkage()) + return ELFSym::STB_LOCAL; - // XXX: put local symbols *before* global ones! + if (GV->hasWeakLinkage()) + return ELFSym::STB_WEAK; + + return ELFSym::STB_GLOBAL; +} + +// 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); - DOUT << "Section " << S->getName() << " for global " << GV->getName() << "\n"; - - // If this is an external global, emit it now. TODO: Note that it would be - // better to ignore the symbol here and only add it to the symbol table if - // referenced. - if (!GV->hasInitializer()) { - ELFSym ExternalSym(GV); - ExternalSym.SetBind(ELFSym::STB_GLOBAL); - ExternalSym.SetType(ELFSym::STT_NOTYPE); - ExternalSym.SectionIdx = ELFSection::SHN_UNDEF; - SymbolList.push_back(ExternalSym); - return; - } - + unsigned Flags = S->getFlags(); + unsigned SectionType = ELFSection::SHT_PROGBITS; + unsigned SHdrFlags = ELFSection::SHF_ALLOC; const TargetData *TD = TM.getTargetData(); unsigned Align = TD->getPreferredAlignment(GV); Constant *CV = GV->getInitializer(); - unsigned Size = TD->getTypeAllocSize(CV->getType()); - // If this global has a zero initializer, go to .bss or common section. - if (CV->isNullValue() || isa(CV)) { - // If this global is part of the common block, add it now. Variables are - // part of the common block if they are zero initialized and allowed to be - // merged with other symbols. - if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() || - GV->hasCommonLinkage()) { - ELFSym CommonSym(GV); - // Value for common symbols is the alignment required. - CommonSym.Value = Align; - CommonSym.Size = Size; - CommonSym.SetBind(ELFSym::STB_GLOBAL); - CommonSym.SetType(ELFSym::STT_OBJECT); - CommonSym.SectionIdx = ELFSection::SHN_COMMON; - SymbolList.push_back(CommonSym); - getSection(S->getName(), ELFSection::SHT_NOBITS, - ELFSection::SHF_WRITE | ELFSection::SHF_ALLOC, 1); - return; - } + DOUT << "Section " << S->getName() << " for global " << GV->getName() << "\n"; - // Otherwise, this symbol is part of the .bss section. Emit it now. - // Handle alignment. Ensure section is aligned at least as much as required - // by this symbol. - ELFSection &BSSSection = getBSSSection(); - BSSSection.Align = std::max(BSSSection.Align, Align); - - // Within the section, emit enough virtual padding to get us to an alignment - // boundary. - if (Align) - BSSSection.Size = (BSSSection.Size + Align - 1) & ~(Align-1); - - ELFSym BSSSym(GV); - BSSSym.Value = BSSSection.Size; - BSSSym.Size = Size; - BSSSym.SetType(ELFSym::STT_OBJECT); - - switch (GV->getLinkage()) { - default: // weak/linkonce/common handled above - assert(0 && "Unexpected linkage type!"); - case GlobalValue::AppendingLinkage: // FIXME: This should be improved! - case GlobalValue::ExternalLinkage: - BSSSym.SetBind(ELFSym::STB_GLOBAL); - break; - case GlobalValue::InternalLinkage: - BSSSym.SetBind(ELFSym::STB_LOCAL); - break; - } - - // Set the idx of the .bss section - BSSSym.SectionIdx = BSSSection.SectionIdx; - if (!GV->hasPrivateLinkage()) - SymbolList.push_back(BSSSym); - - // Reserve space in the .bss section for this symbol. - BSSSection.Size += Size; - return; + // If this is an external global, the symbol does not have a section. + if (!GV->hasInitializer()) { + Sym.SectionIdx = ELFSection::SHN_UNDEF; + return getNullSection(); } - /// Emit the Global symbol to the right ELF section - ELFSym GblSym(GV); - GblSym.Size = Size; - GblSym.SetType(ELFSym::STT_OBJECT); - GblSym.SetBind(ELFSym::STB_GLOBAL); - unsigned Flags = S->getFlags(); - unsigned SectType = ELFSection::SHT_PROGBITS; - unsigned SHdrFlags = ELFSection::SHF_ALLOC; - if (Flags & SectionFlags::Code) SHdrFlags |= ELFSection::SHF_EXECINSTR; if (Flags & SectionFlags::Writeable) @@ -246,29 +182,78 @@ void ELFWriter::EmitGlobal(GlobalVariable *GV) { if (Flags & SectionFlags::Strings) SHdrFlags |= ELFSection::SHF_STRINGS; - // Remove tab from section name prefix - std::string SectionName(S->getName()); - size_t Pos = SectionName.find("\t"); - if (Pos != std::string::npos) - SectionName.erase(Pos, 1); + // 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); + if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() || + GV->hasCommonLinkage()) { + Sym.SectionIdx = ELFSection::SHN_COMMON; + Sym.IsCommon = true; + return ElfS; + } + Sym.IsBss = true; + Sym.SectionIdx = ElfS.SectionIdx; + if (Align) ElfS.Size = (ElfS.Size + Align-1) & ~(Align-1); + ElfS.Align = std::max(ElfS.Align, Align); + return ElfS; + } - // The section alignment should be bound to the element with - // the largest alignment - ELFSection &ElfS = getSection(SectionName, SectType, SHdrFlags); - GblSym.SectionIdx = ElfS.SectionIdx; - if (Align > ElfS.Align) - ElfS.Align = Align; + Sym.IsConstant = true; + ELFSection &ElfS = getSection(S->getName(), SectionType, SHdrFlags); + Sym.SectionIdx = ElfS.SectionIdx; + ElfS.Align = std::max(ElfS.Align, Align); + return ElfS; +} - // S.Value should contain the symbol index inside the section, - // and all symbols should start on their required alignment boundary - GblSym.Value = (ElfS.size() + (Align-1)) & (-Align); - ElfS.emitAlignment(Align); - - // Emit the constant symbol to its section - EmitGlobalConstant(CV, ElfS); +void ELFWriter::EmitFunctionDeclaration(const Function *F) { + ELFSym GblSym(F); + GblSym.setBind(ELFSym::STB_GLOBAL); + GblSym.setType(ELFSym::STT_NOTYPE); + GblSym.SectionIdx = ELFSection::SHN_UNDEF; SymbolList.push_back(GblSym); } +void ELFWriter::EmitGlobalVar(const GlobalVariable *GV) { + unsigned SymBind = getGlobalELFLinkage(GV); + ELFSym GblSym(GV); + GblSym.setBind(SymBind); + + if (GV->hasInitializer()) + GblSym.setType(ELFSym::STT_OBJECT); + else + GblSym.setType(ELFSym::STT_NOTYPE); + + ELFSection &GblSection = getGlobalSymELFSection(GV, GblSym); + const TargetData *TD = TM.getTargetData(); + unsigned Align = TD->getPreferredAlignment(GV); + unsigned Size = TD->getTypeAllocSize(GV->getInitializer()->getType()); + GblSym.Size = Size; + + if (GblSym.IsCommon) { + GblSym.Value = Align; + } else if (GblSym.IsBss) { + GblSym.Value = GblSection.Size; + GblSection.Size += Size; + } else if (GblSym.IsConstant){ + // GblSym.Value should contain the symbol index inside the section, + // and all symbols should start on their required alignment boundary + GblSym.Value = (GblSection.size() + (Align-1)) & (-Align); + GblSection.emitAlignment(Align); + EmitGlobalConstant(GV->getInitializer(), GblSection); + } + + // Local symbols should come first on the symbol table. + if (!GV->hasPrivateLinkage()) { + if (SymBind == ELFSym::STB_LOCAL) + SymbolList.push_front(GblSym); + else + SymbolList.push_back(GblSym); + } +} + void ELFWriter::EmitGlobalConstantStruct(const ConstantStruct *CVS, ELFSection &GblS) { @@ -306,6 +291,7 @@ void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) { if (const ConstantArray *CVA = dyn_cast(CV)) { if (CVA->isString()) { std::string GblStr = CVA->getAsString(); + GblStr.resize(GblStr.size()-1); GblS.emitString(GblStr); } else { // Not a string. Print the values in successive locations for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i) @@ -370,8 +356,31 @@ bool ELFWriter::doFinalization(Module &M) { // Build and emit data, bss and "common" sections. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - EmitGlobal(I); + I != E; ++I) { + EmitGlobalVar(I); + GblSymLookup[I] = 0; + } + + // Emit all pending globals + // TODO: this should be done only for referenced symbols + for (SetVector::const_iterator I = PendingGlobals.begin(), + E = PendingGlobals.end(); I != E; ++I) { + + // No need to emit the symbol again + if (GblSymLookup.find(*I) != GblSymLookup.end()) + continue; + + if (GlobalVariable *GV = dyn_cast(*I)) { + EmitGlobalVar(GV); + } else if (Function *F = dyn_cast(*I)) { + // If function is not in GblSymLookup, it doesn't have a body, + // so emit the symbol as a function declaration (no section associated) + EmitFunctionDeclaration(F); + } else { + assert("unknown howto handle pending global"); + } + GblSymLookup[*I] = 0; + } // Emit non-executable stack note if (TAI->getNonexecutableStackDirective()) @@ -400,6 +409,67 @@ bool ELFWriter::doFinalization(Module &M) { /// EmitRelocations - Emit relocations void ELFWriter::EmitRelocations() { + + // Create Relocation sections for each section which needs it. + for (std::list::iterator I = SectionList.begin(), + E = SectionList.end(); I != E; ++I) { + + // This section does not have relocations + if (!I->hasRelocations()) continue; + + // Get the relocation section for section 'I' + bool HasRelA = TEW->hasRelocationAddend(); + ELFSection &RelSec = getRelocSection(I->getName(), HasRelA); + + // 'Link' - Section hdr idx of the associated symbol table + // 'Info' - Section hdr idx of the section to which the relocation applies + ELFSection &SymTab = getSymbolTableSection(); + RelSec.Link = SymTab.SectionIdx; + RelSec.Info = I->SectionIdx; + RelSec.EntSize = TEW->getRelocationEntrySize(); + + // Get the relocations from Section + std::vector Relos = I->getRelocations(); + for (std::vector::iterator MRI = Relos.begin(), + MRE = Relos.end(); MRI != MRE; ++MRI) { + MachineRelocation &MR = *MRI; + + // Offset from the start of the section containing the symbol + unsigned Offset = MR.getMachineCodeOffset(); + + // Symbol index in the symbol table + unsigned SymIdx = 0; + + // Target specific ELF relocation type + unsigned RelType = TEW->getRelocationType(MR.getRelocationType()); + + // Constant addend used to compute the value to be stored + // into the relocatable field + int64_t Addend = TEW->getAddendForRelTy(RelType); + + // There are several machine relocations types, and each one of + // them needs a different approach to retrieve the symbol table index. + if (MR.isGlobalValue()) { + const GlobalValue *G = MR.getGlobalValue(); + SymIdx = GblSymLookup[G]; + } else { + assert(0 && "dunno how to handle other relocation types"); + } + + // Get the relocation entry and emit to the relocation section + ELFRelocation Rel(Offset, SymIdx, RelType, HasRelA, Addend); + EmitRelocation(RelSec, Rel, HasRelA); + } + } +} + +/// EmitRelocation - Write relocation 'Rel' to the relocation section 'Rel' +void ELFWriter::EmitRelocation(BinaryObject &RelSec, ELFRelocation &Rel, + bool HasRelA) { + RelSec.emitWord(Rel.getOffset()); + RelSec.emitWord(Rel.getInfo(is64Bit)); + if (HasRelA) + RelSec.emitWord(Rel.getAddend()); } /// EmitSymbol - Write symbol 'Sym' to the symbol table 'SymbolTable' @@ -451,25 +521,27 @@ void ELFWriter::EmitSectionHeader(BinaryObject &SHdrTab, /// EmitSymbolTable - If the current symbol table is non-empty, emit the string /// table for it and then the symbol table itself. void ELFWriter::EmitSymbolTable() { - if (SymbolList.size() == 1) return; // Only the null entry. + if (!SymbolList.size()) return; // Empty symbol table. - // FIXME: compact all local symbols to the start of the symtab. unsigned FirstNonLocalSymbol = 1; - ELFSection &StrTab = getStringTableSection(); // Set the zero'th symbol to a null byte, as required. StrTab.emitByte(0); + // Walk on the symbol list and write symbol names into the + // string table. unsigned Index = 1; - for (unsigned i = 1, e = SymbolList.size(); i != e; ++i) { + for (std::list::iterator I = SymbolList.begin(), + E = SymbolList.end(); I != E; ++I) { + // Use the name mangler to uniquify the LLVM symbol. - std::string Name = Mang->getValueName(SymbolList[i].GV); + std::string Name = Mang->getValueName(I->GV); if (Name.empty()) { - SymbolList[i].NameIdx = 0; + I->NameIdx = 0; } else { - SymbolList[i].NameIdx = Index; + I->NameIdx = Index; StrTab.emitString(Name); // Keep track of the number of bytes emitted to this section. @@ -482,16 +554,33 @@ void ELFWriter::EmitSymbolTable() { // Now that we have emitted the string table and know the offset into the // string table of each symbol, emit the symbol table itself. ELFSection &SymTab = getSymbolTableSection(); - SymTab.Align = TEW->getSymTabAlignment(); + SymTab.Align = TEW->getPrefELFAlignment(); SymTab.Link = StrTab.SectionIdx; // Section Index of .strtab. - SymTab.Info = FirstNonLocalSymbol; // First non-STB_LOCAL symbol. // Size of each symtab entry. SymTab.EntSize = TEW->getSymTabEntrySize(); - for (unsigned i = 0, e = SymbolList.size(); i != e; ++i) - EmitSymbol(SymTab, SymbolList[i]); + // The first entry in the symtab is the null symbol + ELFSym NullSym = ELFSym(0); + EmitSymbol(SymTab, NullSym); + // Emit all the symbols to the symbol table. Skip the null + // symbol, cause it's emitted already + Index = 1; + for (std::list::iterator I = SymbolList.begin(), + E = SymbolList.end(); I != E; ++I, ++Index) { + // Keep track of the first non-local symbol + if (I->getBind() == ELFSym::STB_LOCAL) + FirstNonLocalSymbol++; + + // Emit symbol to the symbol table + EmitSymbol(SymTab, *I); + + // Record the symbol table index for each global value + GblSymLookup[I->GV] = Index; + } + + SymTab.Info = FirstNonLocalSymbol; SymTab.Size = SymTab.size(); } @@ -559,7 +648,7 @@ void ELFWriter::OutputSectionsAndSectionTable() { } // Align Section Header. - unsigned TableAlign = is64Bit ? 8 : 4; + unsigned TableAlign = TEW->getPrefELFAlignment(); FileOff = (FileOff+TableAlign-1) & ~(TableAlign-1); // Now that we know where all of the sections will be emitted, set the e_shnum diff --git a/llvm/lib/CodeGen/ELFWriter.h b/llvm/lib/CodeGen/ELFWriter.h index 8a380f034010..c713e33118a1 100644 --- a/llvm/lib/CodeGen/ELFWriter.h +++ b/llvm/lib/CodeGen/ELFWriter.h @@ -16,7 +16,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Support/OutputBuffer.h" +#include "llvm/Support/Debug.h" #include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetELFWriterInfo.h" #include "ELF.h" @@ -89,7 +89,7 @@ namespace llvm { bool doFinalization(Module &M); private: - // Blob containing the Elf header + /// Blob containing the Elf header BinaryObject ElfHdr; /// SectionList - This is the list of sections that we have emitted to the @@ -102,14 +102,35 @@ namespace llvm { /// the SectionList. std::map SectionLookup; + /// GblSymLookup - This is a mapping from global value to a symbol index + /// in the symbol table. This is useful since relocations symbol references + /// must be quickly mapped to a symbol table index + std::map GblSymLookup; + + /// SymbolList - This is the list of symbols emitted to the symbol table + /// Local symbols go to the front and Globals to the back. + std::list SymbolList; + + /// PendingGlobals - List of externally defined symbols that we have been + /// asked to emit, but have not seen a reference to. When a reference + /// is seen, the symbol will move from this list to the SymbolList. + SetVector PendingGlobals; + /// 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, + ELFSection &getSection(const std::string &Name, unsigned Type, unsigned Flags = 0, unsigned Align = 0) { ELFSection *&SN = SectionLookup[Name]; if (SN) return *SN; - SectionList.push_back(ELFSection(Name, isLittleEndian, is64Bit)); + // 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); + + SectionList.push_back(ELFSection(SectionName, isLittleEndian, is64Bit)); SN = &SectionList.back(); SN->SectionIdx = NumSections++; SN->Type = Type; @@ -119,11 +140,25 @@ namespace llvm { return *SN; } + /// TODO: support mangled names here to emit the right .text section + /// for c++ object files. ELFSection &getTextSection() { return getSection(".text", ELFSection::SHT_PROGBITS, ELFSection::SHF_EXECINSTR | ELFSection::SHF_ALLOC); } + /// Return the relocation section of section 'S'. 'RelA' is true + /// if the relocation section contains entries with addends. + ELFSection &getRelocSection(std::string SName, bool RelA) { + std::string RelSName(".rel"); + unsigned SHdrTy = RelA ? ELFSection::SHT_RELA : ELFSection::SHT_REL; + + if (RelA) RelSName.append("a"); + RelSName.append(SName); + + return getSection(RelSName, SHdrTy, 0, TEW->getPrefELFAlignment()); + } + ELFSection &getNonExecStackSection() { return getSection(".note.GNU-stack", ELFSection::SHT_PROGBITS, 0, 1); } @@ -146,15 +181,9 @@ namespace llvm { ELFSection::SHF_WRITE | ELFSection::SHF_ALLOC); } - /// SymbolList - 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 SymbolList; - - /// PendingGlobals - List of externally defined symbols that we have been - /// asked to emit, but have not seen a reference to. When a reference - /// is seen, the symbol will move from this list to the SymbolList. - SetVector PendingGlobals; + ELFSection &getNullSection() { + return getSection("", ELFSection::SHT_NULL, 0); + } // 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 @@ -165,11 +194,15 @@ namespace llvm { unsigned ELFHdr_e_shnum_Offset; // e_shnum in ELF header. private: - void EmitGlobal(GlobalVariable *GV); + void EmitFunctionDeclaration(const Function *F); + void EmitGlobalVar(const GlobalVariable *GV); void EmitGlobalConstant(const Constant *C, ELFSection &GblS); void EmitGlobalConstantStruct(const ConstantStruct *CVS, ELFSection &GblS); + unsigned getGlobalELFLinkage(const GlobalVariable *GV); + ELFSection &getGlobalSymELFSection(const GlobalVariable *GV, ELFSym &Sym); void EmitRelocations(); + void EmitRelocation(BinaryObject &RelSec, ELFRelocation &Rel, bool HasRelA); void EmitSectionHeader(BinaryObject &SHdrTab, const ELFSection &SHdr); void EmitSectionTableStringTable(); void EmitSymbol(BinaryObject &SymbolTable, ELFSym &Sym); diff --git a/llvm/lib/Target/X86/X86ELFWriterInfo.cpp b/llvm/lib/Target/X86/X86ELFWriterInfo.cpp index d84034b9ed4f..315118f61091 100644 --- a/llvm/lib/Target/X86/X86ELFWriterInfo.cpp +++ b/llvm/lib/Target/X86/X86ELFWriterInfo.cpp @@ -12,11 +12,17 @@ //===----------------------------------------------------------------------===// #include "X86ELFWriterInfo.h" +#include "X86Relocations.h" #include "llvm/Function.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" + using namespace llvm; +//===----------------------------------------------------------------------===// +// Implementation of the X86ELFWriterInfo class +//===----------------------------------------------------------------------===// + X86ELFWriterInfo::X86ELFWriterInfo(TargetMachine &TM) : TargetELFWriterInfo(TM) { bool is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; @@ -25,6 +31,34 @@ X86ELFWriterInfo::X86ELFWriterInfo(TargetMachine &TM) X86ELFWriterInfo::~X86ELFWriterInfo() {} +unsigned X86ELFWriterInfo::getRelocationType(unsigned MachineRelTy) const { + if (is64Bit) { + switch(MachineRelTy) { + case X86::reloc_pcrel_word: + return R_X86_64_PC32; + case X86::reloc_absolute_word: + return R_X86_64_32; + case X86::reloc_absolute_dword: + return R_X86_64_64; + case X86::reloc_picrel_word: + default: + assert(0 && "unknown relocation type"); + } + } else { + switch(MachineRelTy) { + case X86::reloc_pcrel_word: + return R_386_PC32; + case X86::reloc_absolute_word: + return R_386_32; + case X86::reloc_absolute_dword: + case X86::reloc_picrel_word: + default: + assert(0 && "unknown relocation type"); + } + } + return 0; +} + unsigned X86ELFWriterInfo::getFunctionAlignment(const Function *F) const { unsigned FnAlign = 4; @@ -36,3 +70,15 @@ unsigned X86ELFWriterInfo::getFunctionAlignment(const Function *F) const { return (1 << FnAlign); } + +long int X86ELFWriterInfo::getAddendForRelTy(unsigned RelTy) const { + if (is64Bit) { + switch(RelTy) { + case R_X86_64_PC32: return -4; + break; + default: + assert(0 && "unknown x86 relocation type"); + } + } + return 0; +} diff --git a/llvm/lib/Target/X86/X86ELFWriterInfo.h b/llvm/lib/Target/X86/X86ELFWriterInfo.h index e9c5bc45cba3..96485b897071 100644 --- a/llvm/lib/Target/X86/X86ELFWriterInfo.h +++ b/llvm/lib/Target/X86/X86ELFWriterInfo.h @@ -19,11 +19,43 @@ namespace llvm { class X86ELFWriterInfo : public TargetELFWriterInfo { + + // ELF Relocation types for X86 + enum X86RelocationType { + R_386_NONE = 0, + R_386_32 = 1, + R_386_PC32 = 2 + }; + + // ELF Relocation types for X86_64 + enum X86_64RelocationType { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_PC64 = 24 + }; + public: X86ELFWriterInfo(TargetMachine &TM); virtual ~X86ELFWriterInfo(); + /// getFunctionAlignment - Returns the alignment for function 'F', targets + /// with different alignment constraints should overload this method virtual unsigned getFunctionAlignment(const Function *F) const; + + /// getRelocationType - Returns the target specific ELF Relocation type. + /// 'MachineRelTy' contains the object code independent relocation type + virtual unsigned getRelocationType(unsigned MachineRelTy) const; + + /// hasRelocationAddend - True if the target uses an addend in the + /// ELF relocation entry. + virtual bool hasRelocationAddend() const { return is64Bit ? true : false; } + + /// getAddendForRelTy - Gets the addend value for an ELF relocation entry + /// based on the target relocation type + virtual long int getAddendForRelTy(unsigned RelTy) const; }; } // end llvm namespace