86 if (
auto *CPA = dyn_cast<ConstantPtrAuth>(C)) {
87 Fixups.emplace_back(&GV, CPA, GEPPath, ExprPath);
90 if (isa<ConstantAggregate>(C)) {
91 for (
unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
92 if (
auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
101 if (
auto *CE = dyn_cast<ConstantExpr>(C)) {
102 for (
unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
103 if (
auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
104 ExprPath.push_back({CE, I});
118 return Error::success();
120 llvm::Triple T(M.getTargetTriple());
124 return Error::success();
127 SmallVector<GlobalInitPtrAuthFixup> GlobalInitFixups;
128 for (
auto &G : M.globals()) {
129 if (!G.hasInitializer())
131 SmallVector<unsigned> GEPPath;
132 SmallVector<ExprStep> ExprPath;
139 SmallVector<WeakInlinePtrAuthFixup> WeakInlineFixups;
140 for (
auto &F : M.functions()) {
142 for (
auto &Inst : BB) {
143 for (
unsigned OpIdx = 0, E = Inst.getNumOperands(); OpIdx != E;
145 auto *CPA = dyn_cast<ConstantPtrAuth>(Inst.getOperand(OpIdx));
148 auto *GV = dyn_cast<GlobalValue>(CPA->getPointer());
149 if (!GV || !GV->hasExternalWeakLinkage())
151 WeakInlineFixups.push_back({&Inst, OpIdx, CPA});
157 if (GlobalInitFixups.empty() && WeakInlineFixups.empty())
158 return Error::success();
161 auto &Ctx = M.getContext();
162 Type *Int32Ty = Type::getInt32Ty(Ctx);
163 Type *IntPtrTy = Type::getInt64Ty(Ctx);
165 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::ptrauth_blend);
167 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::ptrauth_sign);
171 Function::Create(FunctionType::get(Type::getVoidTy(Ctx),
false),
172 GlobalValue::InternalLinkage,
"ptrauth.sign", &M);
173 FixupFn->insert(FixupFn->end(), BasicBlock::Create(Ctx));
174 IRBuilder<>
B(&FixupFn->back());
176 for (
auto &Fixup : GlobalInitFixups) {
177 GlobalVariable *GV = Fixup.GV;
178 ConstantPtrAuth *CPA = Fixup.CPA;
181 if (isa<ConstantPointerNull>(CPA->getPointer())) {
182 CPA->replaceAllUsesWith(CPA->getPointer());
189 if (Fixup.GEPPath.empty()) {
192 SmallVector<Value *> GEPValues;
193 GEPValues.push_back(ConstantInt::get(Int32Ty, 0));
194 for (
unsigned Idx : Fixup.GEPPath)
195 GEPValues.push_back(ConstantInt::get(Int32Ty, Idx));
196 Loc =
B.CreateGEP(GV->getValueType(), GV, GEPValues);
199 Type *PtrTy = CPA->getType();
202 Value *Disc = CPA->getDiscriminator();
203 if (CPA->hasAddressDiscriminator())
204 Disc =
B.CreateCall(BlendIntrinsic,
205 {
B.CreatePointerCast(Loc, IntPtrTy), Disc});
207 if (!Fixup.ExprPath.empty()) {
210 Value *SignedPtr =
B.CreateCall(
211 SignIntrinsic, {
B.CreatePointerCast(CPA->getPointer(), IntPtrTy),
212 CPA->getKey(), Disc});
213 Value *Result =
B.CreateIntToPtr(SignedPtr, PtrTy);
215 for (
auto &
Step : llvm::reverse(Fixup.ExprPath)) {
217 I->setOperand(
Step.OperandIdx, Result);
221 B.CreateStore(Result, Loc);
224 Value *RawPtr =
B.CreateLoad(PtrTy, Loc);
226 B.CreateCall(SignIntrinsic, {
B.CreatePointerCast(RawPtr, IntPtrTy),
227 CPA->getKey(), Disc});
228 B.CreateStore(
B.CreateBitOrPointerCast(SignedPtr, PtrTy), Loc);
231 CPA->replaceAllUsesWith(CPA->getPointer());
238 for (
auto &Fixup : WeakInlineFixups) {
239 IRBuilder<>
B(Fixup.Inst);
240 ConstantPtrAuth *CPA = Fixup.CPA;
241 Type *PtrTy = CPA->getType();
243 Value *Disc = CPA->getDiscriminator();
244 if (CPA->hasAddressDiscriminator()) {
246 B.CreatePointerCast(CPA->getAddrDiscriminator(), IntPtrTy);
247 Disc =
B.CreateCall(BlendIntrinsic, {AddrDisc, Disc});
252 Value *RawPtr =
B.CreatePtrToInt(CPA->getPointer(), IntPtrTy);
253 Value *NullCheck =
B.CreateIsNull(RawPtr);
255 B.CreateCall(SignIntrinsic, {RawPtr, CPA->getKey(), Disc});
257 B.CreateSelect(NullCheck, Constant::getNullValue(IntPtrTy), SignedPtr);
258 Fixup.Inst->setOperand(Fixup.OperandIdx,
B.CreateIntToPtr(Result, PtrTy));
262 auto *UInt8PtrTy = PointerType::getUnqual(Ctx);
263 StructType *CtorType =
264 StructType::get(Ctx, {Int32Ty, FixupFn->getType(), UInt8PtrTy});
265 Constant *PtrFixupCtor =
266 ConstantStruct::get(CtorType, {ConstantInt::get(Int32Ty, 0), FixupFn,
267 Constant::getNullValue(UInt8PtrTy)});
269 const char *LLVMGlobalCtorsName =
"llvm.global_ctors";
270 GlobalVariable *OldCtorList = M.getNamedGlobal(LLVMGlobalCtorsName);
271 SmallVector<Constant *> CtorListArgs;
272 CtorListArgs.push_back(PtrFixupCtor);
277 if (OldCtorList->getNumUses() != 0) {
279 raw_string_ostream S(ErrStr);
280 S <<
"Global ctors variable has users, so can not be rewritten to "
281 "include pointer fixups: '"
282 << *OldCtorList <<
"'";
283 return make_error<StringError>(S.str(), inconvertibleErrorCode());
286 for (
auto &Op : OldCtorList->getInitializer()->operands())
287 CtorListArgs.push_back(cast<Constant>(Op.get()));
290 ArrayType *CtorListType = ArrayType::get(CtorType, CtorListArgs.size());
291 Constant *CtorListInit = ConstantArray::get(CtorListType, CtorListArgs);
293 GlobalVariable *NewCtorList =
new GlobalVariable(
294 M, CtorListType,
false, GlobalValue::AppendingLinkage, CtorListInit);
297 NewCtorList->takeName(OldCtorList);
298 OldCtorList->eraseFromParent();
300 NewCtorList->setName(LLVMGlobalCtorsName);
302 return Error::success();