diff mbox series

[v3,6/6] plugin: Getting qemu-plugin works under win32.

Message ID 20201001163429.1348-7-luoyonggang@gmail.com
State New
Headers show
Series Enable plugin support on msys2/mingw | expand

Commit Message

罗勇刚(Yonggang Luo) Oct. 1, 2020, 4:34 p.m. UTC
We removed the need of .symbols file, so is the
configure script, if we one expose a function to qemu-plugin
just need prefix the function with QEMU_PLUGIN_EXPORT

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
---
 Makefile                     |   1 -
 configure                    |  71 -------------
 contrib/plugins/hotblocks.c  |   1 +
 contrib/plugins/hotpages.c   |   1 +
 contrib/plugins/howvec.c     |   1 +
 contrib/plugins/lockstep.c   |   1 +
 include/qemu/qemu-plugin.h   | 197 +++++++++++++++++++++++++++--------
 meson.build                  |   6 +-
 plugins/api.c                |  62 +++++------
 plugins/core.c               |  10 +-
 plugins/loader.c             |  50 ++++++++-
 plugins/meson.build          |  10 +-
 plugins/plugin.h             |   1 +
 plugins/qemu-plugins.symbols |  40 -------
 tests/plugin/bb.c            |   1 +
 tests/plugin/empty.c         |   1 +
 tests/plugin/insn.c          |   1 +
 tests/plugin/mem.c           |   1 +
 18 files changed, 251 insertions(+), 205 deletions(-)
 delete mode 100644 plugins/qemu-plugins.symbols

Comments

Alex Bennée Oct. 6, 2020, 11:29 a.m. UTC | #1
Yonggang Luo <luoyonggang@gmail.com> writes:

> We removed the need of .symbols file, so is the

> configure script, if we one expose a function to qemu-plugin

> just need prefix the function with QEMU_PLUGIN_EXPORT

>

> Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>

> ---

>  Makefile                     |   1 -

>  configure                    |  71 -------------

>  contrib/plugins/hotblocks.c  |   1 +

>  contrib/plugins/hotpages.c   |   1 +

>  contrib/plugins/howvec.c     |   1 +

>  contrib/plugins/lockstep.c   |   1 +

>  include/qemu/qemu-plugin.h   | 197 +++++++++++++++++++++++++++--------

>  meson.build                  |   6 +-

>  plugins/api.c                |  62 +++++------

>  plugins/core.c               |  10 +-

>  plugins/loader.c             |  50 ++++++++-

>  plugins/meson.build          |  10 +-

>  plugins/plugin.h             |   1 +

>  plugins/qemu-plugins.symbols |  40 -------

>  tests/plugin/bb.c            |   1 +

>  tests/plugin/empty.c         |   1 +

>  tests/plugin/insn.c          |   1 +

>  tests/plugin/mem.c           |   1 +

>  18 files changed, 251 insertions(+), 205 deletions(-)

>  delete mode 100644 plugins/qemu-plugins.symbols

>

> diff --git a/Makefile b/Makefile

> index 54fc1a9d10..9981dd5209 100644

> --- a/Makefile

> +++ b/Makefile

> @@ -105,7 +105,6 @@ config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION

>  

>  # Force configure to re-run if the API symbols are updated

>  ifeq ($(CONFIG_PLUGIN),y)

> -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols

>  

>  .PHONY: plugins

>  plugins:

> diff --git a/configure b/configure

> index 1c21a73c3b..ea447919fc 100755

> --- a/configure

> +++ b/configure

> @@ -5435,61 +5435,6 @@ if compile_prog "" "" ; then

>    atomic64=yes

>  fi

>  

> -#########################################

> -# See if --dynamic-list is supported by the linker

> -ld_dynamic_list="no"

> -if test "$static" = "no" ; then

> -    cat > $TMPTXT <<EOF

> -{

> -  foo;

> -};

> -EOF

> -

> -    cat > $TMPC <<EOF

> -#include <stdio.h>

> -void foo(void);

> -

> -void foo(void)

> -{

> -  printf("foo\n");

> -}

> -

> -int main(void)

> -{

> -  foo();

> -  return 0;

> -}

> -EOF

> -

> -    if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then

> -        ld_dynamic_list="yes"

> -    fi

> -fi

> -

> -#########################################

> -# See if -exported_symbols_list is supported by the linker

> -

> -ld_exported_symbols_list="no"

> -if test "$static" = "no" ; then

> -    cat > $TMPTXT <<EOF

> -  _foo

> -EOF

> -

> -    if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then

> -        ld_exported_symbols_list="yes"

> -    fi

> -fi

> -

> -if  test "$plugins" = "yes" &&

> -    test "$ld_dynamic_list" = "no" &&

> -    test "$ld_exported_symbols_list" = "no" ; then

> -  error_exit \

> -      "Plugin support requires dynamic linking and specifying a set of symbols " \

> -      "that are exported to plugins. Unfortunately your linker doesn't " \

> -      "support the flag (--dynamic-list or -exported_symbols_list) used " \

> -      "for this purpose. You can't build with --static."

> -fi

> -

>  ########################################

>  # See if __attribute__((alias)) is supported.

>  # This false for Xcode 9, but has been remedied for Xcode 10.

> @@ -7074,22 +7019,6 @@ fi

>  

>  if test "$plugins" = "yes" ; then

>      echo "CONFIG_PLUGIN=y" >> $config_host_mak

> -    # Copy the export object list to the build dir

> -    if test "$ld_dynamic_list" = "yes" ; then

> -	echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak

> -	ld_symbols=qemu-plugins-ld.symbols

> -	cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols

> -    elif test "$ld_exported_symbols_list" = "yes" ; then

> -	echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak

> -	ld64_symbols=qemu-plugins-ld64.symbols

> -	echo "# Automatically generated by configure - do not modify" > $ld64_symbols

> -	grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \

> -	    sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols

> -    else

> -	error_exit \

> -	    "If \$plugins=yes, either \$ld_dynamic_list or " \

> -	    "\$ld_exported_symbols_list should have been set to 'yes'."

> -    fi

>  fi

>  

>  if test -n "$gdb_bin" ; then

> diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c

> index 37435a3fc7..39e77d2980 100644

> --- a/contrib/plugins/hotblocks.c

> +++ b/contrib/plugins/hotblocks.c

> @@ -13,6 +13,7 @@

>  #include <stdio.h>

>  #include <glib.h>

>  

> +#define QEMU_PLUGIN_IMPLEMENTATION

>  #include <qemu-plugin.h>


As mentioned in earlier patch we should be able to just have the tweak
in api.c and avoid touching all the plugins themselves.
>  

> -#define QEMU_PLUGIN_VERSION 0

> +#define QEMU_PLUGIN_VERSION 1

> +

> +typedef void *(*qemu_plugin_global_dlsym_t)(void* context, const char *name);

>  

>  typedef struct {

>      /* string describing architecture */

> @@ -73,8 +71,23 @@ typedef struct {

>              int max_vcpus;

>          } system;

>      };

> +    void *context;

> +    qemu_plugin_global_dlsym_t dlsym;

>  } qemu_info_t;

>  

> +/**

> + * qemu_plugin_initialize() - Initialize a plugin before install

> + * @info: a block describing some details about the guest

> + *

> + * All plugins must export this symbol, and in most case using qemu-plugin.h

> + * provided implementation directly.

> + * For plugin provide this function, the QEMU_PLUGIN_VERSION should >= 1

> + *

> + * Note: This function only used to loading qemu's exported functions, nothing

> + * else should doding in this function.

> + */

> +QEMU_PLUGIN_EXPORT int qemu_plugin_initialize(const qemu_info_t *info);

> +


So this is essentially working around the linker/dlopen stage and
manually linking in all the API functions? Does this affect the
efficiency of the API calls?
> -void qemu_plugin_outs(const char *string);

> +typedef void (*qemu_plugin_outs_t)(const char *string);

> +

> +#if !defined(QEMU_PLUGIN_API_IMPLEMENTATION)

> +#if defined(QEMU_PLUGIN_IMPLEMENTATION)

> +#define QEMU_PLUGIN_EXTERN

> +#else

> +#define QEMU_PLUGIN_EXTERN extern

> +#endif


As mentioned in the earlier patch I want to understand why the extern is
required. Could we avoid it with a parameter to the compiler when
building plugins?

<snip>
>  

>  static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)

>  {

> +    qemu_plugin_initialize_func_t initialize = NULL;

>      qemu_plugin_install_func_t install;

>      struct qemu_plugin_ctx *ctx;

>      gpointer sym;

>      int rc;

> +    int version = -1;

>  

>      ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));

>      memset(ctx, 0, sizeof(*ctx));

> @@ -184,7 +187,7 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)

>                       desc->path, g_module_error());

>          goto err_symbol;

>      } else {

> -        int version = *(int *)sym;

> +        version = *(int *)sym;

>          if (version < QEMU_PLUGIN_MIN_VERSION) {

>              error_report("TCG plugin %s requires API version %d, but "

>                           "this QEMU supports only a minimum version of %d",

> @@ -198,6 +201,21 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)

>          }

>      }

>  

> +    if (version >= QEMU_PLUGIN_VERSION_1) {

> +        /* This version should call to qemu_plugin_initialize first */

> +        if (!g_module_symbol(ctx->handle, "qemu_plugin_initialize", &sym)) {

> +            error_report("%s: %s", __func__, g_module_error());

> +            goto err_symbol;

> +        }

> +        initialize = (qemu_plugin_initialize_func_t) sym;

> +        /* symbol was found; it could be NULL though */

> +        if (initialize == NULL) {

> +            error_report("%s: %s: qemu_plugin_initialize is NULL",

> +                        __func__, desc->path);

> +            goto err_symbol;

> +        }

> +    }

> +

>      qemu_rec_mutex_lock(&plugin.lock);

>  

>      /* find an unused random id with &ctx as the seed */

> @@ -216,6 +234,16 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)

>          }

>      }

>      QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);

> +    if (initialize != NULL) {

> +        rc = initialize(info);

> +        if (rc) {

> +            error_report("%s: qemu_plugin_initialize returned error code %d",

> +                        __func__, rc);

> +            /* qemu_plugin_initialize only loading function symbols */

> +            goto err_symbol;

> +        }

> +    }

> +

>      ctx->installing = true;

>      rc = install(ctx->id, info, desc->argc, desc->argv);

>      ctx->installing = false;

> @@ -254,6 +282,17 @@ static void plugin_desc_free(struct qemu_plugin_desc *desc)

>      g_free(desc);

>  }

>  

> +static void *qemu_plugin_global_dlsym(void* context, const char *name)

> +{

> +    GModule *global_handle = context;

> +    gpointer sym = NULL;

> +    if (!g_module_symbol(global_handle, name, &sym)) {

> +        error_report("%s: %s", __func__, g_module_error());

> +        return NULL;

> +    }

> +    return sym;

> +}

> +

>  /**

>   * qemu_plugin_load_list - load a list of plugins

>   * @head: head of the list of descriptors of the plugins to be loaded

> @@ -267,6 +306,7 @@ int qemu_plugin_load_list(QemuPluginList *head)

>  {

>      struct qemu_plugin_desc *desc, *next;

>      g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);

> +    GModule *global_handle = NULL;

>  

>      info->target_name = TARGET_NAME;

>      info->version.min = QEMU_PLUGIN_MIN_VERSION;

> @@ -276,6 +316,12 @@ int qemu_plugin_load_list(QemuPluginList *head)

>      info->system_emulation = true;

>      info->system.smp_vcpus = ms->smp.cpus;

>      info->system.max_vcpus = ms->smp.max_cpus;

> +    global_handle = g_module_open(NULL, G_MODULE_BIND_LOCAL);

> +    if (global_handle == NULL) {

> +        goto err_dlopen;

> +    }

> +    info->dlsym = qemu_plugin_global_dlsym;

> +    info->context = (void*)global_handle;

>  #else

>      info->system_emulation = false;

>  #endif

> @@ -289,6 +335,8 @@ int qemu_plugin_load_list(QemuPluginList *head)

>          }

>          QTAILQ_REMOVE(head, desc, entry);

>      }

> +

> +err_dlopen:

>      return 0;


This doesn't compile cleanly for both linux-user and softmmu:

  Compiling C object libqemu-aarch64-linux-user.fa.p/tcg_tcg-common.c.o
  ../../plugins/loader.c: In function ‘qemu_plugin_load_list’:
  ../../plugins/loader.c:339:1: error: label ‘err_dlopen’ defined but not used [-Werror=unused-label]
   err_dlopen:
   ^~~~~~~~~~
  ../../plugins/loader.c:309:14: error: unused variable ‘global_handle’ [-Werror=unused-variable]
       GModule *global_handle = NULL;
                ^~~~~~~~~~~~~
  At top level:
  ../../plugins/loader.c:285:14: error: ‘qemu_plugin_global_dlsym’ defined but not used [-Werror=unused-function]
   static void *qemu_plugin_global_dlsym(void* context, const char *name)
                ^~~~~~~~~~~~~~~~~~~~~~~~
  cc1: all warnings being treated as errors
  make: *** [Makefile.ninja:6703: libqemu-aarch64-linux-user.fa.p/plugins_loader.c.o] Error 1
  make: *** Waiting for unfinished jobs....

-- 
Alex Bennée
罗勇刚(Yonggang Luo) Oct. 6, 2020, 12:08 p.m. UTC | #2
On Tue, Oct 6, 2020 at 7:29 PM Alex Bennée <alex.bennee@linaro.org> wrote:
>

>

> Yonggang Luo <luoyonggang@gmail.com> writes:

>

> > We removed the need of .symbols file, so is the

> > configure script, if we one expose a function to qemu-plugin

> > just need prefix the function with QEMU_PLUGIN_EXPORT

> >

> > Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>

> > ---

> >  Makefile                     |   1 -

> >  configure                    |  71 -------------

> >  contrib/plugins/hotblocks.c  |   1 +

> >  contrib/plugins/hotpages.c   |   1 +

> >  contrib/plugins/howvec.c     |   1 +

> >  contrib/plugins/lockstep.c   |   1 +

> >  include/qemu/qemu-plugin.h   | 197 +++++++++++++++++++++++++++--------

> >  meson.build                  |   6 +-

> >  plugins/api.c                |  62 +++++------

> >  plugins/core.c               |  10 +-

> >  plugins/loader.c             |  50 ++++++++-

> >  plugins/meson.build          |  10 +-

> >  plugins/plugin.h             |   1 +

> >  plugins/qemu-plugins.symbols |  40 -------

> >  tests/plugin/bb.c            |   1 +

> >  tests/plugin/empty.c         |   1 +

> >  tests/plugin/insn.c          |   1 +

> >  tests/plugin/mem.c           |   1 +

> >  18 files changed, 251 insertions(+), 205 deletions(-)

> >  delete mode 100644 plugins/qemu-plugins.symbols

> >

> > diff --git a/Makefile b/Makefile

> > index 54fc1a9d10..9981dd5209 100644

> > --- a/Makefile

> > +++ b/Makefile

> > @@ -105,7 +105,6 @@ config-host.mak: $(SRC_PATH)/configure

$(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
> >

> >  # Force configure to re-run if the API symbols are updated

> >  ifeq ($(CONFIG_PLUGIN),y)

> > -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols

> >

> >  .PHONY: plugins

> >  plugins:

> > diff --git a/configure b/configure

> > index 1c21a73c3b..ea447919fc 100755

> > --- a/configure

> > +++ b/configure

> > @@ -5435,61 +5435,6 @@ if compile_prog "" "" ; then

> >    atomic64=yes

> >  fi

> >

> > -#########################################

> > -# See if --dynamic-list is supported by the linker

> > -ld_dynamic_list="no"

> > -if test "$static" = "no" ; then

> > -    cat > $TMPTXT <<EOF

> > -{

> > -  foo;

> > -};

> > -EOF

> > -

> > -    cat > $TMPC <<EOF

> > -#include <stdio.h>

> > -void foo(void);

> > -

> > -void foo(void)

> > -{

> > -  printf("foo\n");

> > -}

> > -

> > -int main(void)

> > -{

> > -  foo();

> > -  return 0;

> > -}

> > -EOF

> > -

> > -    if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then

> > -        ld_dynamic_list="yes"

> > -    fi

> > -fi

> > -

> > -#########################################

> > -# See if -exported_symbols_list is supported by the linker

> > -

> > -ld_exported_symbols_list="no"

> > -if test "$static" = "no" ; then

> > -    cat > $TMPTXT <<EOF

> > -  _foo

> > -EOF

> > -

> > -    if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then

> > -        ld_exported_symbols_list="yes"

> > -    fi

> > -fi

> > -

> > -if  test "$plugins" = "yes" &&

> > -    test "$ld_dynamic_list" = "no" &&

> > -    test "$ld_exported_symbols_list" = "no" ; then

> > -  error_exit \

> > -      "Plugin support requires dynamic linking and specifying a set of

symbols " \
> > -      "that are exported to plugins. Unfortunately your linker doesn't

" \
> > -      "support the flag (--dynamic-list or -exported_symbols_list)

used " \
> > -      "for this purpose. You can't build with --static."

> > -fi

> > -

> >  ########################################

> >  # See if __attribute__((alias)) is supported.

> >  # This false for Xcode 9, but has been remedied for Xcode 10.

> > @@ -7074,22 +7019,6 @@ fi

> >

> >  if test "$plugins" = "yes" ; then

> >      echo "CONFIG_PLUGIN=y" >> $config_host_mak

> > -    # Copy the export object list to the build dir

> > -    if test "$ld_dynamic_list" = "yes" ; then

> > -     echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak

> > -     ld_symbols=qemu-plugins-ld.symbols

> > -     cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols

> > -    elif test "$ld_exported_symbols_list" = "yes" ; then

> > -     echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak

> > -     ld64_symbols=qemu-plugins-ld64.symbols

> > -     echo "# Automatically generated by configure - do not modify" >

$ld64_symbols
> > -     grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed

's/;//g' | \
> > -         sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols

> > -    else

> > -     error_exit \

> > -         "If \$plugins=yes, either \$ld_dynamic_list or " \

> > -         "\$ld_exported_symbols_list should have been set to 'yes'."

> > -    fi

> >  fi

> >

> >  if test -n "$gdb_bin" ; then

> > diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c

> > index 37435a3fc7..39e77d2980 100644

> > --- a/contrib/plugins/hotblocks.c

> > +++ b/contrib/plugins/hotblocks.c

> > @@ -13,6 +13,7 @@

> >  #include <stdio.h>

> >  #include <glib.h>

> >

> > +#define QEMU_PLUGIN_IMPLEMENTATION

> >  #include <qemu-plugin.h>

>

> As mentioned in earlier patch we should be able to just have the tweak

> in api.c and avoid touching all the plugins themselves.

> >

> > -#define QEMU_PLUGIN_VERSION 0

> > +#define QEMU_PLUGIN_VERSION 1

> > +

> > +typedef void *(*qemu_plugin_global_dlsym_t)(void* context, const char

*name);
> >

> >  typedef struct {

> >      /* string describing architecture */

> > @@ -73,8 +71,23 @@ typedef struct {

> >              int max_vcpus;

> >          } system;

> >      };

> > +    void *context;

> > +    qemu_plugin_global_dlsym_t dlsym;

> >  } qemu_info_t;

> >

> > +/**

> > + * qemu_plugin_initialize() - Initialize a plugin before install

> > + * @info: a block describing some details about the guest

> > + *

> > + * All plugins must export this symbol, and in most case using

qemu-plugin.h
> > + * provided implementation directly.

> > + * For plugin provide this function, the QEMU_PLUGIN_VERSION should >=

1
> > + *

> > + * Note: This function only used to loading qemu's exported functions,

nothing
> > + * else should doding in this function.

> > + */

> > +QEMU_PLUGIN_EXPORT int qemu_plugin_initialize(const qemu_info_t *info);

> > +

>

> So this is essentially working around the linker/dlopen stage and

> manually linking in all the API functions? Does this affect the

> efficiency of the API calls?

> > -void qemu_plugin_outs(const char *string);

> > +typedef void (*qemu_plugin_outs_t)(const char *string);

> > +

> > +#if !defined(QEMU_PLUGIN_API_IMPLEMENTATION)

> > +#if defined(QEMU_PLUGIN_IMPLEMENTATION)

> > +#define QEMU_PLUGIN_EXTERN

> > +#else

> > +#define QEMU_PLUGIN_EXTERN extern

> > +#endif

>

> As mentioned in the earlier patch I want to understand why the extern is

> required. Could we avoid it with a parameter to the compiler when

> building plugins?

Hi, I've publisehd with v5 of the patch and explain that,

If we only have a single .c file in a plugin, then define
QEMU_PLUGIN_EXTERN to empty is OK, but if we have multiple .c files
in a plugin, then we need distinguish the implementation and the
deceleration. only the main .c file should define the macro
QEMU_PLUGIN_IMPLEMENTATION
other sources are user and should use extern
>

> <snip>

> >

> >  static int plugin_load(struct qemu_plugin_desc *desc, const

qemu_info_t *info)
> >  {

> > +    qemu_plugin_initialize_func_t initialize = NULL;

> >      qemu_plugin_install_func_t install;

> >      struct qemu_plugin_ctx *ctx;

> >      gpointer sym;

> >      int rc;

> > +    int version = -1;

> >

> >      ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));

> >      memset(ctx, 0, sizeof(*ctx));

> > @@ -184,7 +187,7 @@ static int plugin_load(struct qemu_plugin_desc

*desc, const qemu_info_t *info)
> >                       desc->path, g_module_error());

> >          goto err_symbol;

> >      } else {

> > -        int version = *(int *)sym;

> > +        version = *(int *)sym;

> >          if (version < QEMU_PLUGIN_MIN_VERSION) {

> >              error_report("TCG plugin %s requires API version %d, but "

> >                           "this QEMU supports only a minimum version of

%d",
> > @@ -198,6 +201,21 @@ static int plugin_load(struct qemu_plugin_desc

*desc, const qemu_info_t *info)
> >          }

> >      }

> >

> > +    if (version >= QEMU_PLUGIN_VERSION_1) {

> > +        /* This version should call to qemu_plugin_initialize first */

> > +        if (!g_module_symbol(ctx->handle, "qemu_plugin_initialize",

&sym)) {
> > +            error_report("%s: %s", __func__, g_module_error());

> > +            goto err_symbol;

> > +        }

> > +        initialize = (qemu_plugin_initialize_func_t) sym;

> > +        /* symbol was found; it could be NULL though */

> > +        if (initialize == NULL) {

> > +            error_report("%s: %s: qemu_plugin_initialize is NULL",

> > +                        __func__, desc->path);

> > +            goto err_symbol;

> > +        }

> > +    }

> > +

> >      qemu_rec_mutex_lock(&plugin.lock);

> >

> >      /* find an unused random id with &ctx as the seed */

> > @@ -216,6 +234,16 @@ static int plugin_load(struct qemu_plugin_desc

*desc, const qemu_info_t *info)
> >          }

> >      }

> >      QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);

> > +    if (initialize != NULL) {

> > +        rc = initialize(info);

> > +        if (rc) {

> > +            error_report("%s: qemu_plugin_initialize returned error

code %d",
> > +                        __func__, rc);

> > +            /* qemu_plugin_initialize only loading function symbols */

> > +            goto err_symbol;

> > +        }

> > +    }

> > +

> >      ctx->installing = true;

> >      rc = install(ctx->id, info, desc->argc, desc->argv);

> >      ctx->installing = false;

> > @@ -254,6 +282,17 @@ static void plugin_desc_free(struct

qemu_plugin_desc *desc)
> >      g_free(desc);

> >  }

> >

> > +static void *qemu_plugin_global_dlsym(void* context, const char *name)

> > +{

> > +    GModule *global_handle = context;

> > +    gpointer sym = NULL;

> > +    if (!g_module_symbol(global_handle, name, &sym)) {

> > +        error_report("%s: %s", __func__, g_module_error());

> > +        return NULL;

> > +    }

> > +    return sym;

> > +}

> > +

> >  /**

> >   * qemu_plugin_load_list - load a list of plugins

> >   * @head: head of the list of descriptors of the plugins to be loaded

> > @@ -267,6 +306,7 @@ int qemu_plugin_load_list(QemuPluginList *head)

> >  {

> >      struct qemu_plugin_desc *desc, *next;

> >      g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);

> > +    GModule *global_handle = NULL;

> >

> >      info->target_name = TARGET_NAME;

> >      info->version.min = QEMU_PLUGIN_MIN_VERSION;

> > @@ -276,6 +316,12 @@ int qemu_plugin_load_list(QemuPluginList *head)

> >      info->system_emulation = true;

> >      info->system.smp_vcpus = ms->smp.cpus;

> >      info->system.max_vcpus = ms->smp.max_cpus;

> > +    global_handle = g_module_open(NULL, G_MODULE_BIND_LOCAL);

> > +    if (global_handle == NULL) {

> > +        goto err_dlopen;

> > +    }

> > +    info->dlsym = qemu_plugin_global_dlsym;

> > +    info->context = (void*)global_handle;

> >  #else

> >      info->system_emulation = false;

> >  #endif

> > @@ -289,6 +335,8 @@ int qemu_plugin_load_list(QemuPluginList *head)

> >          }

> >          QTAILQ_REMOVE(head, desc, entry);

> >      }

> > +

> > +err_dlopen:

> >      return 0;

>

> This doesn't compile cleanly for both linux-user and softmmu:

>

>   Compiling C object libqemu-aarch64-linux-user.fa.p/tcg_tcg-common.c.o

>   ../../plugins/loader.c: In function ‘qemu_plugin_load_list’:

>   ../../plugins/loader.c:339:1: error: label ‘err_dlopen’ defined but not

used [-Werror=unused-label]
>    err_dlopen:

>    ^~~~~~~~~~

>   ../../plugins/loader.c:309:14: error: unused variable ‘global_handle’

[-Werror=unused-variable]
>        GModule *global_handle = NULL;

>                 ^~~~~~~~~~~~~

>   At top level:

>   ../../plugins/loader.c:285:14: error: ‘qemu_plugin_global_dlsym’

defined but not used [-Werror=unused-function]
>    static void *qemu_plugin_global_dlsym(void* context, const char *name)

>                 ^~~~~~~~~~~~~~~~~~~~~~~~

>   cc1: all warnings being treated as errors

>   make: *** [Makefile.ninja:6703:

libqemu-aarch64-linux-user.fa.p/plugins_loader.c.o] Error 1
>   make: *** Waiting for unfinished jobs....

>

> --

> Alex Bennée




--
         此致
礼
罗勇刚
Yours
    sincerely,
Yonggang Luo
<div dir="ltr"><br><br>On Tue, Oct 6, 2020 at 7:29 PM Alex Bennée &lt;<a href="mailto:alex.bennee@linaro.org">alex.bennee@linaro.org</a>&gt; wrote:<br>&gt;<br>&gt;<br>&gt; Yonggang Luo &lt;<a href="mailto:luoyonggang@gmail.com">luoyonggang@gmail.com</a>&gt; writes:<br>&gt;<br>&gt; &gt; We removed the need of .symbols file, so is the<br>&gt; &gt; configure script, if we one expose a function to qemu-plugin<br>&gt; &gt; just need prefix the function with QEMU_PLUGIN_EXPORT<br>&gt; &gt;<br>&gt; &gt; Signed-off-by: Yonggang Luo &lt;<a href="mailto:luoyonggang@gmail.com">luoyonggang@gmail.com</a>&gt;<br>&gt; &gt; ---<br>&gt; &gt;  Makefile                     |   1 -<br>&gt; &gt;  configure                    |  71 -------------<br>&gt; &gt;  contrib/plugins/hotblocks.c  |   1 +<br>&gt; &gt;  contrib/plugins/hotpages.c   |   1 +<br>&gt; &gt;  contrib/plugins/howvec.c     |   1 +<br>&gt; &gt;  contrib/plugins/lockstep.c   |   1 +<br>&gt; &gt;  include/qemu/qemu-plugin.h   | 197 +++++++++++++++++++++++++++--------<br>&gt; &gt;  meson.build                  |   6 +-<br>&gt; &gt;  plugins/api.c                |  62 +++++------<br>&gt; &gt;  plugins/core.c               |  10 +-<br>&gt; &gt;  plugins/loader.c             |  50 ++++++++-<br>&gt; &gt;  plugins/meson.build          |  10 +-<br>&gt; &gt;  plugins/plugin.h             |   1 +<br>&gt; &gt;  plugins/qemu-plugins.symbols |  40 -------<br>&gt; &gt;  tests/plugin/bb.c            |   1 +<br>&gt; &gt;  tests/plugin/empty.c         |   1 +<br>&gt; &gt;  tests/plugin/insn.c          |   1 +<br>&gt; &gt;  tests/plugin/mem.c           |   1 +<br>&gt; &gt;  18 files changed, 251 insertions(+), 205 deletions(-)<br>&gt; &gt;  delete mode 100644 plugins/qemu-plugins.symbols<br>&gt; &gt;<br>&gt; &gt; diff --git a/Makefile b/Makefile<br>&gt; &gt; index 54fc1a9d10..9981dd5209 100644<br>&gt; &gt; --- a/Makefile<br>&gt; &gt; +++ b/Makefile<br>&gt; &gt; @@ -105,7 +105,6 @@ config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION<br>&gt; &gt; <br>&gt; &gt;  # Force configure to re-run if the API symbols are updated<br>&gt; &gt;  ifeq ($(CONFIG_PLUGIN),y)<br>&gt; &gt; -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols<br>&gt; &gt; <br>&gt; &gt;  .PHONY: plugins<br>&gt; &gt;  plugins:<br>&gt; &gt; diff --git a/configure b/configure<br>&gt; &gt; index 1c21a73c3b..ea447919fc 100755<br>&gt; &gt; --- a/configure<br>&gt; &gt; +++ b/configure<br>&gt; &gt; @@ -5435,61 +5435,6 @@ if compile_prog &quot;&quot; &quot;&quot; ; then<br>&gt; &gt;    atomic64=yes<br>&gt; &gt;  fi<br>&gt; &gt; <br>&gt; &gt; -#########################################<br>&gt; &gt; -# See if --dynamic-list is supported by the linker<br>&gt; &gt; -ld_dynamic_list=&quot;no&quot;<br>&gt; &gt; -if test &quot;$static&quot; = &quot;no&quot; ; then<br>&gt; &gt; -    cat &gt; $TMPTXT &lt;&lt;EOF<br>&gt; &gt; -{<br>&gt; &gt; -  foo;<br>&gt; &gt; -};<br>&gt; &gt; -EOF<br>&gt; &gt; -<br>&gt; &gt; -    cat &gt; $TMPC &lt;&lt;EOF<br>&gt; &gt; -#include &lt;stdio.h&gt;<br>&gt; &gt; -void foo(void);<br>&gt; &gt; -<br>&gt; &gt; -void foo(void)<br>&gt; &gt; -{<br>&gt; &gt; -  printf(&quot;foo\n&quot;);<br>&gt; &gt; -}<br>&gt; &gt; -<br>&gt; &gt; -int main(void)<br>&gt; &gt; -{<br>&gt; &gt; -  foo();<br>&gt; &gt; -  return 0;<br>&gt; &gt; -}<br>&gt; &gt; -EOF<br>&gt; &gt; -<br>&gt; &gt; -    if compile_prog &quot;&quot; &quot;-Wl,--dynamic-list=$TMPTXT&quot; ; then<br>&gt; &gt; -        ld_dynamic_list=&quot;yes&quot;<br>&gt; &gt; -    fi<br>&gt; &gt; -fi<br>&gt; &gt; -<br>&gt; &gt; -#########################################<br>&gt; &gt; -# See if -exported_symbols_list is supported by the linker<br>&gt; &gt; -<br>&gt; &gt; -ld_exported_symbols_list=&quot;no&quot;<br>&gt; &gt; -if test &quot;$static&quot; = &quot;no&quot; ; then<br>&gt; &gt; -    cat &gt; $TMPTXT &lt;&lt;EOF<br>&gt; &gt; -  _foo<br>&gt; &gt; -EOF<br>&gt; &gt; -<br>&gt; &gt; -    if compile_prog &quot;&quot; &quot;-Wl,-exported_symbols_list,$TMPTXT&quot; ; then<br>&gt; &gt; -        ld_exported_symbols_list=&quot;yes&quot;<br>&gt; &gt; -    fi<br>&gt; &gt; -fi<br>&gt; &gt; -<br>&gt; &gt; -if  test &quot;$plugins&quot; = &quot;yes&quot; &amp;&amp;<br>&gt; &gt; -    test &quot;$ld_dynamic_list&quot; = &quot;no&quot; &amp;&amp;<br>&gt; &gt; -    test &quot;$ld_exported_symbols_list&quot; = &quot;no&quot; ; then<br>&gt; &gt; -  error_exit \<br>&gt; &gt; -      &quot;Plugin support requires dynamic linking and specifying a set of symbols &quot; \<br>&gt; &gt; -      &quot;that are exported to plugins. Unfortunately your linker doesn&#39;t &quot; \<br>&gt; &gt; -      &quot;support the flag (--dynamic-list or -exported_symbols_list) used &quot; \<br>&gt; &gt; -      &quot;for this purpose. You can&#39;t build with --static.&quot;<br>&gt; &gt; -fi<br>&gt; &gt; -<br>&gt; &gt;  ########################################<br>&gt; &gt;  # See if __attribute__((alias)) is supported.<br>&gt; &gt;  # This false for Xcode 9, but has been remedied for Xcode 10.<br>&gt; &gt; @@ -7074,22 +7019,6 @@ fi<br>&gt; &gt; <br>&gt; &gt;  if test &quot;$plugins&quot; = &quot;yes&quot; ; then<br>&gt; &gt;      echo &quot;CONFIG_PLUGIN=y&quot; &gt;&gt; $config_host_mak<br>&gt; &gt; -    # Copy the export object list to the build dir<br>&gt; &gt; -    if test &quot;$ld_dynamic_list&quot; = &quot;yes&quot; ; then<br>&gt; &gt; -     echo &quot;CONFIG_HAS_LD_DYNAMIC_LIST=yes&quot; &gt;&gt; $config_host_mak<br>&gt; &gt; -     ld_symbols=qemu-plugins-ld.symbols<br>&gt; &gt; -     cp &quot;$source_path/plugins/qemu-plugins.symbols&quot; $ld_symbols<br>&gt; &gt; -    elif test &quot;$ld_exported_symbols_list&quot; = &quot;yes&quot; ; then<br>&gt; &gt; -     echo &quot;CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes&quot; &gt;&gt; $config_host_mak<br>&gt; &gt; -     ld64_symbols=qemu-plugins-ld64.symbols<br>&gt; &gt; -     echo &quot;# Automatically generated by configure - do not modify&quot; &gt; $ld64_symbols<br>&gt; &gt; -     grep &#39;qemu_&#39; &quot;$source_path/plugins/qemu-plugins.symbols&quot; | sed &#39;s/;//g&#39; | \<br>&gt; &gt; -         sed -E &#39;s/^[[:space:]]*(.*)/_\1/&#39; &gt;&gt; $ld64_symbols<br>&gt; &gt; -    else<br>&gt; &gt; -     error_exit \<br>&gt; &gt; -         &quot;If \$plugins=yes, either \$ld_dynamic_list or &quot; \<br>&gt; &gt; -         &quot;\$ld_exported_symbols_list should have been set to &#39;yes&#39;.&quot;<br>&gt; &gt; -    fi<br>&gt; &gt;  fi<br>&gt; &gt; <br>&gt; &gt;  if test -n &quot;$gdb_bin&quot; ; then<br>&gt; &gt; diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c<br>&gt; &gt; index 37435a3fc7..39e77d2980 100644<br>&gt; &gt; --- a/contrib/plugins/hotblocks.c<br>&gt; &gt; +++ b/contrib/plugins/hotblocks.c<br>&gt; &gt; @@ -13,6 +13,7 @@<br>&gt; &gt;  #include &lt;stdio.h&gt;<br>&gt; &gt;  #include &lt;glib.h&gt;<br>&gt; &gt; <br>&gt; &gt; +#define QEMU_PLUGIN_IMPLEMENTATION<br>&gt; &gt;  #include &lt;qemu-plugin.h&gt;<br>&gt;<br>&gt; As mentioned in earlier patch we should be able to just have the tweak<br>&gt; in api.c and avoid touching all the plugins themselves.<br>&gt; &gt; <br>&gt; &gt; -#define QEMU_PLUGIN_VERSION 0<br>&gt; &gt; +#define QEMU_PLUGIN_VERSION 1<br>&gt; &gt; +<br>&gt; &gt; +typedef void *(*qemu_plugin_global_dlsym_t)(void* context, const char *name);<br>&gt; &gt; <br>&gt; &gt;  typedef struct {<br>&gt; &gt;      /* string describing architecture */<br>&gt; &gt; @@ -73,8 +71,23 @@ typedef struct {<br>&gt; &gt;              int max_vcpus;<br>&gt; &gt;          } system;<br>&gt; &gt;      };<br>&gt; &gt; +    void *context;<br>&gt; &gt; +    qemu_plugin_global_dlsym_t dlsym;<br>&gt; &gt;  } qemu_info_t;<br>&gt; &gt; <br>&gt; &gt; +/**<br>&gt; &gt; + * qemu_plugin_initialize() - Initialize a plugin before install<br>&gt; &gt; + * @info: a block describing some details about the guest<br>&gt; &gt; + *<br>&gt; &gt; + * All plugins must export this symbol, and in most case using qemu-plugin.h<br>&gt; &gt; + * provided implementation directly.<br>&gt; &gt; + * For plugin provide this function, the QEMU_PLUGIN_VERSION should &gt;= 1<br>&gt; &gt; + *<br>&gt; &gt; + * Note: This function only used to loading qemu&#39;s exported functions, nothing<br>&gt; &gt; + * else should doding in this function.<br>&gt; &gt; + */<br>&gt; &gt; +QEMU_PLUGIN_EXPORT int qemu_plugin_initialize(const qemu_info_t *info);<br>&gt; &gt; +<br>&gt;<br>&gt; So this is essentially working around the linker/dlopen stage and<br>&gt; manually linking in all the API functions? Does this affect the<br>&gt; efficiency of the API calls?<br>&gt; &gt; -void qemu_plugin_outs(const char *string);<br>&gt; &gt; +typedef void (*qemu_plugin_outs_t)(const char *string);<br>&gt; &gt; +<br>&gt; &gt; +#if !defined(QEMU_PLUGIN_API_IMPLEMENTATION)<br>&gt; &gt; +#if defined(QEMU_PLUGIN_IMPLEMENTATION)<br>&gt; &gt; +#define QEMU_PLUGIN_EXTERN<br>&gt; &gt; +#else<br>&gt; &gt; +#define QEMU_PLUGIN_EXTERN extern<br>&gt; &gt; +#endif<br>&gt;<br>&gt; As mentioned in the earlier patch I want to understand why the extern is<br>&gt; required. Could we avoid it with a parameter to the compiler when<br>&gt; building plugins?<div>Hi, I&#39;ve publisehd with v5 of the patch and explain that,</div><div><br></div><div>If we only have a single .c file in a plugin, then define<br>QEMU_PLUGIN_EXTERN to empty is OK, but if we have multiple .c files<br>in a plugin, then we need distinguish the implementation and the<br>deceleration. only the main .c file should define the macro QEMU_PLUGIN_IMPLEMENTATION<br>other sources are user and should use extern<br>&gt;<br>&gt; &lt;snip&gt;<br>&gt; &gt; <br>&gt; &gt;  static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)<br>&gt; &gt;  {<br>&gt; &gt; +    qemu_plugin_initialize_func_t initialize = NULL;<br>&gt; &gt;      qemu_plugin_install_func_t install;<br>&gt; &gt;      struct qemu_plugin_ctx *ctx;<br>&gt; &gt;      gpointer sym;<br>&gt; &gt;      int rc;<br>&gt; &gt; +    int version = -1;<br>&gt; &gt; <br>&gt; &gt;      ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));<br>&gt; &gt;      memset(ctx, 0, sizeof(*ctx));<br>&gt; &gt; @@ -184,7 +187,7 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)<br>&gt; &gt;                       desc-&gt;path, g_module_error());<br>&gt; &gt;          goto err_symbol;<br>&gt; &gt;      } else {<br>&gt; &gt; -        int version = *(int *)sym;<br>&gt; &gt; +        version = *(int *)sym;<br>&gt; &gt;          if (version &lt; QEMU_PLUGIN_MIN_VERSION) {<br>&gt; &gt;              error_report(&quot;TCG plugin %s requires API version %d, but &quot;<br>&gt; &gt;                           &quot;this QEMU supports only a minimum version of %d&quot;,<br>&gt; &gt; @@ -198,6 +201,21 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)<br>&gt; &gt;          }<br>&gt; &gt;      }<br>&gt; &gt; <br>&gt; &gt; +    if (version &gt;= QEMU_PLUGIN_VERSION_1) {<br>&gt; &gt; +        /* This version should call to qemu_plugin_initialize first */<br>&gt; &gt; +        if (!g_module_symbol(ctx-&gt;handle, &quot;qemu_plugin_initialize&quot;, &amp;sym)) {<br>&gt; &gt; +            error_report(&quot;%s: %s&quot;, __func__, g_module_error());<br>&gt; &gt; +            goto err_symbol;<br>&gt; &gt; +        }<br>&gt; &gt; +        initialize = (qemu_plugin_initialize_func_t) sym;<br>&gt; &gt; +        /* symbol was found; it could be NULL though */<br>&gt; &gt; +        if (initialize == NULL) {<br>&gt; &gt; +            error_report(&quot;%s: %s: qemu_plugin_initialize is NULL&quot;,<br>&gt; &gt; +                        __func__, desc-&gt;path);<br>&gt; &gt; +            goto err_symbol;<br>&gt; &gt; +        }<br>&gt; &gt; +    }<br>&gt; &gt; +<br>&gt; &gt;      qemu_rec_mutex_lock(&amp;plugin.lock);<br>&gt; &gt; <br>&gt; &gt;      /* find an unused random id with &amp;ctx as the seed */<br>&gt; &gt; @@ -216,6 +234,16 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)<br>&gt; &gt;          }<br>&gt; &gt;      }<br>&gt; &gt;      QTAILQ_INSERT_TAIL(&amp;plugin.ctxs, ctx, entry);<br>&gt; &gt; +    if (initialize != NULL) {<br>&gt; &gt; +        rc = initialize(info);<br>&gt; &gt; +        if (rc) {<br>&gt; &gt; +            error_report(&quot;%s: qemu_plugin_initialize returned error code %d&quot;,<br>&gt; &gt; +                        __func__, rc);<br>&gt; &gt; +            /* qemu_plugin_initialize only loading function symbols */<br>&gt; &gt; +            goto err_symbol;<br>&gt; &gt; +        }<br>&gt; &gt; +    }<br>&gt; &gt; +<br>&gt; &gt;      ctx-&gt;installing = true;<br>&gt; &gt;      rc = install(ctx-&gt;id, info, desc-&gt;argc, desc-&gt;argv);<br>&gt; &gt;      ctx-&gt;installing = false;<br>&gt; &gt; @@ -254,6 +282,17 @@ static void plugin_desc_free(struct qemu_plugin_desc *desc)<br>&gt; &gt;      g_free(desc);<br>&gt; &gt;  }<br>&gt; &gt; <br>&gt; &gt; +static void *qemu_plugin_global_dlsym(void* context, const char *name)<br>&gt; &gt; +{<br>&gt; &gt; +    GModule *global_handle = context;<br>&gt; &gt; +    gpointer sym = NULL;<br>&gt; &gt; +    if (!g_module_symbol(global_handle, name, &amp;sym)) {<br>&gt; &gt; +        error_report(&quot;%s: %s&quot;, __func__, g_module_error());<br>&gt; &gt; +        return NULL;<br>&gt; &gt; +    }<br>&gt; &gt; +    return sym;<br>&gt; &gt; +}<br>&gt; &gt; +<br>&gt; &gt;  /**<br>&gt; &gt;   * qemu_plugin_load_list - load a list of plugins<br>&gt; &gt;   * @head: head of the list of descriptors of the plugins to be loaded<br>&gt; &gt; @@ -267,6 +306,7 @@ int qemu_plugin_load_list(QemuPluginList *head)<br>&gt; &gt;  {<br>&gt; &gt;      struct qemu_plugin_desc *desc, *next;<br>&gt; &gt;      g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);<br>&gt; &gt; +    GModule *global_handle = NULL;<br>&gt; &gt; <br>&gt; &gt;      info-&gt;target_name = TARGET_NAME;<br>&gt; &gt;      info-&gt;version.min = QEMU_PLUGIN_MIN_VERSION;<br>&gt; &gt; @@ -276,6 +316,12 @@ int qemu_plugin_load_list(QemuPluginList *head)<br>&gt; &gt;      info-&gt;system_emulation = true;<br>&gt; &gt;      info-&gt;system.smp_vcpus = ms-&gt;smp.cpus;<br>&gt; &gt;      info-&gt;system.max_vcpus = ms-&gt;smp.max_cpus;<br>&gt; &gt; +    global_handle = g_module_open(NULL, G_MODULE_BIND_LOCAL);<br>&gt; &gt; +    if (global_handle == NULL) {<br>&gt; &gt; +        goto err_dlopen;<br>&gt; &gt; +    }<br>&gt; &gt; +    info-&gt;dlsym = qemu_plugin_global_dlsym;<br>&gt; &gt; +    info-&gt;context = (void*)global_handle;<br>&gt; &gt;  #else<br>&gt; &gt;      info-&gt;system_emulation = false;<br>&gt; &gt;  #endif<br>&gt; &gt; @@ -289,6 +335,8 @@ int qemu_plugin_load_list(QemuPluginList *head)<br>&gt; &gt;          }<br>&gt; &gt;          QTAILQ_REMOVE(head, desc, entry);<br>&gt; &gt;      }<br>&gt; &gt; +<br>&gt; &gt; +err_dlopen:<br>&gt; &gt;      return 0;<br>&gt;<br>&gt; This doesn&#39;t compile cleanly for both linux-user and softmmu:<br>&gt;<br>&gt;   Compiling C object libqemu-aarch64-linux-user.fa.p/tcg_tcg-common.c.o<br>&gt;   ../../plugins/loader.c: In function ‘qemu_plugin_load_list’:<br>&gt;   ../../plugins/loader.c:339:1: error: label ‘err_dlopen’ defined but not used [-Werror=unused-label]<br>&gt;    err_dlopen:<br>&gt;    ^~~~~~~~~~<br>&gt;   ../../plugins/loader.c:309:14: error: unused variable ‘global_handle’ [-Werror=unused-variable]<br>&gt;        GModule *global_handle = NULL;<br>&gt;                 ^~~~~~~~~~~~~<br>&gt;   At top level:<br>&gt;   ../../plugins/loader.c:285:14: error: ‘qemu_plugin_global_dlsym’ defined but not used [-Werror=unused-function]<br>&gt;    static void *qemu_plugin_global_dlsym(void* context, const char *name)<br>&gt;                 ^~~~~~~~~~~~~~~~~~~~~~~~<br>&gt;   cc1: all warnings being treated as errors<br>&gt;   make: *** [Makefile.ninja:6703: libqemu-aarch64-linux-user.fa.p/plugins_loader.c.o] Error 1<br>&gt;   make: *** Waiting for unfinished jobs....<br>&gt;<br>&gt; --<br>&gt; Alex Bennée<br><br><br><br>--<br>         此致<br>礼<br>罗勇刚<br>Yours<br>    sincerely,<br>Yonggang Luo</div></div>
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 54fc1a9d10..9981dd5209 100644
--- a/Makefile
+++ b/Makefile
@@ -105,7 +105,6 @@  config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
 
 # Force configure to re-run if the API symbols are updated
 ifeq ($(CONFIG_PLUGIN),y)
-config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols
 
 .PHONY: plugins
 plugins:
diff --git a/configure b/configure
index 1c21a73c3b..ea447919fc 100755
--- a/configure
+++ b/configure
@@ -5435,61 +5435,6 @@  if compile_prog "" "" ; then
   atomic64=yes
 fi
 
-#########################################
-# See if --dynamic-list is supported by the linker
-ld_dynamic_list="no"
-if test "$static" = "no" ; then
-    cat > $TMPTXT <<EOF
-{
-  foo;
-};
-EOF
-
-    cat > $TMPC <<EOF
-#include <stdio.h>
-void foo(void);
-
-void foo(void)
-{
-  printf("foo\n");
-}
-
-int main(void)
-{
-  foo();
-  return 0;
-}
-EOF
-
-    if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
-        ld_dynamic_list="yes"
-    fi
-fi
-
-#########################################
-# See if -exported_symbols_list is supported by the linker
-
-ld_exported_symbols_list="no"
-if test "$static" = "no" ; then
-    cat > $TMPTXT <<EOF
-  _foo
-EOF
-
-    if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
-        ld_exported_symbols_list="yes"
-    fi
-fi
-
-if  test "$plugins" = "yes" &&
-    test "$ld_dynamic_list" = "no" &&
-    test "$ld_exported_symbols_list" = "no" ; then
-  error_exit \
-      "Plugin support requires dynamic linking and specifying a set of symbols " \
-      "that are exported to plugins. Unfortunately your linker doesn't " \
-      "support the flag (--dynamic-list or -exported_symbols_list) used " \
-      "for this purpose. You can't build with --static."
-fi
-
 ########################################
 # See if __attribute__((alias)) is supported.
 # This false for Xcode 9, but has been remedied for Xcode 10.
@@ -7074,22 +7019,6 @@  fi
 
 if test "$plugins" = "yes" ; then
     echo "CONFIG_PLUGIN=y" >> $config_host_mak
-    # Copy the export object list to the build dir
-    if test "$ld_dynamic_list" = "yes" ; then
-	echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak
-	ld_symbols=qemu-plugins-ld.symbols
-	cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols
-    elif test "$ld_exported_symbols_list" = "yes" ; then
-	echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak
-	ld64_symbols=qemu-plugins-ld64.symbols
-	echo "# Automatically generated by configure - do not modify" > $ld64_symbols
-	grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \
-	    sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols
-    else
-	error_exit \
-	    "If \$plugins=yes, either \$ld_dynamic_list or " \
-	    "\$ld_exported_symbols_list should have been set to 'yes'."
-    fi
 fi
 
 if test -n "$gdb_bin" ; then
diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c
index 37435a3fc7..39e77d2980 100644
--- a/contrib/plugins/hotblocks.c
+++ b/contrib/plugins/hotblocks.c
@@ -13,6 +13,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/contrib/plugins/hotpages.c b/contrib/plugins/hotpages.c
index ecd6c18732..1ae3f44aed 100644
--- a/contrib/plugins/hotpages.c
+++ b/contrib/plugins/hotpages.c
@@ -16,6 +16,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/contrib/plugins/howvec.c b/contrib/plugins/howvec.c
index 3b9a6939f2..db1b4e5780 100644
--- a/contrib/plugins/howvec.c
+++ b/contrib/plugins/howvec.c
@@ -18,6 +18,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/contrib/plugins/lockstep.c b/contrib/plugins/lockstep.c
index a696673dff..7173b2910d 100644
--- a/contrib/plugins/lockstep.c
+++ b/contrib/plugins/lockstep.c
@@ -31,6 +31,7 @@ 
 #include <stdio.h>
 #include <errno.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index bab8b0d4b3..8d08f52f7f 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -21,11 +21,7 @@ 
  *   https://gcc.gnu.org/wiki/Visibility
  */
 #if defined _WIN32 || defined __CYGWIN__
-  #ifdef BUILDING_DLL
-    #define QEMU_PLUGIN_EXPORT __declspec(dllexport)
-  #else
-    #define QEMU_PLUGIN_EXPORT __declspec(dllimport)
-  #endif
+  #define QEMU_PLUGIN_EXPORT __declspec(dllexport)
   #define QEMU_PLUGIN_LOCAL
 #else
   #if __GNUC__ >= 4
@@ -52,7 +48,9 @@  typedef uint64_t qemu_plugin_id_t;
 
 extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
 
-#define QEMU_PLUGIN_VERSION 0
+#define QEMU_PLUGIN_VERSION 1
+
+typedef void *(*qemu_plugin_global_dlsym_t)(void* context, const char *name);
 
 typedef struct {
     /* string describing architecture */
@@ -73,8 +71,23 @@  typedef struct {
             int max_vcpus;
         } system;
     };
+    void *context;
+    qemu_plugin_global_dlsym_t dlsym;
 } qemu_info_t;
 
+/**
+ * qemu_plugin_initialize() - Initialize a plugin before install
+ * @info: a block describing some details about the guest
+ *
+ * All plugins must export this symbol, and in most case using qemu-plugin.h
+ * provided implementation directly.
+ * For plugin provide this function, the QEMU_PLUGIN_VERSION should >= 1
+ *
+ * Note: This function only used to loading qemu's exported functions, nothing
+ * else should doding in this function.
+ */
+QEMU_PLUGIN_EXPORT int qemu_plugin_initialize(const qemu_info_t *info);
+
 /**
  * qemu_plugin_install() - Install a plugin
  * @id: this plugin's opaque ID
@@ -121,7 +134,7 @@  typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
  *
  * Note: Calling this function from qemu_plugin_install() is a bug.
  */
-void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
+typedef void (*qemu_plugin_uninstall_t)(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
 
 /**
  * qemu_plugin_reset() - Reset a plugin
@@ -134,7 +147,7 @@  void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
  * Plugins are reset asynchronously, and therefore the given plugin receives
  * callbacks until @cb is called.
  */
-void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
+typedef void (*qemu_plugin_reset_t)(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
 
 /**
  * qemu_plugin_register_vcpu_init_cb() - register a vCPU initialization callback
@@ -145,7 +158,7 @@  void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
  *
  * See also: qemu_plugin_register_vcpu_exit_cb()
  */
-void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_init_cb_t)(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb);
 
 /**
@@ -157,7 +170,7 @@  void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
  *
  * See also: qemu_plugin_register_vcpu_init_cb()
  */
-void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_exit_cb_t)(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb);
 
 /**
@@ -167,7 +180,7 @@  void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
  *
  * The @cb function is called every time a vCPU idles.
  */
-void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_idle_cb_t)(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb);
 
 /**
@@ -177,7 +190,7 @@  void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
  *
  * The @cb function is called every time a vCPU resumes execution.
  */
-void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_resume_cb_t)(qemu_plugin_id_t id,
                                          qemu_plugin_vcpu_simple_cb_t cb);
 
 /*
@@ -214,11 +227,11 @@  enum qemu_plugin_mem_rw {
 typedef void (*qemu_plugin_vcpu_tb_trans_cb_t)(qemu_plugin_id_t id,
                                                struct qemu_plugin_tb *tb);
 
-void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_tb_trans_cb_t)(qemu_plugin_id_t id,
                                            qemu_plugin_vcpu_tb_trans_cb_t cb);
 
 /**
- * qemu_plugin_register_vcpu_tb_trans_exec_cb() - register execution callback
+ * qemu_plugin_register_vcpu_tb_exec_cb() - register execution callback
  * @tb: the opaque qemu_plugin_tb handle for the translation
  * @cb: callback function
  * @flags: does the plugin read or write the CPU's registers?
@@ -226,7 +239,7 @@  void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
  *
  * The @cb function is called every time a translated unit executes.
  */
-void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
+typedef void (*qemu_plugin_register_vcpu_tb_exec_cb_t)(struct qemu_plugin_tb *tb,
                                           qemu_plugin_vcpu_udata_cb_t cb,
                                           enum qemu_plugin_cb_flags flags,
                                           void *userdata);
@@ -236,7 +249,7 @@  enum qemu_plugin_op {
 };
 
 /**
- * qemu_plugin_register_vcpu_tb_trans_exec_inline() - execution inline op
+ * qemu_plugin_register_vcpu_tb_exec_inline() - execution inline op
  * @tb: the opaque qemu_plugin_tb handle for the translation
  * @op: the type of qemu_plugin_op (e.g. ADD_U64)
  * @ptr: the target memory location for the op
@@ -246,7 +259,7 @@  enum qemu_plugin_op {
  * Useful if you just want to increment a single counter somewhere in
  * memory.
  */
-void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
+typedef void (*qemu_plugin_register_vcpu_tb_exec_inline_t)(struct qemu_plugin_tb *tb,
                                               enum qemu_plugin_op op,
                                               void *ptr, uint64_t imm);
 
@@ -259,7 +272,7 @@  void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
  *
  * The @cb function is called every time an instruction is executed
  */
-void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
+typedef void (*qemu_plugin_register_vcpu_insn_exec_cb_t)(struct qemu_plugin_insn *insn,
                                             qemu_plugin_vcpu_udata_cb_t cb,
                                             enum qemu_plugin_cb_flags flags,
                                             void *userdata);
@@ -275,26 +288,26 @@  void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
  * Insert an inline op to every time an instruction executes. Useful
  * if you just want to increment a single counter somewhere in memory.
  */
-void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
+typedef void (*qemu_plugin_register_vcpu_insn_exec_inline_t)(struct qemu_plugin_insn *insn,
                                                 enum qemu_plugin_op op,
                                                 void *ptr, uint64_t imm);
 
 /*
  * Helpers to query information about the instructions in a block
  */
-size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
+typedef size_t (*qemu_plugin_tb_n_insns_t)(const struct qemu_plugin_tb *tb);
 
-uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
+typedef uint64_t (*qemu_plugin_tb_vaddr_t)(const struct qemu_plugin_tb *tb);
 
-struct qemu_plugin_insn *
-qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
+typedef struct qemu_plugin_insn *
+(*qemu_plugin_tb_get_insn_t)(const struct qemu_plugin_tb *tb, size_t idx);
 
-const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
+typedef const void *(*qemu_plugin_insn_data_t)(const struct qemu_plugin_insn *insn);
 
-size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
+typedef size_t (*qemu_plugin_insn_size_t)(const struct qemu_plugin_insn *insn);
 
-uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
-void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn);
+typedef uint64_t (*qemu_plugin_insn_vaddr_t)(const struct qemu_plugin_insn *insn);
+typedef void *(*qemu_plugin_insn_haddr_t)(const struct qemu_plugin_insn *insn);
 
 /*
  * Memory Instrumentation
@@ -307,10 +320,10 @@  typedef uint32_t qemu_plugin_meminfo_t;
 struct qemu_plugin_hwaddr;
 
 /* meminfo queries */
-unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
-bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
-bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
-bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
+typedef unsigned int (*qemu_plugin_mem_size_shift_t)(qemu_plugin_meminfo_t info);
+typedef bool (*qemu_plugin_mem_is_sign_extended_t)(qemu_plugin_meminfo_t info);
+typedef bool (*qemu_plugin_mem_is_big_endian_t)(qemu_plugin_meminfo_t info);
+typedef bool (*qemu_plugin_mem_is_store_t)(qemu_plugin_meminfo_t info);
 
 /*
  * qemu_plugin_get_hwaddr():
@@ -324,7 +337,7 @@  bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
  * information about the handle should be recovered before the
  * callback returns.
  */
-struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
+typedef struct qemu_plugin_hwaddr *(*qemu_plugin_get_hwaddr_t)(qemu_plugin_meminfo_t info,
                                                   uint64_t vaddr);
 
 /*
@@ -332,21 +345,21 @@  struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
  * to return information about it. For non-IO accesses the device
  * offset will be into the appropriate block of RAM.
  */
-bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
-uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr);
+typedef bool (*qemu_plugin_hwaddr_is_io_t)(const struct qemu_plugin_hwaddr *haddr);
+typedef uint64_t (*qemu_plugin_hwaddr_device_offset_t)(const struct qemu_plugin_hwaddr *haddr);
 
 typedef void
 (*qemu_plugin_vcpu_mem_cb_t)(unsigned int vcpu_index,
                              qemu_plugin_meminfo_t info, uint64_t vaddr,
                              void *userdata);
 
-void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
+typedef void (*qemu_plugin_register_vcpu_mem_cb_t)(struct qemu_plugin_insn *insn,
                                       qemu_plugin_vcpu_mem_cb_t cb,
                                       enum qemu_plugin_cb_flags flags,
                                       enum qemu_plugin_mem_rw rw,
                                       void *userdata);
 
-void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
+typedef void (*qemu_plugin_register_vcpu_mem_inline_t)(struct qemu_plugin_insn *insn,
                                           enum qemu_plugin_mem_rw rw,
                                           enum qemu_plugin_op op, void *ptr,
                                           uint64_t imm);
@@ -359,15 +372,15 @@  typedef void
                                  uint64_t a3, uint64_t a4, uint64_t a5,
                                  uint64_t a6, uint64_t a7, uint64_t a8);
 
-void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_vcpu_syscall_cb_t)(qemu_plugin_id_t id,
                                           qemu_plugin_vcpu_syscall_cb_t cb);
 
 typedef void
 (*qemu_plugin_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_idx,
                                      int64_t num, int64_t ret);
 
-void
-qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
+typedef void
+(*qemu_plugin_register_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id,
                                          qemu_plugin_vcpu_syscall_ret_cb_t cb);
 
 
@@ -378,7 +391,7 @@  qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
  * Returns an allocated string containing the disassembly
  */
 
-char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
+typedef char *(*qemu_plugin_insn_disas_t)(const struct qemu_plugin_insn *insn);
 
 /**
  * qemu_plugin_vcpu_for_each() - iterate over the existing vCPU
@@ -389,25 +402,117 @@  char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
  *
  * See also: qemu_plugin_register_vcpu_init_cb()
  */
-void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_vcpu_for_each_t)(qemu_plugin_id_t id,
                                qemu_plugin_vcpu_simple_cb_t cb);
 
-void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_flush_cb_t)(qemu_plugin_id_t id,
                                    qemu_plugin_simple_cb_t cb);
 
-void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
+typedef void (*qemu_plugin_register_atexit_cb_t)(qemu_plugin_id_t id,
                                     qemu_plugin_udata_cb_t cb, void *userdata);
 
 /* returns -1 in user-mode */
-int qemu_plugin_n_vcpus(void);
+typedef int (*qemu_plugin_n_vcpus_t)(void);
 
 /* returns -1 in user-mode */
-int qemu_plugin_n_max_vcpus(void);
+typedef int (*qemu_plugin_n_max_vcpus_t)(void);
 
 /**
  * qemu_plugin_outs() - output string via QEMU's logging system
  * @string: a string
  */
-void qemu_plugin_outs(const char *string);
+typedef void (*qemu_plugin_outs_t)(const char *string);
+
+#if !defined(QEMU_PLUGIN_API_IMPLEMENTATION)
+#if defined(QEMU_PLUGIN_IMPLEMENTATION)
+#define QEMU_PLUGIN_EXTERN
+#else
+#define QEMU_PLUGIN_EXTERN extern
+#endif
+
+QEMU_PLUGIN_EXTERN qemu_plugin_uninstall_t qemu_plugin_uninstall;
+QEMU_PLUGIN_EXTERN qemu_plugin_reset_t qemu_plugin_reset;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_init_cb_t qemu_plugin_register_vcpu_init_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_exit_cb_t qemu_plugin_register_vcpu_exit_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_idle_cb_t qemu_plugin_register_vcpu_idle_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_resume_cb_t qemu_plugin_register_vcpu_resume_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_tb_trans_cb_t qemu_plugin_register_vcpu_tb_trans_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_tb_exec_cb_t qemu_plugin_register_vcpu_tb_exec_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_tb_exec_inline_t qemu_plugin_register_vcpu_tb_exec_inline;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_insn_exec_cb_t qemu_plugin_register_vcpu_insn_exec_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_insn_exec_inline_t qemu_plugin_register_vcpu_insn_exec_inline;
+QEMU_PLUGIN_EXTERN qemu_plugin_tb_n_insns_t qemu_plugin_tb_n_insns;
+QEMU_PLUGIN_EXTERN qemu_plugin_tb_vaddr_t qemu_plugin_tb_vaddr;
+QEMU_PLUGIN_EXTERN qemu_plugin_tb_get_insn_t qemu_plugin_tb_get_insn;
+QEMU_PLUGIN_EXTERN qemu_plugin_insn_data_t qemu_plugin_insn_data;
+QEMU_PLUGIN_EXTERN qemu_plugin_insn_size_t qemu_plugin_insn_size;
+QEMU_PLUGIN_EXTERN qemu_plugin_insn_vaddr_t qemu_plugin_insn_vaddr;
+QEMU_PLUGIN_EXTERN qemu_plugin_insn_haddr_t qemu_plugin_insn_haddr;
+QEMU_PLUGIN_EXTERN qemu_plugin_mem_size_shift_t qemu_plugin_mem_size_shift;
+QEMU_PLUGIN_EXTERN qemu_plugin_mem_is_sign_extended_t qemu_plugin_mem_is_sign_extended;
+QEMU_PLUGIN_EXTERN qemu_plugin_mem_is_big_endian_t qemu_plugin_mem_is_big_endian;
+QEMU_PLUGIN_EXTERN qemu_plugin_mem_is_store_t qemu_plugin_mem_is_store;
+QEMU_PLUGIN_EXTERN qemu_plugin_get_hwaddr_t qemu_plugin_get_hwaddr;
+QEMU_PLUGIN_EXTERN qemu_plugin_hwaddr_is_io_t qemu_plugin_hwaddr_is_io;
+QEMU_PLUGIN_EXTERN qemu_plugin_hwaddr_device_offset_t qemu_plugin_hwaddr_device_offset;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_mem_cb_t qemu_plugin_register_vcpu_mem_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_mem_inline_t qemu_plugin_register_vcpu_mem_inline;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_syscall_cb_t qemu_plugin_register_vcpu_syscall_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_vcpu_syscall_ret_cb_t qemu_plugin_register_vcpu_syscall_ret_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_insn_disas_t qemu_plugin_insn_disas;
+QEMU_PLUGIN_EXTERN qemu_plugin_vcpu_for_each_t qemu_plugin_vcpu_for_each;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_flush_cb_t qemu_plugin_register_flush_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_register_atexit_cb_t qemu_plugin_register_atexit_cb;
+QEMU_PLUGIN_EXTERN qemu_plugin_n_vcpus_t qemu_plugin_n_vcpus;
+QEMU_PLUGIN_EXTERN qemu_plugin_n_max_vcpus_t qemu_plugin_n_max_vcpus;
+QEMU_PLUGIN_EXTERN qemu_plugin_outs_t qemu_plugin_outs;
+
+#if defined(QEMU_PLUGIN_IMPLEMENTATION)
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_initialize(const qemu_info_t *info)
+{
+    qemu_plugin_uninstall = info->dlsym(info->context, "qemu_plugin_uninstall");
+    qemu_plugin_reset = info->dlsym(info->context, "qemu_plugin_reset");
+    qemu_plugin_register_vcpu_init_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_init_cb");
+    qemu_plugin_register_vcpu_exit_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_exit_cb");
+    qemu_plugin_register_vcpu_idle_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_idle_cb");
+    qemu_plugin_register_vcpu_resume_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_resume_cb");
+    qemu_plugin_register_vcpu_tb_trans_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_tb_trans_cb");
+    qemu_plugin_register_vcpu_tb_exec_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_tb_exec_cb");
+    qemu_plugin_register_vcpu_tb_exec_inline = info->dlsym(info->context, "qemu_plugin_register_vcpu_tb_exec_inline");
+    qemu_plugin_register_vcpu_insn_exec_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_insn_exec_cb");
+    qemu_plugin_register_vcpu_insn_exec_inline = info->dlsym(info->context, "qemu_plugin_register_vcpu_insn_exec_inline");
+    qemu_plugin_tb_n_insns = info->dlsym(info->context, "qemu_plugin_tb_n_insns");
+    qemu_plugin_tb_vaddr = info->dlsym(info->context, "qemu_plugin_tb_vaddr");
+    qemu_plugin_tb_get_insn = info->dlsym(info->context, "qemu_plugin_tb_get_insn");
+    qemu_plugin_insn_data = info->dlsym(info->context, "qemu_plugin_insn_data");
+    qemu_plugin_insn_size = info->dlsym(info->context, "qemu_plugin_insn_size");
+    qemu_plugin_insn_vaddr = info->dlsym(info->context, "qemu_plugin_insn_vaddr");
+    qemu_plugin_insn_haddr = info->dlsym(info->context, "qemu_plugin_insn_haddr");
+    qemu_plugin_mem_size_shift = info->dlsym(info->context, "qemu_plugin_mem_size_shift");
+    qemu_plugin_mem_is_sign_extended = info->dlsym(info->context, "qemu_plugin_mem_is_sign_extended");
+    qemu_plugin_mem_is_big_endian = info->dlsym(info->context, "qemu_plugin_mem_is_big_endian");
+    qemu_plugin_mem_is_store = info->dlsym(info->context, "qemu_plugin_mem_is_store");
+    qemu_plugin_get_hwaddr = info->dlsym(info->context, "qemu_plugin_get_hwaddr");
+    qemu_plugin_hwaddr_is_io = info->dlsym(info->context, "qemu_plugin_hwaddr_is_io");
+    qemu_plugin_hwaddr_device_offset = info->dlsym(info->context, "qemu_plugin_hwaddr_device_offset");
+    qemu_plugin_register_vcpu_mem_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_mem_cb");
+    qemu_plugin_register_vcpu_mem_inline = info->dlsym(info->context, "qemu_plugin_register_vcpu_mem_inline");
+    qemu_plugin_register_vcpu_syscall_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_syscall_cb");
+    qemu_plugin_register_vcpu_syscall_ret_cb = info->dlsym(info->context, "qemu_plugin_register_vcpu_syscall_ret_cb");
+    qemu_plugin_insn_disas = info->dlsym(info->context, "qemu_plugin_insn_disas");
+    qemu_plugin_vcpu_for_each = info->dlsym(info->context, "qemu_plugin_vcpu_for_each");
+    qemu_plugin_register_flush_cb = info->dlsym(info->context, "qemu_plugin_register_flush_cb");
+    qemu_plugin_register_atexit_cb = info->dlsym(info->context, "qemu_plugin_register_atexit_cb");
+    qemu_plugin_n_vcpus = info->dlsym(info->context, "qemu_plugin_n_vcpus");
+    qemu_plugin_n_max_vcpus = info->dlsym(info->context, "qemu_plugin_n_max_vcpus");
+    qemu_plugin_outs = info->dlsym(info->context, "qemu_plugin_outs");
+    return 0;
+}
+
+#endif
+
+#endif /* QEMU_PLUGIN_API_IMPLEMENTATION */
+
 
 #endif /* QEMU_PLUGIN_API_H */
diff --git a/meson.build b/meson.build
index 853064e983..3998d1f14a 100644
--- a/meson.build
+++ b/meson.build
@@ -243,7 +243,11 @@  endif
 rt = cc.find_library('rt', required: false)
 libdl = not_found
 if 'CONFIG_PLUGIN' in config_host
-  libdl = cc.find_library('dl', required: true)
+  if targetos == 'windows'
+    libdl = declare_dependency(compile_args: [], link_args: [])
+  else
+    libdl = cc.find_library('dl', required: true)
+  endif
 endif
 libiscsi = not_found
 if 'CONFIG_LIBISCSI' in config_host
diff --git a/plugins/api.c b/plugins/api.c
index d325084385..2acbbe5159 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -51,12 +51,12 @@ 
 
 /* Uninstall and Reset handlers */
 
-void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
+QEMU_PLUGIN_EXPORT void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
 {
     plugin_reset_uninstall(id, cb, false);
 }
 
-void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
+QEMU_PLUGIN_EXPORT void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
 {
     plugin_reset_uninstall(id, cb, true);
 }
@@ -68,19 +68,19 @@  void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
  * during the translation.
  */
 
-void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
 }
 
-void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
 }
 
-void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
                                           qemu_plugin_vcpu_udata_cb_t cb,
                                           enum qemu_plugin_cb_flags flags,
                                           void *udata)
@@ -89,14 +89,14 @@  void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
                                   cb, flags, udata);
 }
 
-void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
                                               enum qemu_plugin_op op,
                                               void *ptr, uint64_t imm)
 {
     plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
 }
 
-void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
                                             qemu_plugin_vcpu_udata_cb_t cb,
                                             enum qemu_plugin_cb_flags flags,
                                             void *udata)
@@ -105,7 +105,7 @@  void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
         cb, flags, udata);
 }
 
-void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
                                                 enum qemu_plugin_op op,
                                                 void *ptr, uint64_t imm)
 {
@@ -115,7 +115,7 @@  void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
 
 
 
-void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
                                       qemu_plugin_vcpu_mem_cb_t cb,
                                       enum qemu_plugin_cb_flags flags,
                                       enum qemu_plugin_mem_rw rw,
@@ -125,7 +125,7 @@  void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
                                 cb, flags, rw, udata);
 }
 
-void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
                                           enum qemu_plugin_mem_rw rw,
                                           enum qemu_plugin_op op, void *ptr,
                                           uint64_t imm)
@@ -134,19 +134,19 @@  void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
         rw, op, ptr, imm);
 }
 
-void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
                                            qemu_plugin_vcpu_tb_trans_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
 }
 
-void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
                                           qemu_plugin_vcpu_syscall_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
 }
 
-void
+QEMU_PLUGIN_EXPORT void
 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
                                          qemu_plugin_vcpu_syscall_ret_cb_t cb)
 {
@@ -169,17 +169,17 @@  qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
  * each translated instruction.
  */
 
-size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
+QEMU_PLUGIN_EXPORT size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
 {
     return tb->n;
 }
 
-uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
+QEMU_PLUGIN_EXPORT uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
 {
     return tb->vaddr;
 }
 
-struct qemu_plugin_insn *
+QEMU_PLUGIN_EXPORT struct qemu_plugin_insn *
 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
 {
     if (unlikely(idx >= tb->n)) {
@@ -195,27 +195,27 @@  qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
  * instruction being translated.
  */
 
-const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
+QEMU_PLUGIN_EXPORT const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
 {
     return insn->data->data;
 }
 
-size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
+QEMU_PLUGIN_EXPORT size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
 {
     return insn->data->len;
 }
 
-uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
+QEMU_PLUGIN_EXPORT uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
 {
     return insn->vaddr;
 }
 
-void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
+QEMU_PLUGIN_EXPORT void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
 {
     return insn->haddr;
 }
 
-char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
+QEMU_PLUGIN_EXPORT char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
 {
     CPUState *cpu = current_cpu;
     return plugin_disas(cpu, insn->vaddr, insn->data->len);
@@ -226,22 +226,22 @@  char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
  * memory access.
  */
 
-unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
+QEMU_PLUGIN_EXPORT unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
 {
     return info & TRACE_MEM_SZ_SHIFT_MASK;
 }
 
-bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
+QEMU_PLUGIN_EXPORT bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
 {
     return !!(info & TRACE_MEM_SE);
 }
 
-bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
+QEMU_PLUGIN_EXPORT bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
 {
     return !!(info & TRACE_MEM_BE);
 }
 
-bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
+QEMU_PLUGIN_EXPORT bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
 {
     return !!(info & TRACE_MEM_ST);
 }
@@ -254,7 +254,7 @@  bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
 static __thread struct qemu_plugin_hwaddr hwaddr_info;
 #endif
 
-struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
+QEMU_PLUGIN_EXPORT struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
                                                   uint64_t vaddr)
 {
 #ifdef CONFIG_SOFTMMU
@@ -274,7 +274,7 @@  struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
 #endif
 }
 
-bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
+QEMU_PLUGIN_EXPORT bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
 {
 #ifdef CONFIG_SOFTMMU
     return haddr->is_io;
@@ -283,7 +283,7 @@  bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
 #endif
 }
 
-uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr)
+QEMU_PLUGIN_EXPORT uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr)
 {
 #ifdef CONFIG_SOFTMMU
     if (haddr) {
@@ -314,7 +314,7 @@  static MachineState * get_ms(void)
 }
 #endif
 
-int qemu_plugin_n_vcpus(void)
+QEMU_PLUGIN_EXPORT int qemu_plugin_n_vcpus(void)
 {
 #ifdef CONFIG_USER_ONLY
     return -1;
@@ -323,7 +323,7 @@  int qemu_plugin_n_vcpus(void)
 #endif
 }
 
-int qemu_plugin_n_max_vcpus(void)
+QEMU_PLUGIN_EXPORT int qemu_plugin_n_max_vcpus(void)
 {
 #ifdef CONFIG_USER_ONLY
     return -1;
@@ -335,7 +335,7 @@  int qemu_plugin_n_max_vcpus(void)
 /*
  * Plugin output
  */
-void qemu_plugin_outs(const char *string)
+QEMU_PLUGIN_EXPORT void qemu_plugin_outs(const char *string)
 {
     qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
 }
diff --git a/plugins/core.c b/plugins/core.c
index 7a79ea4179..a59a0bd25b 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -234,7 +234,7 @@  static void plugin_vcpu_for_each(gpointer k, gpointer v, gpointer udata)
     args->cb(args->ctx->id, cpu_index);
 }
 
-void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
                                qemu_plugin_vcpu_simple_cb_t cb)
 {
     struct plugin_for_each_args args;
@@ -385,19 +385,19 @@  void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
 }
 
-void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
                                        qemu_plugin_vcpu_simple_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_IDLE, cb);
 }
 
-void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
                                          qemu_plugin_vcpu_simple_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
 }
 
-void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
                                    qemu_plugin_simple_cb_t cb)
 {
     plugin_register_cb(id, QEMU_PLUGIN_EV_FLUSH, cb);
@@ -464,7 +464,7 @@  void qemu_plugin_atexit_cb(void)
     plugin_cb__udata(QEMU_PLUGIN_EV_ATEXIT);
 }
 
-void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
+QEMU_PLUGIN_EXPORT void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
                                     qemu_plugin_udata_cb_t cb,
                                     void *udata)
 {
diff --git a/plugins/loader.c b/plugins/loader.c
index 8ac5dbc20f..53fb1671ee 100644
--- a/plugins/loader.c
+++ b/plugins/loader.c
@@ -63,6 +63,7 @@  QemuOptsList qemu_plugin_opts = {
     },
 };
 
+typedef int (*qemu_plugin_initialize_func_t)(const qemu_info_t *);
 typedef int (*qemu_plugin_install_func_t)(qemu_plugin_id_t, const qemu_info_t *, int, char **);
 
 extern struct qemu_plugin_state plugin;
@@ -152,10 +153,12 @@  static uint64_t xorshift64star(uint64_t x)
 
 static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)
 {
+    qemu_plugin_initialize_func_t initialize = NULL;
     qemu_plugin_install_func_t install;
     struct qemu_plugin_ctx *ctx;
     gpointer sym;
     int rc;
+    int version = -1;
 
     ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));
     memset(ctx, 0, sizeof(*ctx));
@@ -184,7 +187,7 @@  static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)
                      desc->path, g_module_error());
         goto err_symbol;
     } else {
-        int version = *(int *)sym;
+        version = *(int *)sym;
         if (version < QEMU_PLUGIN_MIN_VERSION) {
             error_report("TCG plugin %s requires API version %d, but "
                          "this QEMU supports only a minimum version of %d",
@@ -198,6 +201,21 @@  static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)
         }
     }
 
+    if (version >= QEMU_PLUGIN_VERSION_1) {
+        /* This version should call to qemu_plugin_initialize first */
+        if (!g_module_symbol(ctx->handle, "qemu_plugin_initialize", &sym)) {
+            error_report("%s: %s", __func__, g_module_error());
+            goto err_symbol;
+        }
+        initialize = (qemu_plugin_initialize_func_t) sym;
+        /* symbol was found; it could be NULL though */
+        if (initialize == NULL) {
+            error_report("%s: %s: qemu_plugin_initialize is NULL",
+                        __func__, desc->path);
+            goto err_symbol;
+        }
+    }
+
     qemu_rec_mutex_lock(&plugin.lock);
 
     /* find an unused random id with &ctx as the seed */
@@ -216,6 +234,16 @@  static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)
         }
     }
     QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);
+    if (initialize != NULL) {
+        rc = initialize(info);
+        if (rc) {
+            error_report("%s: qemu_plugin_initialize returned error code %d",
+                        __func__, rc);
+            /* qemu_plugin_initialize only loading function symbols */
+            goto err_symbol;
+        }
+    }
+
     ctx->installing = true;
     rc = install(ctx->id, info, desc->argc, desc->argv);
     ctx->installing = false;
@@ -254,6 +282,17 @@  static void plugin_desc_free(struct qemu_plugin_desc *desc)
     g_free(desc);
 }
 
+static void *qemu_plugin_global_dlsym(void* context, const char *name)
+{
+    GModule *global_handle = context;
+    gpointer sym = NULL;
+    if (!g_module_symbol(global_handle, name, &sym)) {
+        error_report("%s: %s", __func__, g_module_error());
+        return NULL;
+    }
+    return sym;
+}
+
 /**
  * qemu_plugin_load_list - load a list of plugins
  * @head: head of the list of descriptors of the plugins to be loaded
@@ -267,6 +306,7 @@  int qemu_plugin_load_list(QemuPluginList *head)
 {
     struct qemu_plugin_desc *desc, *next;
     g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);
+    GModule *global_handle = NULL;
 
     info->target_name = TARGET_NAME;
     info->version.min = QEMU_PLUGIN_MIN_VERSION;
@@ -276,6 +316,12 @@  int qemu_plugin_load_list(QemuPluginList *head)
     info->system_emulation = true;
     info->system.smp_vcpus = ms->smp.cpus;
     info->system.max_vcpus = ms->smp.max_cpus;
+    global_handle = g_module_open(NULL, G_MODULE_BIND_LOCAL);
+    if (global_handle == NULL) {
+        goto err_dlopen;
+    }
+    info->dlsym = qemu_plugin_global_dlsym;
+    info->context = (void*)global_handle;
 #else
     info->system_emulation = false;
 #endif
@@ -289,6 +335,8 @@  int qemu_plugin_load_list(QemuPluginList *head)
         }
         QTAILQ_REMOVE(head, desc, entry);
     }
+
+err_dlopen:
     return 0;
 }
 
diff --git a/plugins/meson.build b/plugins/meson.build
index e77723010e..16af5d7ca3 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -1,13 +1,5 @@ 
-if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host
-  plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')]
-elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host
-  plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')]
-else
-  plugin_ldflags = []
-endif
-
 specific_ss.add(when: 'CONFIG_PLUGIN', if_true: [files(
   'loader.c',
   'core.c',
   'api.c',
-), declare_dependency(link_args: plugin_ldflags)])
+), declare_dependency(link_args: [], compile_args: ['-Wno-missing-prototypes'])])
diff --git a/plugins/plugin.h b/plugins/plugin.h
index 1aa29dcadd..406f246a72 100644
--- a/plugins/plugin.h
+++ b/plugins/plugin.h
@@ -15,6 +15,7 @@ 
 #include <gmodule.h>
 
 #define QEMU_PLUGIN_MIN_VERSION 0
+#define QEMU_PLUGIN_VERSION_1 1
 
 /* global state */
 struct qemu_plugin_state {
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
deleted file mode 100644
index 4bdb381f48..0000000000
--- a/plugins/qemu-plugins.symbols
+++ /dev/null
@@ -1,40 +0,0 @@ 
-{
-  qemu_plugin_uninstall;
-  qemu_plugin_reset;
-  qemu_plugin_register_vcpu_init_cb;
-  qemu_plugin_register_vcpu_exit_cb;
-  qemu_plugin_register_vcpu_idle_cb;
-  qemu_plugin_register_vcpu_resume_cb;
-  qemu_plugin_register_vcpu_insn_exec_cb;
-  qemu_plugin_register_vcpu_insn_exec_inline;
-  qemu_plugin_register_vcpu_mem_cb;
-  qemu_plugin_register_vcpu_mem_haddr_cb;
-  qemu_plugin_register_vcpu_mem_inline;
-  qemu_plugin_ram_addr_from_host;
-  qemu_plugin_register_vcpu_tb_trans_cb;
-  qemu_plugin_register_vcpu_tb_exec_cb;
-  qemu_plugin_register_vcpu_tb_exec_inline;
-  qemu_plugin_register_flush_cb;
-  qemu_plugin_register_vcpu_syscall_cb;
-  qemu_plugin_register_vcpu_syscall_ret_cb;
-  qemu_plugin_register_atexit_cb;
-  qemu_plugin_tb_n_insns;
-  qemu_plugin_tb_get_insn;
-  qemu_plugin_tb_vaddr;
-  qemu_plugin_insn_data;
-  qemu_plugin_insn_size;
-  qemu_plugin_insn_vaddr;
-  qemu_plugin_insn_haddr;
-  qemu_plugin_insn_disas;
-  qemu_plugin_mem_size_shift;
-  qemu_plugin_mem_is_sign_extended;
-  qemu_plugin_mem_is_big_endian;
-  qemu_plugin_mem_is_store;
-  qemu_plugin_get_hwaddr;
-  qemu_plugin_hwaddr_is_io;
-  qemu_plugin_hwaddr_to_raddr;
-  qemu_plugin_vcpu_for_each;
-  qemu_plugin_n_vcpus;
-  qemu_plugin_n_max_vcpus;
-  qemu_plugin_outs;
-};
diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c
index de09bdde4e..cda3fbdde9 100644
--- a/tests/plugin/bb.c
+++ b/tests/plugin/bb.c
@@ -12,6 +12,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/tests/plugin/empty.c b/tests/plugin/empty.c
index 8fa6bacd93..0c3adf7aa0 100644
--- a/tests/plugin/empty.c
+++ b/tests/plugin/empty.c
@@ -11,6 +11,7 @@ 
 #include <unistd.h>
 #include <stdio.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c
index a9a6e41237..bf86fdafe6 100644
--- a/tests/plugin/insn.c
+++ b/tests/plugin/insn.c
@@ -12,6 +12,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
index 4725bd851d..f39be9c969 100644
--- a/tests/plugin/mem.c
+++ b/tests/plugin/mem.c
@@ -12,6 +12,7 @@ 
 #include <stdio.h>
 #include <glib.h>
 
+#define QEMU_PLUGIN_IMPLEMENTATION
 #include <qemu-plugin.h>
 
 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;