[clang][patch] To solve PR26413, x86 interrupt routines may only call routines with no_saved_reg

Reviewed By: Aaron Ballman

Differential Revision: https://reviews.llvm.org/D97764
This commit is contained in:
Melanie Blower 2021-03-02 07:58:42 -05:00
parent b2bc0a3254
commit cc3d25be01
4 changed files with 39 additions and 2 deletions

View File

@ -293,6 +293,9 @@ def err_anyx86_interrupt_attribute : Error<
"a pointer as the first parameter|a %2 type as the second parameter}1">;
def err_anyx86_interrupt_called : Error<
"interrupt service routine cannot be called directly">;
def err_anyx86_interrupt_regsave : Error<
"interrupt service routine may only call a function"
" with attribute 'no_caller_saved_registers'">;
def warn_arm_interrupt_calling_convention : Warning<
"call to function without interrupt attribute could clobber interruptee's VFP registers">,
InGroup<Extra>;

View File

@ -6552,12 +6552,25 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// so there's some risk when calling out to non-interrupt handler functions
// that the callee might not preserve them. This is easy to diagnose here,
// but can be very challenging to debug.
if (auto *Caller = getCurFunctionDecl())
// Likewise, X86 interrupt handlers may only call routines with attribute
// no_caller_saved_registers since there is no efficient way to
// save and restore the non-GPR state.
if (auto *Caller = getCurFunctionDecl()) {
if (Caller->hasAttr<ARMInterruptAttr>()) {
bool VFP = Context.getTargetInfo().hasFeature("vfp");
if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>()))
if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) {
Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
if (FDecl)
Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
}
}
if (Caller->hasAttr<AnyX86InterruptAttr>() &&
((!FDecl || !FDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()))) {
Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_regsave);
if (FDecl)
Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
}
}
// Promote the function operand.
// We special-case function promotion here because we only allow promoting

View File

@ -19,6 +19,9 @@ __attribute__((interrupt)) void foo8() {}
__attribute__((interrupt())) void foo9() {}
__attribute__((interrupt(""))) void foo10() {}
#ifndef SOFT
// expected-note@+2 {{'callee1' declared here}}
#endif
void callee1();
__attribute__((interrupt("IRQ"))) void callee2();
void caller1() {

View File

@ -3,6 +3,7 @@
// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s -DNOCALLERSAVE=1
struct a {
int b;
@ -39,6 +40,23 @@ __attribute__((interrupt)) void foo6(float *a, int b) {}
__attribute__((interrupt)) void foo7(int *a, unsigned b) {}
__attribute__((interrupt)) void foo8(int *a) {}
#ifdef _LP64
typedef unsigned long Arg2Type;
#elif defined(__x86_64__)
typedef unsigned long long Arg2Type;
#else
typedef unsigned int Arg2Type;
#endif
#ifndef NOCALLERSAVE
__attribute__((no_caller_saved_registers))
#else
// expected-note@+3 {{'foo9' declared here}}
// expected-error@+4 {{interrupt service routine may only call a function with attribute 'no_caller_saved_registers'}}
#endif
void foo9(int *a, Arg2Type b) {}
__attribute__((interrupt)) void fooA(int *a, Arg2Type b) {
foo9(a, b);
}
void g(void (*fp)(int *));
int main(int argc, char **argv) {
void *ptr = (void *)&foo7;