On Thu, Sep 12, 2024 at 06:09:53PM +0200, Jose E. Marchesi via Gcc wrote:
> - "noreturn" and jump tables run-time hints
> 
>   It has been expressed on the kernel side the desire of having the C compiler
>   emit run-time hints marking functions that are not supposed to return and
>   also to provide annotations on jump tables.  This is for the benefit of
>   objtool in arm64, see references below.
> 
>   Goal of the discussion:
> 
>   Collect and assess the requirements of these features, discuss their
>   pertinence and the way it could be best implemented.  The outcome of the
>   discussion will then be used to continue the discussion with the clang/llvm
>   and kernel hackers at LPC.
> 
>   References:
>   
> https://lore.kernel.org/linux-arm-kernel/yylmhuxtuanza...@hirez.programming.kicks-ass.net/

What I was suggesting is something like (completely untested, GPL v2.0+ in
case you'd like to use anything from that):
#include "gcc-common.h"

__visible int plugin_is_GPL_compatible;

static struct plugin_info mark_noreturn_plugin_info = {
        .version        = PLUGIN_VERSION,
        .help           = "mark noreturn plugin\n",
};

static unsigned int mark_noreturn_execute(void)
{
        if (flags_from_decl_or_type(current_function_decl) & ECF_NORETURN) {
                const char *name = 
IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(current_function_decl));
                name = targetm.strip_name_encoding(name);
                name = concat("__noreturn_function.", name, NULL);
                tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
                                       get_identifier(name), 
TREE_TYPE(current_function_decl));
                DECL_ARTIFICIAL(decl) = 1;
                TREE_PUBLIC(decl) = 0;
                DECL_WEAK(decl) = DECL_WEAK(current_function_decl);
                assemble_alias(current_function_decl, decl);
        }
        return 0;
}

#define PASS_NAME mark_noreturn

#define NO_GATE

#include "gcc-generate-gimple-pass.h"

__visible int plugin_init(struct plugin_name_args *plugin_info, struct 
plugin_gcc_version *version)
{
        int i;
        const char * const plugin_name = plugin_info->base_name;
        const int argc = plugin_info->argc;
        const struct plugin_argument * const argv = plugin_info->argv;
        bool enable = true;

        PASS_INFO(mark_noreturn, "optimized", 0, PASS_POS_INSERT_BEFORE);

        if (!plugin_default_version_check(version, &gcc_version)) {
                error(G_("incompatible gcc/plugin versions"));
                return 1;
        }

        for (i = 0; i < argc; ++i) {
                if (!strcmp(argv[i].key, "no-mark-noreturn")) {
                        enable = false;
                        continue;
                }
                error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, 
argv[i].key);
        }

        register_callback(plugin_name, PLUGIN_INFO, NULL, 
&mark_noreturn_plugin_info);

        if (!enable)
                return 0;

#if BUILDING_GCC_VERSION < 6000
        register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, 
&mark_noreturn_pass_info);
#endif

        return 0;
}

Basically just create a __noreturn_function.foobarbaz alias to foobarbaz
function if that function is noreturn.  Haven't investigated if all Linux
kernel arches will be happy with . in the name, other options are $ or
_ or conditionally one of them e.g. based on NO_DOT_IN_LABEL/NO_DOLLAR_IN_LABEL
macros.

> - Struct layout randomization (-frandomize-struct-layout) and debug info
> 
>   The GCC plugin hooks in a way that emitted debug info doesn't match with the
>   resulting randomized structs.  It works in clang because it generates DWARF
>   later in the compilation process.
> 
>   References:
> 
>   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84052
>   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116457
> 
>   Goal of the discussion:
> 
>   Determine how to best fix this in the plugin, or by using a different
>   approach.  The outcome of the discussion will then be used to continue the
>   discussion with the clang/llvm and kernel hackers at LPC.
> 
> - Userland stack unwinding from within the Linux kernel
> 
>   There are reasons for wanting to unwind both userland and kernel
>   stacks from within the kernel.  Currently the kernel can unwind kernel
>   stacks based on ORC (which is revese-engineered from kernel compiled
>   objects by objtool) and userland stacks provided stack frame pointers
>   are present.  SFrame is a format similar to ORC, but general enough to
>   be used in userspace, and there is an on-going effort to introduce a
>   SFrame based unwinder in the kernel.  This will require some glibc
>   support as well.
> 
>   References:
> 
>   First prototype (V1) from Josh Poimboeuf:
>   https://lkml.kernel.org/lkml/cover.1699487758.git.jpoim...@kernel.org/

As discussed, either submit a patch to add another plugin callback event
after a new structure is almost ready to be finalized but debug info hasn't
been emitted yet, or there is also not so complicated option of reordering
the already registered debug info to match how the FIELD_DECLs have been
actually reordered.

As for marking of the start and end of jump tables (though, of course, only
when they are actually emitted, switch lowering can use many different ways
of lowering the switches or combination thereof), I'd think a GCC plugin
registering an RTL pass which is run before "final" (or so), walks the
RTL and adds CODE_LABEL with some prefix and consecutively increased counter
before and after the JUMP_TABLE_DATA insns.

        Jakub

Reply via email to