summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2009-08-08 17:29:04 +0000
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>2009-08-08 17:29:04 +0000
commit3e0094d9694a27c9e925f789fa26e740dc445fbe (patch)
treebf79d815b7a022383924549bd9eab653bc9daae5
parentcf1e764a1c1a15f3710ca41ecad5662527fca21f (diff)
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.h20
-rw-r--r--lib/CodeGen/ELF.h6
-rw-r--r--lib/CodeGen/ELFWriter.cpp140
-rw-r--r--lib/CodeGen/ELFWriter.h6
4 files changed, 114 insertions, 58 deletions
diff --git a/include/llvm/CodeGen/BinaryObject.h b/include/llvm/CodeGen/BinaryObject.h
index 542a177529e..2d4bd73a82e 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 499af10c79e..c9ec9b1912b 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 93e84154162..42fe56df616 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 fe726524d32..362c278472d 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();