return __builtin_addressof(value);
}
+``__builtin_function_start``
+-----------------------------
+
+``__builtin_function_start`` returns the address of a function body.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ void *__builtin_function_start(function)
+
+**Example of use**:
+
+.. code-block:: c++
+
+ void a() {}
+ void *p = __builtin_function_start(a);
+
+ class A {
+ public:
+ void a(int n);
+ void a();
+ };
+
+ void A::a(int n) {}
+ void A::a() {}
+
+ void *pa1 = __builtin_function_start((void(A::*)(int)) &A::a);
+ void *pa2 = __builtin_function_start((void(A::*)()) &A::a);
+
+**Description**:
+
+The ``__builtin_function_start`` builtin accepts an argument that can be
+constant-evaluated to a function, and returns the address of the function
+body. This builtin is not supported on all targets.
+
+The returned pointer may differ from the normally taken function address
+and is not safe to call. For example, with ``-fsanitize=cfi``, taking a
+function address produces a callable pointer to a CFI jump table, while
+``__builtin_function_start`` returns an address that fails
+:doc:`cfi-icall<ControlFlowIntegrity>` checks.
+
``__builtin_operator_new`` and ``__builtin_operator_delete``
------------------------------------------------------------
bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
const Expr **Culprit = nullptr) const;
+ /// If this expression is an unambiguous reference to a single declaration,
+ /// in the style of __builtin_function_start, return that declaration. Note
+ /// that this may return a non-static member function or field in C++ if this
+ /// expression is a member pointer constant.
+ const ValueDecl *getAsBuiltinConstantDeclRef(const ASTContext &Context) const;
+
/// EvalStatus is a struct with detailed info about an evaluation in progress.
struct EvalStatus {
/// Whether the evaluated expression has side effects.
// Clang builtins (not available in GCC).
BUILTIN(__builtin_addressof, "v*v&", "nct")
+BUILTIN(__builtin_function_start, "v*v&", "nct")
BUILTIN(__builtin_operator_new, "v*z", "tc")
BUILTIN(__builtin_operator_delete, "vv*", "tn")
BUILTIN(__builtin_char_memchr, "c*cC*iz", "n")
"%2, but the corresponding specifier may require size %3">,
InGroup<FortifySource>;
+def err_function_start_invalid_type: Error<
+ "argument must be a function">;
+
/// main()
// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
return false;
}
+const ValueDecl *
+Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
+ Expr::EvalResult Eval;
+
+ if (EvaluateAsConstantExpr(Eval, Context)) {
+ APValue &Value = Eval.Val;
+
+ if (Value.isMemberPointer())
+ return Value.getMemberPointerDecl();
+
+ if (Value.isLValue() && Value.getLValueOffset().isZero())
+ return Value.getLValueBase().dyn_cast<const ValueDecl *>();
+ }
+
+ return nullptr;
+}
+
// Amusing macro metaprogramming hack: check whether a class provides
// a more specific implementation of getExprLoc().
//
return true;
}
-/// Should this call expression be treated as a string literal?
-static bool IsStringLiteralCall(const CallExpr *E) {
+/// Should this call expression be treated as a constant?
+static bool IsConstantCall(const CallExpr *E) {
unsigned Builtin = E->getBuiltinCallee();
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
- Builtin == Builtin::BI__builtin___NSStringMakeConstantString);
+ Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
+ Builtin == Builtin::BI__builtin_function_start);
}
static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::ObjCBoxedExprClass:
return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
case Expr::CallExprClass:
- return IsStringLiteralCall(cast<CallExpr>(E));
+ return IsConstantCall(cast<CallExpr>(E));
// For GCC compatibility, &&label has static storage duration.
case Expr::AddrLabelExprClass:
return true;
}
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (IsStringLiteralCall(E))
+ if (IsConstantCall(E))
return Success(E);
if (unsigned BuiltinOp = E->getBuiltinCallee())
}
case Builtin::BI__builtin_addressof:
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
+ case Builtin::BI__builtin_function_start:
+ return RValue::get(CGM.GetFunctionStart(
+ E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext())));
case Builtin::BI__builtin_operator_new:
return EmitBuiltinNewDeleteCall(
E->getCallee()->getType()->castAs<FunctionProtoType>(), E, false);
ConstantLValue
ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
unsigned builtin = E->getBuiltinCallee();
+ if (builtin == Builtin::BI__builtin_function_start)
+ return CGM.GetFunctionStart(
+ E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext()));
if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
builtin != Builtin::BI__builtin___NSStringMakeConstantString)
return nullptr;
return F;
}
+llvm::Constant *CodeGenModule::GetFunctionStart(const ValueDecl *Decl) {
+ llvm::GlobalValue *F =
+ cast<llvm::GlobalValue>(GetAddrOfFunction(Decl)->stripPointerCasts());
+
+ return llvm::ConstantExpr::getBitCast(llvm::NoCFIValue::get(F),
+ llvm::Type::getInt8PtrTy(VMContext));
+}
+
static const FunctionDecl *
GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) {
TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
ForDefinition_t IsForDefinition
= NotForDefinition);
+ // Return the function body address of the given function.
+ llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
+
/// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
return false;
}
+/// Check that the argument to __builtin_function_start is a function.
+static bool SemaBuiltinFunctionStart(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 1))
+ return true;
+
+ ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+ if (Arg.isInvalid())
+ return true;
+
+ TheCall->setArg(0, Arg.get());
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
+ Arg.get()->getAsBuiltinConstantDeclRef(S.getASTContext()));
+
+ if (!FD) {
+ S.Diag(TheCall->getBeginLoc(), diag::err_function_start_invalid_type)
+ << TheCall->getSourceRange();
+ return true;
+ }
+
+ return !S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ TheCall->getBeginLoc());
+}
+
/// Check the number of arguments and set the result type to
/// the argument type.
static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
if (SemaBuiltinAddressof(*this, TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_function_start:
+ if (SemaBuiltinFunctionStart(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_is_aligned:
case Builtin::BI__builtin_align_up:
case Builtin::BI__builtin_align_down:
case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_expect_with_probability:
case Builtin::BI__builtin_assume_aligned:
- case Builtin::BI__builtin_addressof: {
+ case Builtin::BI__builtin_addressof:
+ case Builtin::BI__builtin_function_start: {
// For __builtin_unpredictable, __builtin_expect,
// __builtin_expect_with_probability and __builtin_assume_aligned,
// just return the value of the subexpression.
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=cfi-icall -o - %s | FileCheck %s
+
+#if !__has_builtin(__builtin_function_start)
+#error "missing __builtin_function_start"
+#endif
+
+void a(void) {}
+// CHECK: @e = global i8* bitcast (void ()* no_cfi @_Z1av to i8*)
+const void *e = __builtin_function_start(a);
+
+constexpr void (*d)() = &a;
+// CHECK: @f = global i8* bitcast (void ()* no_cfi @_Z1av to i8*)
+const void *f = __builtin_function_start(d);
+
+void b(void) {}
+// CHECK: @g = global [2 x i8*] [i8* bitcast (void ()* @_Z1bv to i8*), i8* bitcast (void ()* no_cfi @_Z1bv to i8*)]
+void *g[] = {(void *)b, __builtin_function_start(b)};
+
+void c(void *p) {}
+
+class A {
+public:
+ void f();
+ virtual void g();
+ static void h();
+ int i() const;
+ int i(int n) const;
+};
+
+void A::f() {}
+void A::g() {}
+void A::h() {}
+
+// CHECK: define {{.*}}i32 @_ZNK1A1iEv(%class.A* {{.*}}%this)
+int A::i() const { return 0; }
+
+// CHECK: define {{.*}}i32 @_ZNK1A1iEi(%class.A* {{.*}}%this, i32 %n)
+int A::i(int n) const { return 0; }
+
+void h(void) {
+ // CHECK: store i8* bitcast (void ()* no_cfi @_Z1bv to i8*), i8** %g
+ void *g = __builtin_function_start(b);
+ // CHECK: call void @_Z1cPv(i8* bitcast (void ()* no_cfi @_Z1av to i8*))
+ c(__builtin_function_start(a));
+
+ // CHECK: store i8* bitcast (void (%class.A*)* no_cfi @_ZN1A1fEv to i8*), i8** %Af
+ void *Af = __builtin_function_start(&A::f);
+ // CHECK: store i8* bitcast (void (%class.A*)* no_cfi @_ZN1A1gEv to i8*), i8** %Ag
+ void *Ag = __builtin_function_start(&A::g);
+ // CHECK: store i8* bitcast (void ()* no_cfi @_ZN1A1hEv to i8*), i8** %Ah
+ void *Ah = __builtin_function_start(&A::h);
+ // CHECK: store i8* bitcast (i32 (%class.A*)* no_cfi @_ZNK1A1iEv to i8*), i8** %Ai1
+ void *Ai1 = __builtin_function_start((int(A::*)() const) & A::i);
+ // CHECK: store i8* bitcast (i32 (%class.A*, i32)* no_cfi @_ZNK1A1iEi to i8*), i8** %Ai2
+ void *Ai2 = __builtin_function_start((int(A::*)(int) const) & A::i);
+}
S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}}
}
+namespace function_start {
+void a(void) {}
+int n;
+void *p = __builtin_function_start(n); // expected-error {{argument must be a function}}
+static_assert(__builtin_function_start(a) == a, ""); // expected-error {{static_assert expression is not an integral constant expression}}
+} // namespace function_start
+
void no_ms_builtins() {
__assume(1); // expected-error {{use of undeclared}}
__noop(1); // expected-error {{use of undeclared}}