https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128360

            Bug ID: 128360
           Summary: i386: __attribute__((cf_check)) on static/localized
                    function silently omits ENDBR under
                    -fcf-protection=branch -mmanual-endbr
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: x86_64-*-* i?86-*-*

Reproducer
----------
$ cat trigger.c
static __attribute__((cf_check, noinline)) int
static_cf_target (int x)
{
  __asm__ volatile ("" : "+r" (x));
  return x + 1;
}

__attribute__((cf_check, noinline)) int
extern_cf_target (int x)
{
  __asm__ volatile ("" : "+r" (x));
  return x + 2;
}

int
caller (int x)
{
  return static_cf_target (x) + extern_cf_target (x);
}

Compile flag: x86_64-linux-gnu-gcc -O2 -fcf-protection=branch -mmanual-endbr -S
trigger.c

static_cf_target:
.LFB0:
        .cfi_startproc
        leal    1(%rdi), %eax   # missing endbr64 despite cf_check
        ret
        .cfi_endproc

extern_cf_target:
.LFB1:
        .cfi_startproc
        endbr64                 # emitted as expected
        leal    2(%rdi), %eax
        ret
        .cfi_endproc

Root cause
----------
In rest_of_insert_endbr_and_patchable_area
(gcc/config/i386/i386-features.cc:3014-3025),
the cf_check check is conjoined with !cgraph_node::get
(cfun->decl)->only_called_directly_p ():

  if (!lookup_attribute ("nocf_check",
                         TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
      && (!flag_manual_endbr
          || lookup_attribute ("cf_check",
                               DECL_ATTRIBUTES (cfun->decl)))
      && (!cgraph_node::get (cfun->decl)->only_called_directly_p ()
          || ...))

When a static function (or a function localized by -fwhole-program / LTO) is
annotated with cf_check (e.g. reached via inline-asm indirect branch), GCC
still drops endbr64 whenever the middle-end sees only direct calls.

Suggested Fix
-------------
In rest_of_insert_endbr_and_patchable_area
(gcc/config/i386/i386-features.cc:3019),
exempt functions carrying an explicit cf_check attribute on DECL_ATTRIBUTES
(cfun->decl)
from the only_called_directly_p () check.

Reply via email to