• Jose E. Marchesi's avatar
    libbpf: Fix bpf_ksym_exists() in GCC · cf9bea94
    Jose E. Marchesi authored
    The macro bpf_ksym_exists is defined in bpf_helpers.h as:
    
      #define bpf_ksym_exists(sym) ({								\
      	_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak");	\
      	!!sym;											\
      })
    
    The purpose of the macro is to determine whether a given symbol has
    been defined, given the address of the object associated with the
    symbol.  It also has a compile-time check to make sure the object
    whose address is passed to the macro has been declared as weak, which
    makes the check on `sym' meaningful.
    
    As it happens, the check for weak doesn't work in GCC in all cases,
    because __builtin_constant_p not always folds at parse time when
    optimizing.  This is because optimizations that happen later in the
    compilation process, like inlining, may make a previously non-constant
    expression a constant.  This results in errors like the following when
    building the selftests with GCC:
    
      bpf_helpers.h:190:24: error: expression in static assertion is not constant
      190 |         _Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak");       \
          |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Fortunately recent versions of GCC support a __builtin_has_attribute
    that can be used to directly check for the __weak__ attribute.  This
    patch changes bpf_helpers.h to use that builtin when building with a
    recent enough GCC, and to omit the check if GCC is too old to support
    the builtin.
    
    The macro used for GCC becomes:
    
      #define bpf_ksym_exists(sym) ({									\
    	_Static_assert(__builtin_has_attribute (*sym, __weak__), #sym " should be marked as __weak");	\
    	!!sym;												\
      })
    
    Note that since bpf_ksym_exists is designed to get the address of the
    object associated with symbol SYM, we pass *sym to
    __builtin_has_attribute instead of sym.  When an expression is passed
    to __builtin_has_attribute then it is the type of the passed
    expression that is checked for the specified attribute.  The
    expression itself is not evaluated.  This accommodates well with the
    existing usages of the macro:
    
    - For function objects:
    
      struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak;
      [...]
      bpf_ksym_exists(bpf_task_acquire)
    
    - For variable objects:
    
      extern const struct rq runqueues __ksym __weak; /* typed */
      [...]
      bpf_ksym_exists(&runqueues)
    
    Note also that BPF support was added in GCC 10 and support for
    __builtin_has_attribute in GCC 9.
    
    Locally tested in bpf-next master branch.
    No regressions.
    Signed-of-by: default avatarJose E. Marchesi <jose.marchesi@oracle.com>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
    Link: https://lore.kernel.org/bpf/20240428112559.10518-1-jose.marchesi@oracle.com
    cf9bea94
bpf_helpers.h 15.5 KB