-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[PAC][IR][AArch64] Add "ptrauth(...)" Constant to represent signed pointers. #85738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -346,6 +346,7 @@ enum Kind { | |
kw_blockaddress, | ||
kw_dso_local_equivalent, | ||
kw_no_cfi, | ||
kw_ptrauth, | ||
|
||
kw_freeze, | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1008,6 +1008,72 @@ struct OperandTraits<NoCFIValue> : public FixedNumOperandTraits<NoCFIValue, 1> { | |
|
||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(NoCFIValue, Value) | ||
|
||
/// A signed pointer, in the ptrauth sense. | ||
class ConstantPtrAuth final : public Constant { | ||
friend struct ConstantPtrAuthKeyType; | ||
friend class Constant; | ||
|
||
ConstantPtrAuth(Constant *Ptr, ConstantInt *Key, ConstantInt *Disc, | ||
Constant *AddrDisc); | ||
|
||
void *operator new(size_t s) { return User::operator new(s, 4); } | ||
|
||
void destroyConstantImpl(); | ||
Value *handleOperandChangeImpl(Value *From, Value *To); | ||
|
||
public: | ||
/// Return a pointer signed with the specified parameters. | ||
static ConstantPtrAuth *get(Constant *Ptr, ConstantInt *Key, | ||
ConstantInt *Disc, Constant *AddrDisc); | ||
|
||
/// Produce a new ptrauth expression signing the given value using | ||
/// the same schema as is stored in one. | ||
ConstantPtrAuth *getWithSameSchema(Constant *Pointer) const; | ||
|
||
/// Transparently provide more efficient getOperand methods. | ||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); | ||
|
||
/// The pointer that is signed in this ptrauth signed pointer. | ||
Constant *getPointer() const { return cast<Constant>(Op<0>().get()); } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ahmedbougacha Is it a desired behavior that we return a non-const-qualified pointer to associated data when calling getters allowed for calls on const-qualified object? Shouldn't we have two getter overloads, one with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have generally treated a lot of these sorts of types as value types, and there is little you can do with a mutable |
||
|
||
/// The Key ID, an i32 constant. | ||
ConstantInt *getKey() const { return cast<ConstantInt>(Op<1>().get()); } | ||
|
||
/// The integer discriminator, an i64 constant, or 0. | ||
ConstantInt *getDiscriminator() const { | ||
return cast<ConstantInt>(Op<2>().get()); | ||
} | ||
|
||
/// The address discriminator if any, or the null constant. | ||
/// If present, this must be a value equivalent to the storage location of | ||
/// the only global-initializer user of the ptrauth signed pointer. | ||
Constant *getAddrDiscriminator() const { | ||
return cast<Constant>(Op<3>().get()); | ||
} | ||
|
||
/// Whether there is any non-null address discriminator. | ||
bool hasAddressDiscriminator() const { | ||
return !getAddrDiscriminator()->isNullValue(); | ||
} | ||
|
||
/// Check whether an authentication operation with key \p Key and (possibly | ||
/// blended) discriminator \p Discriminator is known to be compatible with | ||
/// this ptrauth signed pointer. | ||
bool isKnownCompatibleWith(const Value *Key, const Value *Discriminator, | ||
const DataLayout &DL) const; | ||
|
||
/// Methods for support type inquiry through isa, cast, and dyn_cast: | ||
static bool classof(const Value *V) { | ||
return V->getValueID() == ConstantPtrAuthVal; | ||
} | ||
}; | ||
|
||
template <> | ||
struct OperandTraits<ConstantPtrAuth> | ||
: public FixedNumOperandTraits<ConstantPtrAuth, 4> {}; | ||
|
||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPtrAuth, Constant) | ||
|
||
//===----------------------------------------------------------------------===// | ||
/// A constant value that is initialized with an expression using | ||
/// other constant values. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4046,6 +4046,60 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) { | |
ID.NoCFI = true; | ||
return false; | ||
} | ||
case lltok::kw_ptrauth: { | ||
// ValID ::= 'ptrauth' '(' ptr @foo ',' i32 <key> | ||
// (',' i64 <disc> (',' ptr addrdisc)? )? ')' | ||
Lex.Lex(); | ||
|
||
Constant *Ptr, *Key; | ||
Constant *Disc = nullptr, *AddrDisc = nullptr; | ||
|
||
if (parseToken(lltok::lparen, | ||
"expected '(' in constant ptrauth expression") || | ||
parseGlobalTypeAndValue(Ptr) || | ||
parseToken(lltok::comma, | ||
"expected comma in constant ptrauth expression") || | ||
parseGlobalTypeAndValue(Key)) | ||
return true; | ||
// If present, parse the optional disc/addrdisc. | ||
if (EatIfPresent(lltok::comma)) | ||
if (parseGlobalTypeAndValue(Disc) || | ||
(EatIfPresent(lltok::comma) && parseGlobalTypeAndValue(AddrDisc))) | ||
return true; | ||
if (parseToken(lltok::rparen, | ||
"expected ')' in constant ptrauth expression")) | ||
return true; | ||
|
||
if (!Ptr->getType()->isPointerTy()) | ||
return error(ID.Loc, "constant ptrauth base pointer must be a pointer"); | ||
|
||
auto *KeyC = dyn_cast<ConstantInt>(Key); | ||
if (!KeyC || KeyC->getBitWidth() != 32) | ||
return error(ID.Loc, "constant ptrauth key must be i32 constant"); | ||
|
||
ConstantInt *DiscC = nullptr; | ||
if (Disc) { | ||
DiscC = dyn_cast<ConstantInt>(Disc); | ||
if (!DiscC || DiscC->getBitWidth() != 64) | ||
return error( | ||
ID.Loc, | ||
"constant ptrauth integer discriminator must be i64 constant"); | ||
} else { | ||
DiscC = ConstantInt::get(Type::getInt64Ty(Context), 0); | ||
} | ||
|
||
if (AddrDisc) { | ||
if (!AddrDisc->getType()->isPointerTy()) | ||
return error( | ||
ID.Loc, "constant ptrauth address discriminator must be a pointer"); | ||
} else { | ||
AddrDisc = ConstantPointerNull::get(PointerType::get(Context, 0)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can Ptr be in a non-default address space, and if so, does AddrDisc have to be in the same address space? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I see a test below where this is the case. I guess the question then changes to: Should the default address space of AddrDisc be 0 or the address space of Ptr? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the base pointer and the addr-disc pointer aren't really related, other than "addr-disc points to memory that's initialized with the full |
||
} | ||
|
||
ID.ConstantVal = ConstantPtrAuth::get(Ptr, KeyC, DiscC, AddrDisc); | ||
ID.Kind = ValID::t_Constant; | ||
return false; | ||
} | ||
|
||
case lltok::kw_trunc: | ||
case lltok::kw_bitcast: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any restrictions on ptr worth documenting? Or is it just the same restrictions as constant expressions in globals, ie, that they can eventually be lowered to Mach-o/ELF relocations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Eventually this will be lowered to ELF pauth relocs (see e.g. https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst)