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
This commit is contained in:
Bruno Cardoso Lopes 2009-08-08 17:29:04 +00:00
parent cf1e764a1c
commit 3e0094d969
4 changed files with 114 additions and 58 deletions

View File

@ -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) {

View File

@ -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;

View File

@ -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()) {

View File

@ -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();