diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2009-08-08 17:29:04 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2009-08-08 17:29:04 +0000 |
commit | 3e0094d9694a27c9e925f789fa26e740dc445fbe (patch) | |
tree | bf79d815b7a022383924549bd9eab653bc9daae5 | |
parent | cf1e764a1c1a15f3710ca41ecad5662527fca21f (diff) | |
download | external_llvm-3e0094d9694a27c9e925f789fa26e740dc445fbe.zip external_llvm-3e0094d9694a27c9e925f789fa26e740dc445fbe.tar.gz external_llvm-3e0094d9694a27c9e925f789fa26e740dc445fbe.tar.bz2 |
ELF improvements:
Handle large integers, x86_fp80, ConstantAggregateZero, and two more ConstantExpr:
GetElementPtr and IntToPtr
Set SHF_MERGE bit for mergeable strings
Avoid zero initialized strings to be classified as a bss symbol
Don't allow common symbols to be classified as STB_WEAK
Add a constant to be used as a global value offset in data relocations
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78476 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/CodeGen/BinaryObject.h | 20 | ||||
-rw-r--r-- | lib/CodeGen/ELF.h | 6 | ||||
-rw-r--r-- | lib/CodeGen/ELFWriter.cpp | 140 | ||||
-rw-r--r-- | lib/CodeGen/ELFWriter.h | 6 |
4 files changed, 114 insertions, 58 deletions
diff --git a/include/llvm/CodeGen/BinaryObject.h b/include/llvm/CodeGen/BinaryObject.h index 542a177..2d4bd73 100644 --- a/include/llvm/CodeGen/BinaryObject.h +++ b/include/llvm/CodeGen/BinaryObject.h @@ -68,6 +68,13 @@ public: return !Relocations.empty(); } + /// emitZeros - This callback is invoked to emit a arbitrary number + /// of zero bytes to the data stream. + inline void emitZeros(unsigned Size) { + for (unsigned i=0; i < Size; ++i) + emitByte(0); + } + /// emitByte - This callback is invoked when a byte needs to be /// written to the data stream. inline void emitByte(uint8_t B) { @@ -124,6 +131,19 @@ public: emitDWordBE(W); } + /// emitWord64 - This callback is invoked when a x86_fp80 needs to be + /// written to the data stream in correct endian format. + inline void emitWordFP80(const uint64_t *W, unsigned PadSize) { + if (IsLittleEndian) { + emitWord64(W[0]); + emitWord16(W[1]); + } else { + emitWord16(W[1]); + emitWord64(W[0]); + } + emitZeros(PadSize); + } + /// emitWordLE - This callback is invoked when a 32-bit word needs to be /// written to the data stream in little-endian format. inline void emitWordLE(uint32_t W) { diff --git a/lib/CodeGen/ELF.h b/lib/CodeGen/ELF.h index 499af10..c9ec9b1 100644 --- a/lib/CodeGen/ELF.h +++ b/lib/CodeGen/ELF.h @@ -136,11 +136,11 @@ namespace llvm { return Sym; } - // getFileSym - Returns a elf symbol to represent the module identifier - static ELFSym *getUndefGV(const GlobalValue *GV) { + // getUndefGV - Returns a STT_NOTYPE symbol + static ELFSym *getUndefGV(const GlobalValue *GV, unsigned Bind) { ELFSym *Sym = new ELFSym(); Sym->Source.GV = GV; - Sym->setBind(STB_GLOBAL); + Sym->setBind(Bind); Sym->setType(STT_NOTYPE); Sym->setVisibility(STV_DEFAULT); Sym->SectionIdx = 0; //ELFSection::SHN_UNDEF; diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index 93e8415..42fe56d 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -265,7 +265,7 @@ unsigned ELFWriter::getGlobalELFBinding(const GlobalValue *GV) { if (GV->hasInternalLinkage()) return ELFSym::STB_LOCAL; - if (GV->isWeakForLinker()) + if (GV->isWeakForLinker() && !GV->hasCommonLinkage()) return ELFSym::STB_WEAK; return ELFSym::STB_GLOBAL; @@ -293,7 +293,7 @@ unsigned ELFWriter::getElfSectionFlags(SectionKind Kind, bool IsAlloc) { ElfSectionFlags |= ELFSection::SHF_EXECINSTR; if (Kind.isWriteable()) ElfSectionFlags |= ELFSection::SHF_WRITE; - if (Kind.isMergeableConst()) + if (Kind.isMergeableConst() || Kind.isMergeableCString()) ElfSectionFlags |= ELFSection::SHF_MERGE; if (Kind.isThreadLocal()) ElfSectionFlags |= ELFSection::SHF_TLS; @@ -303,6 +303,12 @@ unsigned ELFWriter::getElfSectionFlags(SectionKind Kind, bool IsAlloc) { return ElfSectionFlags; } +// isUndefOrNull - The constant is either a null initialized value or an +// undefined one. +static bool isUndefOrNull(const Constant *CV) { + return (CV->isNullValue() || isa<UndefValue>(CV)); +} + // isELFUndefSym - the symbol has no section and must be placed in // the symbol table with a reference to the null section. static bool isELFUndefSym(const GlobalValue *GV) { @@ -312,22 +318,18 @@ static bool isELFUndefSym(const GlobalValue *GV) { // isELFBssSym - for an undef or null value, the symbol must go to a bss // section if it's not weak for linker, otherwise it's a common sym. -static bool isELFBssSym(const GlobalVariable *GV) { +static bool isELFBssSym(const GlobalVariable *GV, SectionKind Kind) { const Constant *CV = GV->getInitializer(); - return ((CV->isNullValue() || isa<UndefValue>(CV)) && !GV->isWeakForLinker()); + + return (!Kind.isMergeableCString() && + isUndefOrNull(CV) && + !GV->isWeakForLinker()); } // isELFCommonSym - for an undef or null value, the symbol must go to a // common section if it's weak for linker, otherwise bss. static bool isELFCommonSym(const GlobalVariable *GV) { - const Constant *CV = GV->getInitializer(); - return ((CV->isNullValue() || isa<UndefValue>(CV)) && GV->isWeakForLinker()); -} - -// isELFDataSym - if the symbol is an initialized but no null constant -// it must go to some kind of data section -static bool isELFDataSym(const Constant *CV) { - return (!(CV->isNullValue() || isa<UndefValue>(CV))); + return (isUndefOrNull(GV->getInitializer()) && GV->isWeakForLinker()); } // EmitGlobal - Choose the right section for global and emit it @@ -343,7 +345,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { // All undef symbols have the same binding, type and visibily and // are classified regardless of their type. - ELFSym *GblSym = isELFUndefSym(GV) ? ELFSym::getUndefGV(GV) + ELFSym *GblSym = isELFUndefSym(GV) ? ELFSym::getUndefGV(GV, SymBind) : ELFSym::getGV(GV, SymBind, SymType, getGlobalELFVisibility(GV)); if (!isELFUndefSym(GV)) { @@ -356,7 +358,8 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { // Get the ELF section where this global belongs from TLOF const MCSection *S = TLOF.SectionForGlobal(GV, Mang, TM); - unsigned SectionFlags = getElfSectionFlags(((MCSectionELF*)S)->getKind()); + SectionKind Kind = ((MCSectionELF*)S)->getKind(); + unsigned SectionFlags = getElfSectionFlags(Kind); // The symbol align should update the section alignment if needed const TargetData *TD = TM.getTargetData(); @@ -373,7 +376,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { // value contains its alignment. GblSym->Value = Align; - } else if (isELFBssSym(GVar)) { + } else if (isELFBssSym(GVar, Kind)) { ELFSection &ES = getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags); GblSym->SectionIdx = ES.SectionIdx; @@ -388,7 +391,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { GblSym->Value = ES.Size; ES.Size += Size; - } else if (isELFDataSym(GV)) { + } else { // The symbol must go to some kind of data section ELFSection &ES = getSection(S->getName(), ELFSection::SHT_PROGBITS, SectionFlags); GblSym->SectionIdx = ES.SectionIdx; @@ -396,8 +399,8 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { // GblSym->Value should contain the symbol offset inside the section, // and all symbols should start on their required alignment boundary ES.Align = std::max(ES.Align, Align); - GblSym->Value = (ES.size() + (Align-1)) & (-Align); - ES.emitAlignment(ES.Align); + ES.emitAlignment(Align); + GblSym->Value = ES.size(); // Emit the global to the data section 'ES' EmitGlobalConstant(GVar->getInitializer(), ES); @@ -441,8 +444,7 @@ void ELFWriter::EmitGlobalConstantStruct(const ConstantStruct *CVS, // Insert padding - this may include padding to increase the size of the // current field up to the ABI size (if the struct is not packed) as well // as padding to ensure that the next field starts at the right offset. - for (unsigned p=0; p < padSize; p++) - GblS.emitByte(0); + GblS.emitZeros(padSize); } assert(sizeSoFar == cvsLayout->getSizeInBytes() && "Layout of constant struct may be incorrect!"); @@ -453,36 +455,37 @@ void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) { unsigned Size = TD->getTypeAllocSize(CV->getType()); if (const ConstantArray *CVA = dyn_cast<ConstantArray>(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) - EmitGlobalConstant(CVA->getOperand(i), GblS); - } + for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i) + EmitGlobalConstant(CVA->getOperand(i), GblS); + return; + } else if (isa<ConstantAggregateZero>(CV)) { + GblS.emitZeros(Size); return; } else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) { EmitGlobalConstantStruct(CVS, GblS); return; } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) { - uint64_t Val = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); + APInt Val = CFP->getValueAPF().bitcastToAPInt(); if (CFP->getType() == Type::DoubleTy) - GblS.emitWord64(Val); + GblS.emitWord64(Val.getZExtValue()); else if (CFP->getType() == Type::FloatTy) - GblS.emitWord32(Val); + GblS.emitWord32(Val.getZExtValue()); else if (CFP->getType() == Type::X86_FP80Ty) { - llvm_unreachable("X86_FP80Ty global emission not implemented"); + unsigned PadSize = TD->getTypeAllocSize(Type::X86_FP80Ty)- + TD->getTypeStoreSize(Type::X86_FP80Ty); + GblS.emitWordFP80(Val.getRawData(), PadSize); } else if (CFP->getType() == Type::PPC_FP128Ty) llvm_unreachable("PPC_FP128Ty global emission not implemented"); return; } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) { - if (Size == 4) + if (Size == 1) + GblS.emitByte(CI->getZExtValue()); + else if (Size == 2) + GblS.emitWord16(CI->getZExtValue()); + else if (Size == 4) GblS.emitWord32(CI->getZExtValue()); - else if (Size == 8) - GblS.emitWord64(CI->getZExtValue()); - else - llvm_unreachable("LargeInt global emission not implemented"); + else + EmitGlobalConstantLargeInt(CI, GblS); return; } else if (const ConstantVector *CP = dyn_cast<ConstantVector>(CV)) { const VectorType *PTy = CP->getType(); @@ -490,28 +493,44 @@ void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) { EmitGlobalConstant(CP->getOperand(I), GblS); return; } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) { - if (CE->getOpcode() == Instruction::BitCast) { + switch (CE->getOpcode()) { + case Instruction::BitCast: { EmitGlobalConstant(CE->getOperand(0), GblS); return; } + case Instruction::GetElementPtr: { + const Constant *ptrVal = CE->getOperand(0); + SmallVector<Value*, 8> idxVec(CE->op_begin()+1, CE->op_end()); + int64_t Offset = TD->getIndexedOffset(ptrVal->getType(), &idxVec[0], + idxVec.size()); + EmitGlobalDataRelocation(cast<const GlobalValue>(ptrVal), + TD->getTypeAllocSize(ptrVal->getType()), + GblS, Offset); + return; + } + case Instruction::IntToPtr: { + Constant *Op = CE->getOperand(0); + Op = ConstantExpr::getIntegerCast(Op, TD->getIntPtrType(), false/*ZExt*/); + EmitGlobalConstant(Op, GblS); + return; + } + } std::string msg(CE->getOpcodeName()); raw_string_ostream ErrorMsg(msg); ErrorMsg << ": Unsupported ConstantExpr type"; llvm_report_error(ErrorMsg.str()); } else if (CV->getType()->getTypeID() == Type::PointerTyID) { // Fill the data entry with zeros or emit a relocation entry - if (isa<ConstantPointerNull>(CV)) { - for (unsigned i=0; i < Size; ++i) - GblS.emitByte(0); - } else { - emitGlobalDataRelocation(cast<const GlobalValue>(CV), - TD->getPointerSize(), GblS); - } + if (isa<ConstantPointerNull>(CV)) + GblS.emitZeros(Size); + else + EmitGlobalDataRelocation(cast<const GlobalValue>(CV), + Size, GblS); return; } else if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { // This is a constant address for a global variable or function and // therefore must be referenced using a relocation entry. - emitGlobalDataRelocation(GV, Size, GblS); + EmitGlobalDataRelocation(GV, Size, GblS); return; } @@ -521,22 +540,37 @@ void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) { llvm_report_error(ErrorMsg.str()); } -void ELFWriter::emitGlobalDataRelocation(const GlobalValue *GV, unsigned Size, - ELFSection &GblS) { +void ELFWriter::EmitGlobalDataRelocation(const GlobalValue *GV, unsigned Size, + ELFSection &GblS, uint64_t Offset) { // Create the relocation entry for the global value MachineRelocation MR = MachineRelocation::getGV(GblS.getCurrentPCOffset(), TEW->getAbsoluteLabelMachineRelTy(), - const_cast<GlobalValue*>(GV)); + const_cast<GlobalValue*>(GV), + Offset); // Fill the data entry with zeros - for (unsigned i=0; i < Size; ++i) - GblS.emitByte(0); + GblS.emitZeros(Size); // Add the relocation entry for the current data section GblS.addRelocation(MR); } +void ELFWriter::EmitGlobalConstantLargeInt(const ConstantInt *CI, + ELFSection &S) { + const TargetData *TD = TM.getTargetData(); + unsigned BitWidth = CI->getBitWidth(); + assert(isPowerOf2_32(BitWidth) && + "Non-power-of-2-sized integers not handled!"); + + const uint64_t *RawData = CI->getValue().getRawData(); + uint64_t Val = 0; + for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) { + Val = (TD->isBigEndian()) ? RawData[e - i - 1] : RawData[i]; + S.emitWord64(Val); + } +} + /// EmitSpecialLLVMGlobal - Check to see if the specified global is a /// special global used by LLVM. If so, emit it and return true, otherwise /// do nothing and return false. @@ -712,15 +746,15 @@ void ELFWriter::EmitRelocations() { // them needs a different approach to retrieve the symbol table index. if (MR.isGlobalValue()) { const GlobalValue *G = MR.getGlobalValue(); + int64_t GlobalOffset = MR.getConstantVal(); SymIdx = GblSymLookup[G]; if (G->hasPrivateLinkage()) { // If the target uses a section offset in the relocation: // SymIdx + Addend = section sym for global + section offset unsigned SectionIdx = PrivateSyms[SymIdx]->SectionIdx; - Addend = PrivateSyms[SymIdx]->Value; + Addend = PrivateSyms[SymIdx]->Value + GlobalOffset; SymIdx = SectionList[SectionIdx]->getSymbolTableIndex(); } else { - int64_t GlobalOffset = MR.getConstantVal(); Addend = TEW->getDefaultAddendForRelTy(RelType, GlobalOffset); } } else if (MR.isExternalSymbol()) { diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index fe72652..362c278 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -21,6 +21,7 @@ namespace llvm { class BinaryObject; class Constant; + class ConstantInt; class ConstantStruct; class ELFCodeEmitter; class ELFRelocation; @@ -248,8 +249,9 @@ namespace llvm { void EmitGlobalConstant(const Constant *C, ELFSection &GblS); void EmitGlobalConstantStruct(const ConstantStruct *CVS, ELFSection &GblS); - void emitGlobalDataRelocation(const GlobalValue *GV, unsigned Size, - ELFSection &GblS); + void EmitGlobalConstantLargeInt(const ConstantInt *CI, ELFSection &S); + void EmitGlobalDataRelocation(const GlobalValue *GV, unsigned Size, + ELFSection &GblS, uint64_t Offset = 0); bool EmitSpecialLLVMGlobal(const GlobalVariable *GV); void EmitXXStructorList(Constant *List, ELFSection &Xtor); void EmitRelocations(); |