mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
Add comdat key field to llvm.global_ctors and llvm.global_dtors
This allows us to put dynamic initializers for weak data into the same comdat group as the data being initialized. This is necessary for MSVC ABI compatibility. Once we have comdats for guard variables, we can use the combination to help GlobalOpt fire more often for weak data with guarded initialization on other platforms. Reviewers: nlewycky Differential Revision: http://reviews.llvm.org/D3499 llvm-svn: 209015
This commit is contained in:
parent
f942b6eb61
commit
fd1a7dfe04
@ -3152,14 +3152,18 @@ The '``llvm.global_ctors``' Global Variable
|
|||||||
|
|
||||||
.. code-block:: llvm
|
.. code-block:: llvm
|
||||||
|
|
||||||
%0 = type { i32, void ()* }
|
%0 = type { i32, void ()*, i8* }
|
||||||
@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @ctor }]
|
@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @ctor, i8* @data }]
|
||||||
|
|
||||||
The ``@llvm.global_ctors`` array contains a list of constructor
|
The ``@llvm.global_ctors`` array contains a list of constructor
|
||||||
functions and associated priorities. The functions referenced by this
|
functions, priorities, and an optional associated global or function.
|
||||||
array will be called in ascending order of priority (i.e. lowest first)
|
The functions referenced by this array will be called in ascending order
|
||||||
when the module is loaded. The order of functions with the same priority
|
of priority (i.e. lowest first) when the module is loaded. The order of
|
||||||
is not defined.
|
functions with the same priority is not defined.
|
||||||
|
|
||||||
|
If the third field is present, non-null, and points to a global variable
|
||||||
|
or function, the initializer function will only run if the associated
|
||||||
|
data from the current module is not discarded.
|
||||||
|
|
||||||
.. _llvmglobaldtors:
|
.. _llvmglobaldtors:
|
||||||
|
|
||||||
@ -3168,14 +3172,18 @@ The '``llvm.global_dtors``' Global Variable
|
|||||||
|
|
||||||
.. code-block:: llvm
|
.. code-block:: llvm
|
||||||
|
|
||||||
%0 = type { i32, void ()* }
|
%0 = type { i32, void ()*, i8* }
|
||||||
@llvm.global_dtors = appending global [1 x %0] [%0 { i32 65535, void ()* @dtor }]
|
@llvm.global_dtors = appending global [1 x %0] [%0 { i32 65535, void ()* @dtor, i8* @data }]
|
||||||
|
|
||||||
The ``@llvm.global_dtors`` array contains a list of destructor functions
|
The ``@llvm.global_dtors`` array contains a list of destructor
|
||||||
and associated priorities. The functions referenced by this array will
|
functions, priorities, and an optional associated global or function.
|
||||||
be called in descending order of priority (i.e. highest first) when the
|
The functions referenced by this array will be called in descending
|
||||||
module is loaded. The order of functions with the same priority is not
|
order of priority (i.e. highest first) when the module is loaded. The
|
||||||
defined.
|
order of functions with the same priority is not defined.
|
||||||
|
|
||||||
|
If the third field is present, non-null, and points to a global variable
|
||||||
|
or function, the destructor function will only run if the associated
|
||||||
|
data from the current module is not discarded.
|
||||||
|
|
||||||
Instruction Reference
|
Instruction Reference
|
||||||
=====================
|
=====================
|
||||||
|
@ -67,10 +67,12 @@ public:
|
|||||||
MachineModuleInfo *MMI) const override;
|
MachineModuleInfo *MMI) const override;
|
||||||
|
|
||||||
void InitializeELF(bool UseInitArray_);
|
void InitializeELF(bool UseInitArray_);
|
||||||
const MCSection *
|
const MCSection *getStaticCtorSection(unsigned Priority,
|
||||||
getStaticCtorSection(unsigned Priority = 65535) const override;
|
const MCSymbol *KeySym,
|
||||||
const MCSection *
|
const MCSection *KeySec) const override;
|
||||||
getStaticDtorSection(unsigned Priority = 65535) const override;
|
const MCSection *getStaticDtorSection(unsigned Priority,
|
||||||
|
const MCSymbol *KeySym,
|
||||||
|
const MCSection *KeySec) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -140,6 +142,13 @@ public:
|
|||||||
void emitModuleFlags(MCStreamer &Streamer,
|
void emitModuleFlags(MCStreamer &Streamer,
|
||||||
ArrayRef<Module::ModuleFlagEntry> ModuleFlags,
|
ArrayRef<Module::ModuleFlagEntry> ModuleFlags,
|
||||||
Mangler &Mang, const TargetMachine &TM) const override;
|
Mangler &Mang, const TargetMachine &TM) const override;
|
||||||
|
|
||||||
|
const MCSection *getStaticCtorSection(unsigned Priority,
|
||||||
|
const MCSymbol *KeySym,
|
||||||
|
const MCSection *KeySec) const override;
|
||||||
|
const MCSection *getStaticDtorSection(unsigned Priority,
|
||||||
|
const MCSymbol *KeySym,
|
||||||
|
const MCSection *KeySec) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -130,14 +130,15 @@ public:
|
|||||||
getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
|
getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
|
||||||
MCStreamer &Streamer) const;
|
MCStreamer &Streamer) const;
|
||||||
|
|
||||||
virtual const MCSection *
|
virtual const MCSection *getStaticCtorSection(unsigned Priority,
|
||||||
getStaticCtorSection(unsigned Priority = 65535) const {
|
const MCSymbol *KeySym,
|
||||||
(void)Priority;
|
const MCSection *KeySec) const {
|
||||||
return StaticCtorSection;
|
return StaticCtorSection;
|
||||||
}
|
}
|
||||||
virtual const MCSection *
|
|
||||||
getStaticDtorSection(unsigned Priority = 65535) const {
|
virtual const MCSection *getStaticDtorSection(unsigned Priority,
|
||||||
(void)Priority;
|
const MCSymbol *KeySym,
|
||||||
|
const MCSection *KeySec) const {
|
||||||
return StaticDtorSection;
|
return StaticDtorSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1700,8 +1700,11 @@ error_code BitcodeReader::GlobalCleanup() {
|
|||||||
// Look for global variables which need to be renamed.
|
// Look for global variables which need to be renamed.
|
||||||
for (Module::global_iterator
|
for (Module::global_iterator
|
||||||
GI = TheModule->global_begin(), GE = TheModule->global_end();
|
GI = TheModule->global_begin(), GE = TheModule->global_end();
|
||||||
GI != GE; ++GI)
|
GI != GE;) {
|
||||||
UpgradeGlobalVariable(GI);
|
GlobalVariable *GV = GI++;
|
||||||
|
UpgradeGlobalVariable(GV);
|
||||||
|
}
|
||||||
|
|
||||||
// Force deallocation of memory for these vectors to favor the client that
|
// Force deallocation of memory for these vectors to favor the client that
|
||||||
// want lazy deserialization.
|
// want lazy deserialization.
|
||||||
std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
|
std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
|
||||||
|
@ -1296,6 +1296,15 @@ void AsmPrinter::EmitLLVMUsedList(const ConstantArray *InitList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct Structor {
|
||||||
|
Structor() : Priority(0), Func(nullptr), ComdatKey(nullptr) {}
|
||||||
|
int Priority;
|
||||||
|
llvm::Constant *Func;
|
||||||
|
llvm::GlobalValue *ComdatKey;
|
||||||
|
};
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init
|
/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init
|
||||||
/// priority.
|
/// priority.
|
||||||
void AsmPrinter::EmitXXStructorList(const Constant *List, bool isCtor) {
|
void AsmPrinter::EmitXXStructorList(const Constant *List, bool isCtor) {
|
||||||
@ -1307,37 +1316,52 @@ void AsmPrinter::EmitXXStructorList(const Constant *List, bool isCtor) {
|
|||||||
const ConstantArray *InitList = dyn_cast<ConstantArray>(List);
|
const ConstantArray *InitList = dyn_cast<ConstantArray>(List);
|
||||||
if (!InitList) return; // Not an array!
|
if (!InitList) return; // Not an array!
|
||||||
StructType *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
|
StructType *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
|
||||||
if (!ETy || ETy->getNumElements() != 2) return; // Not an array of pairs!
|
// FIXME: Only allow the 3-field form in LLVM 4.0.
|
||||||
|
if (!ETy || ETy->getNumElements() < 2 || ETy->getNumElements() > 3)
|
||||||
|
return; // Not an array of two or three elements!
|
||||||
if (!isa<IntegerType>(ETy->getTypeAtIndex(0U)) ||
|
if (!isa<IntegerType>(ETy->getTypeAtIndex(0U)) ||
|
||||||
!isa<PointerType>(ETy->getTypeAtIndex(1U))) return; // Not (int, ptr).
|
!isa<PointerType>(ETy->getTypeAtIndex(1U))) return; // Not (int, ptr).
|
||||||
|
if (ETy->getNumElements() == 3 && !isa<PointerType>(ETy->getTypeAtIndex(2U)))
|
||||||
|
return; // Not (int, ptr, ptr).
|
||||||
|
|
||||||
// Gather the structors in a form that's convenient for sorting by priority.
|
// Gather the structors in a form that's convenient for sorting by priority.
|
||||||
typedef std::pair<unsigned, Constant *> Structor;
|
|
||||||
SmallVector<Structor, 8> Structors;
|
SmallVector<Structor, 8> Structors;
|
||||||
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
for (Value *O : InitList->operands()) {
|
||||||
ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i));
|
ConstantStruct *CS = dyn_cast<ConstantStruct>(O);
|
||||||
if (!CS) continue; // Malformed.
|
if (!CS) continue; // Malformed.
|
||||||
if (CS->getOperand(1)->isNullValue())
|
if (CS->getOperand(1)->isNullValue())
|
||||||
break; // Found a null terminator, skip the rest.
|
break; // Found a null terminator, skip the rest.
|
||||||
ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
|
ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
|
||||||
if (!Priority) continue; // Malformed.
|
if (!Priority) continue; // Malformed.
|
||||||
Structors.push_back(std::make_pair(Priority->getLimitedValue(65535),
|
Structors.push_back(Structor());
|
||||||
CS->getOperand(1)));
|
Structor &S = Structors.back();
|
||||||
|
S.Priority = Priority->getLimitedValue(65535);
|
||||||
|
S.Func = CS->getOperand(1);
|
||||||
|
if (ETy->getNumElements() == 3 && !CS->getOperand(2)->isNullValue())
|
||||||
|
S.ComdatKey = dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the function pointers in the target-specific order
|
// Emit the function pointers in the target-specific order
|
||||||
const DataLayout *DL = TM.getDataLayout();
|
const DataLayout *DL = TM.getDataLayout();
|
||||||
unsigned Align = Log2_32(DL->getPointerPrefAlignment());
|
unsigned Align = Log2_32(DL->getPointerPrefAlignment());
|
||||||
std::stable_sort(Structors.begin(), Structors.end(), less_first());
|
std::stable_sort(Structors.begin(), Structors.end(),
|
||||||
for (unsigned i = 0, e = Structors.size(); i != e; ++i) {
|
[](const Structor &L,
|
||||||
|
const Structor &R) { return L.Priority < R.Priority; });
|
||||||
|
for (Structor &S : Structors) {
|
||||||
|
const TargetLoweringObjectFile &Obj = getObjFileLowering();
|
||||||
|
const MCSymbol *KeySym = nullptr;
|
||||||
|
const MCSection *KeySec = nullptr;
|
||||||
|
if (S.ComdatKey) {
|
||||||
|
KeySym = getSymbol(S.ComdatKey);
|
||||||
|
KeySec = getObjFileLowering().SectionForGlobal(S.ComdatKey, *Mang, TM);
|
||||||
|
}
|
||||||
const MCSection *OutputSection =
|
const MCSection *OutputSection =
|
||||||
(isCtor ?
|
(isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym, KeySec)
|
||||||
getObjFileLowering().getStaticCtorSection(Structors[i].first) :
|
: Obj.getStaticDtorSection(S.Priority, KeySym, KeySec));
|
||||||
getObjFileLowering().getStaticDtorSection(Structors[i].first));
|
|
||||||
OutStreamer.SwitchSection(OutputSection);
|
OutStreamer.SwitchSection(OutputSection);
|
||||||
if (OutStreamer.getCurrentSection() != OutStreamer.getPreviousSection())
|
if (OutStreamer.getCurrentSection() != OutStreamer.getPreviousSection())
|
||||||
EmitAlignment(Align);
|
EmitAlignment(Align);
|
||||||
EmitXXStructor(Structors[i].second);
|
EmitXXStructor(S.Func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,8 +339,8 @@ getSectionForConstant(SectionKind Kind) const {
|
|||||||
return DataRelROSection;
|
return DataRelROSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCSection *
|
const MCSection *TargetLoweringObjectFileELF::getStaticCtorSection(
|
||||||
TargetLoweringObjectFileELF::getStaticCtorSection(unsigned Priority) const {
|
unsigned Priority, const MCSymbol *KeySym, const MCSection *KeySec) const {
|
||||||
// The default scheme is .ctor / .dtor, so we have to invert the priority
|
// The default scheme is .ctor / .dtor, so we have to invert the priority
|
||||||
// numbering.
|
// numbering.
|
||||||
if (Priority == 65535)
|
if (Priority == 65535)
|
||||||
@ -359,8 +359,8 @@ TargetLoweringObjectFileELF::getStaticCtorSection(unsigned Priority) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCSection *
|
const MCSection *TargetLoweringObjectFileELF::getStaticDtorSection(
|
||||||
TargetLoweringObjectFileELF::getStaticDtorSection(unsigned Priority) const {
|
unsigned Priority, const MCSymbol *KeySym, const MCSection *KeySec) const {
|
||||||
// The default scheme is .ctor / .dtor, so we have to invert the priority
|
// The default scheme is .ctor / .dtor, so we have to invert the priority
|
||||||
// numbering.
|
// numbering.
|
||||||
if (Priority == 65535)
|
if (Priority == 65535)
|
||||||
@ -865,3 +865,32 @@ emitModuleFlags(MCStreamer &Streamer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const MCSection *getAssociativeCOFFSection(MCContext &Ctx,
|
||||||
|
const MCSection *Sec,
|
||||||
|
const MCSymbol *KeySym,
|
||||||
|
const MCSection *KeySec) {
|
||||||
|
// Return the normal section if we don't have to be associative.
|
||||||
|
if (!KeySym)
|
||||||
|
return Sec;
|
||||||
|
|
||||||
|
// Make an associative section with the same name and kind as the normal
|
||||||
|
// section.
|
||||||
|
const MCSectionCOFF *SecCOFF = cast<MCSectionCOFF>(Sec);
|
||||||
|
const MCSectionCOFF *KeySecCOFF = cast<MCSectionCOFF>(KeySec);
|
||||||
|
unsigned Characteristics =
|
||||||
|
SecCOFF->getCharacteristics() | COFF::IMAGE_SCN_LNK_COMDAT;
|
||||||
|
return Ctx.getCOFFSection(SecCOFF->getSectionName(), Characteristics,
|
||||||
|
SecCOFF->getKind(), KeySym->getName(),
|
||||||
|
COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE, KeySecCOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MCSection *TargetLoweringObjectFileCOFF::getStaticCtorSection(
|
||||||
|
unsigned Priority, const MCSymbol *KeySym, const MCSection *KeySec) const {
|
||||||
|
return getAssociativeCOFFSection(getContext(), StaticCtorSection, KeySym, KeySec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection(
|
||||||
|
unsigned Priority, const MCSymbol *KeySym, const MCSection *KeySec) const {
|
||||||
|
return getAssociativeCOFFSection(getContext(), StaticDtorSection, KeySym, KeySec);
|
||||||
|
}
|
||||||
|
@ -170,7 +170,59 @@ bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn) {
|
|||||||
return Upgraded;
|
return Upgraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool UpgradeGlobalStructors(GlobalVariable *GV) {
|
||||||
|
ArrayType *ATy = dyn_cast<ArrayType>(GV->getType()->getElementType());
|
||||||
|
StructType *OldTy =
|
||||||
|
ATy ? dyn_cast<StructType>(ATy->getElementType()) : nullptr;
|
||||||
|
|
||||||
|
// Only upgrade an array of a two field struct with the appropriate field
|
||||||
|
// types.
|
||||||
|
if (!OldTy || OldTy->getNumElements() != 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Get the upgraded 3 element type.
|
||||||
|
PointerType *VoidPtrTy = Type::getInt8Ty(GV->getContext())->getPointerTo();
|
||||||
|
Type *Tys[3] = {
|
||||||
|
OldTy->getElementType(0),
|
||||||
|
OldTy->getElementType(1),
|
||||||
|
VoidPtrTy
|
||||||
|
};
|
||||||
|
StructType *NewTy =
|
||||||
|
StructType::get(GV->getContext(), Tys, /*isPacked=*/false);
|
||||||
|
|
||||||
|
// Build new constants with a null third field filled in.
|
||||||
|
ConstantArray *OldInit = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||||
|
if (!OldInit)
|
||||||
|
return false;
|
||||||
|
std::vector<Constant *> Initializers;
|
||||||
|
for (Use &U : OldInit->operands()) {
|
||||||
|
ConstantStruct *Init = cast<ConstantStruct>(&U);
|
||||||
|
Constant *NewInit =
|
||||||
|
ConstantStruct::get(NewTy, Init->getOperand(0), Init->getOperand(1),
|
||||||
|
Constant::getNullValue(VoidPtrTy), nullptr);
|
||||||
|
Initializers.push_back(NewInit);
|
||||||
|
}
|
||||||
|
assert(Initializers.size() == ATy->getNumElements());
|
||||||
|
|
||||||
|
// Replace the old GV with a new one.
|
||||||
|
ATy = ArrayType::get(NewTy, Initializers.size());
|
||||||
|
Constant *NewInit = ConstantArray::get(ATy, Initializers);
|
||||||
|
GlobalVariable *NewGV = new GlobalVariable(
|
||||||
|
*GV->getParent(), ATy, GV->isConstant(), GV->getLinkage(), NewInit, "",
|
||||||
|
GV, GV->getThreadLocalMode(), GV->getType()->getAddressSpace(),
|
||||||
|
GV->isExternallyInitialized());
|
||||||
|
NewGV->copyAttributesFrom(GV);
|
||||||
|
NewGV->takeName(GV);
|
||||||
|
assert(GV->use_empty() && "program cannot use initializer list");
|
||||||
|
GV->eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool llvm::UpgradeGlobalVariable(GlobalVariable *GV) {
|
bool llvm::UpgradeGlobalVariable(GlobalVariable *GV) {
|
||||||
|
if (GV->getName() == "llvm.global_ctors" ||
|
||||||
|
GV->getName() == "llvm.global_dtors")
|
||||||
|
return UpgradeGlobalStructors(GV);
|
||||||
|
|
||||||
// Nothing to do yet.
|
// Nothing to do yet.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -396,14 +396,22 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
|
|||||||
"invalid linkage for intrinsic global variable", &GV);
|
"invalid linkage for intrinsic global variable", &GV);
|
||||||
// Don't worry about emitting an error for it not being an array,
|
// Don't worry about emitting an error for it not being an array,
|
||||||
// visitGlobalValue will complain on appending non-array.
|
// visitGlobalValue will complain on appending non-array.
|
||||||
if (ArrayType *ATy = dyn_cast<ArrayType>(GV.getType())) {
|
if (ArrayType *ATy = dyn_cast<ArrayType>(GV.getType()->getElementType())) {
|
||||||
StructType *STy = dyn_cast<StructType>(ATy->getElementType());
|
StructType *STy = dyn_cast<StructType>(ATy->getElementType());
|
||||||
PointerType *FuncPtrTy =
|
PointerType *FuncPtrTy =
|
||||||
FunctionType::get(Type::getVoidTy(*Context), false)->getPointerTo();
|
FunctionType::get(Type::getVoidTy(*Context), false)->getPointerTo();
|
||||||
Assert1(STy && STy->getNumElements() == 2 &&
|
// FIXME: Reject the 2-field form in LLVM 4.0.
|
||||||
|
Assert1(STy && (STy->getNumElements() == 2 ||
|
||||||
|
STy->getNumElements() == 3) &&
|
||||||
STy->getTypeAtIndex(0u)->isIntegerTy(32) &&
|
STy->getTypeAtIndex(0u)->isIntegerTy(32) &&
|
||||||
STy->getTypeAtIndex(1) == FuncPtrTy,
|
STy->getTypeAtIndex(1) == FuncPtrTy,
|
||||||
"wrong type for intrinsic global variable", &GV);
|
"wrong type for intrinsic global variable", &GV);
|
||||||
|
if (STy->getNumElements() == 3) {
|
||||||
|
Type *ETy = STy->getTypeAtIndex(2);
|
||||||
|
Assert1(ETy->isPointerTy() &&
|
||||||
|
cast<PointerType>(ETy)->getElementType()->isIntegerTy(8),
|
||||||
|
"wrong type for intrinsic global variable", &GV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +155,8 @@ bool ObjCARCAPElim::runOnModule(Module &M) {
|
|||||||
for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end();
|
for (User::op_iterator OI = Init->op_begin(), OE = Init->op_end();
|
||||||
OI != OE; ++OI) {
|
OI != OE; ++OI) {
|
||||||
Value *Op = *OI;
|
Value *Op = *OI;
|
||||||
// llvm.global_ctors is an array of pairs where the second members
|
// llvm.global_ctors is an array of three-field structs where the second
|
||||||
// are constructor functions.
|
// members are constructor functions.
|
||||||
Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1));
|
Function *F = dyn_cast<Function>(cast<ConstantStruct>(Op)->getOperand(1));
|
||||||
// If the user used a constructor function with the wrong signature and
|
// If the user used a constructor function with the wrong signature and
|
||||||
// it got bitcasted or whatever, look the other way.
|
// it got bitcasted or whatever, look the other way.
|
||||||
|
@ -29,26 +29,28 @@ namespace {
|
|||||||
void installGlobalCtors(GlobalVariable *GCL,
|
void installGlobalCtors(GlobalVariable *GCL,
|
||||||
const std::vector<Function *> &Ctors) {
|
const std::vector<Function *> &Ctors) {
|
||||||
// If we made a change, reassemble the initializer list.
|
// If we made a change, reassemble the initializer list.
|
||||||
Constant *CSVals[2];
|
Constant *CSVals[3];
|
||||||
CSVals[0] = ConstantInt::get(Type::getInt32Ty(GCL->getContext()), 65535);
|
|
||||||
CSVals[1] = nullptr;
|
|
||||||
|
|
||||||
StructType *StructTy =
|
StructType *StructTy =
|
||||||
cast<StructType>(GCL->getType()->getElementType()->getArrayElementType());
|
cast<StructType>(GCL->getType()->getElementType()->getArrayElementType());
|
||||||
|
|
||||||
// Create the new init list.
|
// Create the new init list.
|
||||||
std::vector<Constant *> CAList;
|
std::vector<Constant *> CAList;
|
||||||
for (unsigned i = 0, e = Ctors.size(); i != e; ++i) {
|
for (Function *F : Ctors) {
|
||||||
if (Ctors[i]) {
|
Type *Int32Ty = Type::getInt32Ty(GCL->getContext());
|
||||||
CSVals[1] = Ctors[i];
|
if (F) {
|
||||||
|
CSVals[0] = ConstantInt::get(Int32Ty, 65535);
|
||||||
|
CSVals[1] = F;
|
||||||
} else {
|
} else {
|
||||||
Type *FTy = FunctionType::get(Type::getVoidTy(GCL->getContext()), false);
|
CSVals[0] = ConstantInt::get(Int32Ty, 0x7fffffff);
|
||||||
PointerType *PFTy = PointerType::getUnqual(FTy);
|
CSVals[1] = Constant::getNullValue(StructTy->getElementType(1));
|
||||||
CSVals[1] = Constant::getNullValue(PFTy);
|
|
||||||
CSVals[0] =
|
|
||||||
ConstantInt::get(Type::getInt32Ty(GCL->getContext()), 0x7fffffff);
|
|
||||||
}
|
}
|
||||||
CAList.push_back(ConstantStruct::get(StructTy, CSVals));
|
// FIXME: Only allow the 3-field form in LLVM 4.0.
|
||||||
|
size_t NumElts = StructTy->getNumElements();
|
||||||
|
if (NumElts > 2)
|
||||||
|
CSVals[2] = Constant::getNullValue(StructTy->getElementType(2));
|
||||||
|
CAList.push_back(
|
||||||
|
ConstantStruct::get(StructTy, makeArrayRef(CSVals, NumElts)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the array initializer.
|
// Create the array initializer.
|
||||||
|
@ -24,16 +24,16 @@ static void appendToGlobalArray(const char *Array,
|
|||||||
Module &M, Function *F, int Priority) {
|
Module &M, Function *F, int Priority) {
|
||||||
IRBuilder<> IRB(M.getContext());
|
IRBuilder<> IRB(M.getContext());
|
||||||
FunctionType *FnTy = FunctionType::get(IRB.getVoidTy(), false);
|
FunctionType *FnTy = FunctionType::get(IRB.getVoidTy(), false);
|
||||||
StructType *Ty = StructType::get(
|
|
||||||
IRB.getInt32Ty(), PointerType::getUnqual(FnTy), NULL);
|
|
||||||
|
|
||||||
Constant *RuntimeCtorInit = ConstantStruct::get(
|
|
||||||
Ty, IRB.getInt32(Priority), F, NULL);
|
|
||||||
|
|
||||||
// Get the current set of static global constructors and add the new ctor
|
// Get the current set of static global constructors and add the new ctor
|
||||||
// to the list.
|
// to the list.
|
||||||
SmallVector<Constant *, 16> CurrentCtors;
|
SmallVector<Constant *, 16> CurrentCtors;
|
||||||
if (GlobalVariable * GVCtor = M.getNamedGlobal(Array)) {
|
StructType *EltTy;
|
||||||
|
if (GlobalVariable *GVCtor = M.getNamedGlobal(Array)) {
|
||||||
|
// If there is a global_ctors array, use the existing struct type, which can
|
||||||
|
// have 2 or 3 fields.
|
||||||
|
ArrayType *ATy = cast<ArrayType>(GVCtor->getType()->getElementType());
|
||||||
|
EltTy = cast<StructType>(ATy->getElementType());
|
||||||
if (Constant *Init = GVCtor->getInitializer()) {
|
if (Constant *Init = GVCtor->getInitializer()) {
|
||||||
unsigned n = Init->getNumOperands();
|
unsigned n = Init->getNumOperands();
|
||||||
CurrentCtors.reserve(n + 1);
|
CurrentCtors.reserve(n + 1);
|
||||||
@ -41,13 +41,26 @@ static void appendToGlobalArray(const char *Array,
|
|||||||
CurrentCtors.push_back(cast<Constant>(Init->getOperand(i)));
|
CurrentCtors.push_back(cast<Constant>(Init->getOperand(i)));
|
||||||
}
|
}
|
||||||
GVCtor->eraseFromParent();
|
GVCtor->eraseFromParent();
|
||||||
|
} else {
|
||||||
|
// Use a simple two-field struct if there isn't one already.
|
||||||
|
EltTy = StructType::get(IRB.getInt32Ty(), PointerType::getUnqual(FnTy),
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a 2 or 3 field global_ctor entry. We don't take a comdat key.
|
||||||
|
Constant *CSVals[3];
|
||||||
|
CSVals[0] = IRB.getInt32(Priority);
|
||||||
|
CSVals[1] = F;
|
||||||
|
// FIXME: Drop support for the two element form in LLVM 4.0.
|
||||||
|
if (EltTy->getNumElements() >= 3)
|
||||||
|
CSVals[2] = llvm::Constant::getNullValue(IRB.getInt8PtrTy());
|
||||||
|
Constant *RuntimeCtorInit =
|
||||||
|
ConstantStruct::get(EltTy, makeArrayRef(CSVals, EltTy->getNumElements()));
|
||||||
|
|
||||||
CurrentCtors.push_back(RuntimeCtorInit);
|
CurrentCtors.push_back(RuntimeCtorInit);
|
||||||
|
|
||||||
// Create a new initializer.
|
// Create a new initializer.
|
||||||
ArrayType *AT = ArrayType::get(RuntimeCtorInit->getType(),
|
ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size());
|
||||||
CurrentCtors.size());
|
|
||||||
Constant *NewInit = ConstantArray::get(AT, CurrentCtors);
|
Constant *NewInit = ConstantArray::get(AT, CurrentCtors);
|
||||||
|
|
||||||
// Create the new global variable and replace all uses of
|
// Create the new global variable and replace all uses of
|
||||||
|
BIN
test/Linker/Inputs/old_global_ctors.3.4.bc
Normal file
BIN
test/Linker/Inputs/old_global_ctors.3.4.bc
Normal file
Binary file not shown.
29
test/Linker/global_ctors.ll
Normal file
29
test/Linker/global_ctors.ll
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
; RUN: llvm-as %s -o %t.new.bc
|
||||||
|
; RUN: llvm-link %t.new.bc %S/Inputs/old_global_ctors.3.4.bc | llvm-dis | FileCheck %s
|
||||||
|
|
||||||
|
; old_global_ctors.3.4.bc contains the following LLVM IL, assembled into
|
||||||
|
; bitcode by llvm-as from 3.4. It uses a two element @llvm.global_ctors array.
|
||||||
|
; ---
|
||||||
|
; declare void @a_global_ctor()
|
||||||
|
; declare void @b_global_ctor()
|
||||||
|
;
|
||||||
|
; @llvm.global_ctors = appending global [2 x { i32, void ()* } ] [
|
||||||
|
; { i32, void ()* } { i32 65535, void ()* @a_global_ctor },
|
||||||
|
; { i32, void ()* } { i32 65535, void ()* @b_global_ctor }
|
||||||
|
; ]
|
||||||
|
; ---
|
||||||
|
|
||||||
|
declare void @c_global_ctor()
|
||||||
|
declare void @d_global_ctor()
|
||||||
|
|
||||||
|
@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* } ] [
|
||||||
|
{ i32, void ()*, i8* } { i32 65535, void ()* @c_global_ctor, i8* null },
|
||||||
|
{ i32, void ()*, i8* } { i32 65535, void ()* @d_global_ctor, i8* null }
|
||||||
|
]
|
||||||
|
|
||||||
|
; CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [
|
||||||
|
; CHECK-DAG: { i32, void ()*, i8* } { i32 65535, void ()* @a_global_ctor, i8* null }
|
||||||
|
; CHECK-DAG: { i32, void ()*, i8* } { i32 65535, void ()* @b_global_ctor, i8* null }
|
||||||
|
; CHECK-DAG: { i32, void ()*, i8* } { i32 65535, void ()* @c_global_ctor, i8* null }
|
||||||
|
; CHECK-DAG: { i32, void ()*, i8* } { i32 65535, void ()* @d_global_ctor, i8* null }
|
||||||
|
; CHECK: ]
|
@ -9,8 +9,13 @@
|
|||||||
@.str2 = private unnamed_addr constant [12 x i8] c"destructing\00", align 1
|
@.str2 = private unnamed_addr constant [12 x i8] c"destructing\00", align 1
|
||||||
@.str3 = private unnamed_addr constant [5 x i8] c"main\00", align 1
|
@.str3 = private unnamed_addr constant [5 x i8] c"main\00", align 1
|
||||||
|
|
||||||
@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @a_global_ctor }]
|
%ini = type { i32, void()*, i8* }
|
||||||
@llvm.global_dtors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @a_global_dtor }]
|
|
||||||
|
@llvm.global_ctors = appending global [2 x %ini ] [
|
||||||
|
%ini { i32 65535, void ()* @a_global_ctor, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @b_global_ctor, i8* bitcast (i32* @b to i8*) }
|
||||||
|
]
|
||||||
|
@llvm.global_dtors = appending global [1 x %ini ] [%ini { i32 65535, void ()* @a_global_dtor, i8* null }]
|
||||||
|
|
||||||
declare i32 @puts(i8*)
|
declare i32 @puts(i8*)
|
||||||
|
|
||||||
@ -19,6 +24,13 @@ define void @a_global_ctor() nounwind {
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@b = global i32 zeroinitializer
|
||||||
|
|
||||||
|
define void @b_global_ctor() nounwind {
|
||||||
|
store i32 42, i32* @b
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
define void @a_global_dtor() nounwind {
|
define void @a_global_dtor() nounwind {
|
||||||
%1 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str2, i32 0, i32 0))
|
%1 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str2, i32 0, i32 0))
|
||||||
ret void
|
ret void
|
||||||
@ -31,9 +43,13 @@ define i32 @main() nounwind {
|
|||||||
|
|
||||||
; WIN32: .section .CRT$XCU,"rd"
|
; WIN32: .section .CRT$XCU,"rd"
|
||||||
; WIN32: a_global_ctor
|
; WIN32: a_global_ctor
|
||||||
|
; WIN32: .section .CRT$XCU,"rd",associative .bss,{{_?}}b
|
||||||
|
; WIN32: b_global_ctor
|
||||||
; WIN32: .section .CRT$XTX,"rd"
|
; WIN32: .section .CRT$XTX,"rd"
|
||||||
; WIN32: a_global_dtor
|
; WIN32: a_global_dtor
|
||||||
; MINGW32: .section .ctors,"wd"
|
; MINGW32: .section .ctors,"wd"
|
||||||
; MINGW32: a_global_ctor
|
; MINGW32: a_global_ctor
|
||||||
|
; MINGW32: .section .ctors,"wd",associative .bss,{{_?}}b
|
||||||
|
; MINGW32: b_global_ctor
|
||||||
; MINGW32: .section .dtors,"wd"
|
; MINGW32: .section .dtors,"wd"
|
||||||
; MINGW32: a_global_dtor
|
; MINGW32: a_global_dtor
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
; RUN: opt < %s -globalopt -S | not grep CTOR
|
; RUN: opt < %s -globalopt -S | FileCheck %s
|
||||||
@llvm.global_ctors = appending global [11 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @CTOR1 }, { i32, void ()* } { i32 65535, void ()* @CTOR1 }, { i32, void ()* } { i32 65535, void ()* @CTOR2 }, { i32, void ()* } { i32 65535, void ()* @CTOR3 }, { i32, void ()* } { i32 65535, void ()* @CTOR4 }, { i32, void ()* } { i32 65535, void ()* @CTOR5 }, { i32, void ()* } { i32 65535, void ()* @CTOR6 }, { i32, void ()* } { i32 65535, void ()* @CTOR7 }, { i32, void ()* } { i32 65535, void ()* @CTOR8 }, { i32, void ()* } { i32 65535, void ()* @CTOR9 }, { i32, void ()* } { i32 2147483647, void ()* null } ] ; <[10 x { i32, void ()* }]*> [#uses=0]
|
; CHECK-NOT: CTOR
|
||||||
|
%ini = type { i32, void()*, i8* }
|
||||||
|
@llvm.global_ctors = appending global [11 x %ini] [
|
||||||
|
%ini { i32 65535, void ()* @CTOR1, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR1, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR2, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR3, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR4, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR5, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR6, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR7, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR8, i8* null },
|
||||||
|
%ini { i32 65535, void ()* @CTOR9, i8* null },
|
||||||
|
%ini { i32 2147483647, void ()* null, i8* null }
|
||||||
|
]
|
||||||
|
|
||||||
@G = global i32 0 ; <i32*> [#uses=1]
|
@G = global i32 0 ; <i32*> [#uses=1]
|
||||||
@G2 = global i32 0 ; <i32*> [#uses=1]
|
@G2 = global i32 0 ; <i32*> [#uses=1]
|
||||||
@G3 = global i32 -123 ; <i32*> [#uses=2]
|
@G3 = global i32 -123 ; <i32*> [#uses=2]
|
||||||
|
11
test/Verifier/global-ctors.ll
Normal file
11
test/Verifier/global-ctors.ll
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
@llvm.global_ctors = appending global [1 x { i32, void()*, i8 } ] [
|
||||||
|
{ i32, void()*, i8 } { i32 65535, void ()* null, i8 0 }
|
||||||
|
]
|
||||||
|
; CHECK: wrong type for intrinsic global variable
|
||||||
|
|
||||||
|
@llvm.global_dtors = appending global [1 x { i32, void()*, i8*, i8 } ] [
|
||||||
|
{ i32, void()*, i8*, i8 } { i32 65535, void ()* null, i8* null, i8 0}
|
||||||
|
]
|
||||||
|
; CHECK: wrong type for intrinsic global variable
|
Loading…
Reference in New Issue
Block a user