mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-19 18:10:14 +00:00
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:
parent
cf1e764a1c
commit
3e0094d969
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user