从共享对象Windows / MinGW中访问应用程序内的符号

时间:2013-04-15 18:39:26

标签: shared-libraries symbols dlopen

这是我的第一篇文章,我正在努力遵守论坛规则。 我知道这个问题之前已被问过多次,但提供的解决方案对我不起作用。我不太清楚为什么会这样,可能我忽视了一些事情。

我想从位于主应用程序内的共享模块(.so)符号(变量和函数)进行访问。 我总是得到链接错误(“未定义的引用”)。

该场景与此处描述的类似,其中一个假设是我使用普通C而不是C ++:

shared object can't find symbols in main binary, C++

也许这种差异是建议的解决方案不起作用的原因。 我使用32位MinGW,版本4.6.2在32位Windows下(XP,如果重要的话)。

我也阅读了这些帖子:

Receive "undefined symbol" error when loading library with dlopen

Dynamic loading and symbols sharing

Can I access to symbols of the host proccess from a shared object loaded in runtime? Any alternative?

我认为后一种解决方案可行,但不是一种选择,因为这是一个带有100多个符号的Linux移植项目。这是一个插件系统,我不想限制插件可用的可能性。

我在链接主应用程序时尝试了许多命令行开关,例如-rdynamic(MinGW中显然不支持), - export-all-symbols, - export-dynamic。 在链接共享库时我也尝试了不同的命令行选项,例如--allow-shlib-undefined, - enable-auto-import, - enable-runtime-pseudo-reloc

该应用程序是一个Linux应用程序,在那里运行良好;我设法让它在Mac OSX(达尔文)下运行。在链接期间,我不得剥离主应用程序可执行文件,并在链接共享对象时指定“-bundle -bundle_loader'app name'”。

非常感谢提前!

约翰

1 个答案:

答案 0 :(得分:0)

好吧,我在codeguru论坛的帮助下发现了自己(见http://forums.codeguru.com/showthread.php?536343-RESOLVED-accessing-symbols-in-appllication-from-within-dynamic-library-MinGW)。

解决方案不是 - 正如我先想到的那样 - 链接器的一些选项;显然,在Windows中无法进行自动反向链接。您必须在运行时从主应用程序中手动加载要使用的符号;类似于手动加载DLL时。

我做了一个小测试和示范项目:

文件“my_app.c”:

#include <stdio.h>
#include <stdlib.h>

#include "my_app.h"
#include "plugins.h"

int a;
int b;
Plugin *P;

void hello ()
{
  printf ("Hello World!\n");
}

int main ()
{
  char choice;
  char buf[BUFLEN];
  char *plugin_name=NULL;
  Plugin *p=NULL;

  do
  {
    printf ("\n   ---  Menu items ---\n");
    printf ("   '1' .. select plugin\n");
    printf ("   '2' .. load plugin\n");
    printf ("   '3' .. execute plugin function\n");
    printf ("   '4' .. unload plugin\n");
    printf ("   'x' .. exit\n");
    printf ("\n   Your choice: ");

    fgets (buf, sizeof(buf), stdin);
    putchar ('\n');
    choice = buf[0];
    switch (choice)
    {
      case '1':
        plugin_name = plugin_select ();
        break; 
      case '2':
        if (plugin_name)
        {
          p = plugin_load (plugin_name);
          if (p)
            printf ("Plugin '%s' loaded successfully\n", plugin_name);
          P = p;
        } else
          printf ("No plugin selected\n");      
        break; 
      case '3':
        if (p)
        {
          printf ("Enter the 1st number: ");
          fgets (buf, sizeof(buf), stdin);
          a = atoi (buf);
          printf ("Enter the 2nd number: ");
          fgets (buf, sizeof(buf), stdin);
          b = atoi (buf);
          printf ("\nExecuting the plugin '%s' ...\n", plugin_name);
          plugin_action (p);
        } else
          printf ("No plugin loaded\n");
        break; 
      case '4':
        if (p)
        {
          plugin_destroy (p);
          p = NULL;
          P = NULL;
        } else
          printf ("No plugin loaded\n");
        break; 
    }
  } while (choice != 'x');

  return 0;
}

文件“my_app.h”:

#ifndef __MYAPP_H
#define __MYAPP_H

#include "plugins.h"

#define TRUE  1
#define FALSE 0

#define BUFLEN 120

extern int a;
extern int b;

extern void hello (void);

extern Plugin *P;

#endif  /* __MYAPP_H */

file“plugins.c”:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <dlfcn.h>

#include "my_app.h"
#include "plugins.h"

Plugin *plugin_load (const char *filename)
{
  Plugin *p;
  int (*init)(Plugin *);

  p = malloc (sizeof(Plugin));
  if (p == NULL)
  {
    printf ("Couldn't allocate Plugin object\n");
    return NULL;
  }
  strncpy (p->filename, filename, sizeof(p->filename));
  if ((p->module = dlopen(p->filename, RTLD_LAZY)) == NULL)
  {
    printf ("%s\n", dlerror());
    free (p);
    return NULL;
  }

  init = dlsym (p->module, "init_plugin");
  if (init == NULL)
  {
    printf ("%s\n", dlerror());
    free (p);
    return NULL;
  }

  if (!init(p))
  {
    perror ("Couldn't initialize plugin");
    free (p);
    return NULL;
  }

  p->load = TRUE;
  return p;
}

void plugin_action (Plugin *p)
{
  if (p == NULL)
  {
    printf ("Plugin not found!\n");
    return;
  }
  p->plugin_cb();
}

char *plugin_select ()
{
  DIR *dp;
  struct dirent *e;
  static char buf[BUFLEN];
  char *p;
  size_t len;
  char *suffix;

  dp = opendir (".");
  if (dp == NULL)
  {
    perror ("Cannot open '.'");
    return NULL;
  }
  printf ("\nFollowing plugins are available:\n");
  while ((e=readdir(dp)) != NULL)
  {
    suffix = strrchr (e->d_name, '.');
    if (suffix)
    {
      if (strcmp (suffix, PLUGIN_SUFFIX) == 0)
        printf ("  %s\n", e->d_name);
    }
  }
  closedir (dp);
  printf ("Your choice: ");
  buf[0] = '.';
  buf[1] = '/';
  p = &buf[2];
  fgets (p, sizeof(buf)-2, stdin);
  len = strlen (buf);
  if (len > 0)
    len --;
  buf[len] = '\0';
  if (strchr(p, '.') == NULL)
    strcat (buf, PLUGIN_SUFFIX);

  return buf;
}

void plugin_destroy (Plugin *p)
{
  void (*unload)(Plugin *);

  unload = dlsym (p->module, "unload_plugin");
  if (unload != NULL)
    unload (p);

  dlclose (p->module);
  free (p);
}

文件“plugins.h”:

#ifndef __PLUGINS_H
#define __PLUGINS_H

#include <limits.h>          /*PATH_MAX */

#define PLUGIN_SUFFIX  ".so"

typedef struct _Plugin
{
  char filename[PATH_MAX];
  char *name;
  char *description;
  unsigned int show_in_menu;
  unsigned int load;
  void *module;
  void (*plugin_cb)();
} Plugin;

Plugin *plugin_load (const char *filename);
void plugin_action (Plugin *p);
char *plugin_select (void);
void plugin_destroy (Plugin *p);

#endif  /* __PLUGINS_H */

现在插件:

隐藏令人讨厌的函数指针声明等:“plugin_macros.h”:

#ifndef __PLUGIN_MACROS_H
#define __PLUGIN_MACROS_H

#ifdef WIN32
#include <windows.h>

#define DECLARE_FUNC(type,name,par) typedef type (WINAPI *name ## _t)par; static name ## _t name;
#define DECLARE_VAR(type,name) static type * p ## name;
#define DECLARE_PTR(type,name) static type *name;

#define LOAD_FUNCC(name) if((name=(name ## _t)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0
#define LOAD_FUNC(name) (name=(name ## _t)GetProcAddress(GetModuleHandle(NULL),#name))

#define LOAD_VARC(type,name) if((p ## name=(type *)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0
#define LOAD_VAR(type,name) (name=(type *)GetProcAddress(GetModuleHandle(NULL),#name))

#define LOAD_PTRC(type,name) if((name=*(type **)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0
#define LOAD_PTR(type,name) (name=*(type **)GetProcAddress(GetModuleHandle(NULL),#name))

#else
/* not WIN32 */
#define DECLARE_FUNC(type,name,par)
#define DECLARE_VAR(type,name)
#define DECLARE_PTR(type,name)

#define LOAD_FUNCC(name)
#define LOAD_FUNC(name)

#define LOAD_VARC(type,name)
#define LOAD_VAR(type,name)

#define LOAD_PTRC(type,name)
#define LOAD_PTR(type,name)
#endif

#endif  /* __PLUGIN_MACROS_H */

文件“add.c”:

#include <stdio.h>

#include "plugins.h"
#include "plugin_macros.h"

#ifdef WIN32
#include <windows.h>

DECLARE_FUNC(void, hello, (void));
DECLARE_VAR(int, a);
DECLARE_VAR(int, b);
DECLARE_PTR(Plugin, P);

#define a (*pa)
#define b (*pb)

#else
#include "my_app.h"
#endif


static void add ()
{
  hello();
  LOAD_PTR(Plugin, P);
  printf ("name=%s\n", P->name);
  printf ("description=%s\n\n", P->description);
  printf ("%d + %d = %d\n", a, b, a+b);
}

int init_plugin (Plugin *p)
{
  LOAD_FUNCC(hello);
  LOAD_VARC(int, a);
  LOAD_VARC(int, b);

  p->name = "Add";
  p->description = "Add two integers.";
  p->plugin_cb = add;
  P = p;

  return TRUE;
}

file“multiply.c”:

#include <stdio.h>

#include "plugins.h"
#include "plugin_macros.h"

#ifdef WIN32
#include <windows.h>

DECLARE_VAR(int, a);
DECLARE_VAR(int, b);
DECLARE_PTR(Plugin, P);

#define a (*pa)
#define b (*pb)

#else
#include "my_app.h"
#endif

static void multiply ()
{
  LOAD_PTR(Plugin, P);
  printf ("name=%s\n", P->name);
  printf ("description=%s\n\n", P->description);
  printf ("%d * %d = %d\n", a, b, a*b);
}

int init_plugin (Plugin *p)
{
  LOAD_VARC(int, a);
  LOAD_VARC(int, b);

  p->name = "Multiply";
  p->description = "Multiply two integers.";
  p->plugin_cb = multiply;
  P = p;

  return TRUE;
}

...和Makefile:

ifeq ($(OS), Windows_NT)
  TARGET = plugintest.exe
  CC = $(MINGW)\bin\gcc.exe
  LDFLAGS = -Wl,--export-all-symbols
  STRIP = -s
  SHARED = -shared
  RM = del
else
  TARGET = plugintest
  UNAME := $(shell uname -s)
  ifeq ($(UNAME),Linux)
    LDFLAGS = -Wl,--export-dynamic
    STRIP = -s
    SHARED = -shared
  endif
  ifeq ($(UNAME),Darwin)
    LDFLAGS =
    STRIP =
    SHARED = -bundle -bundle_loader plugintest
  endif
  RM = rm -f
endif

PLUGINS = add.so multiply.so
OBJS = my_app.o plugins.o
LIBS = -ldl
CFLAGS = -Wall

all: $(TARGET) my_plugins

$(TARGET): $(OBJS)
    $(CC) $(OBJS) $(LIBS) $(LDFLAGS) -o $(TARGET)

my_app.o: my_app.c my_app.h plugins.h
    $(CC) $(CFLAGS) -c my_app.c -o my_app.o

plugins.o: plugins.c my_app.h plugins.h
    $(CC) $(CFLAGS) -c plugins.c -o plugins.o

my_plugins: $(PLUGINS)

add.so: add.c my_app.h plugin_macros.h
    $(CC) $(CFLAGS) $(SHARED) add.c -o add.so

multiply.so: multiply.c my_app.h plugin_macros.h
    $(CC) $(CFLAGS) $(SHARED) multiply.c -o multiply.so

clean:
    $(RM) *.o *.so $(TARGET)

该项目使用posix动态加载函数dlopen()等。它们不是MinGW安装的一部分,但您可以从这里下载:

http://code.google.com/p/dlfcn-win32/

我希望这可以帮助遇到同样问题的其他人。 欢迎提出任何意见和问题!

约翰