如何将dlsym()的返回值赋给函数类型?

时间:2013-10-01 12:43:30

标签: c gcc function-pointers freebsd strict-aliasing

我的问题如下:

我有一个包含这样的函数指针的结构:

typedef void (CALLING_COVNENTION * functionType_t) (/*...*/);

typedef struct myFuncpointerStruc_s
{
    /*...*/
    functionType_t funcIdentifier;
    /*...*/
}myFuncpointerStruc_t;

现在我想为它分配一个完全相同类型的函数指针。 但遗憾的是,dlsym()正在返回void *而不是function_poitner_type

所以我的第一次尝试:

functionscope ()
{
    myFuncpointerStruc_t structIdentifier;

    structIdentifier.funcIdentifier= dlsym (hAndle, "calledName");
}

在警告中结束:

  

警告:ISO C禁止在函数指针和'void *'

之间进行分配

好吧,这让我感到困惑...... gcc从未对我说过那么严厉。 但好吧让我变得棘手我认为可能会有任何后门保持标准符合。所以我尝试了这个:

functionscope ()
{
    myFuncpointerStruc_t structIdentifier;

    *(void **) &structIdentifier.funcIdentifier = dlsym (hAndle, "calledName");
}
嗯....显然......

  

警告:解除引用类型惩罚指针将破坏严格的别名规则

因为我不知道内部会发生什么dlsym()我不知道我会破坏,因为我返回了一个真正的void *,它使我的功能别名,或者是一些完全不同的东西,我可以吗?

所以我不知道,现在使用这个函数指针会破坏严格别名规则还是不会呢?

但无论如何:对于我的公司来说,使用compilerflag -fstrict-aliasing是合法的。 所以这对我来说也不是一个可能的解决方案,即使它符合要求。

所以我试着继续。

我的下一个想法是:如何将char * dlsym()版本的functionscope () { myFuncpointerStruc_t structIdentifier; unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName"); memcpy (g_interfaceSvCheck.pfnPFD_SVCHK_GET_VERSION, localTestPtr, sizeof (localTestPtr)); } 解析为memcopy?

结果:

functionscope ()
{
    size_t testIndex;
    myFuncpointerStruc_t structIdentifier;
    unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");

    for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
    {
        ((unsigned char *)(structIdentifier.funcIdentifier))[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
    }

}

我现在收到的警告非常具体:

  

警告:ISO C禁止在函数指针和'void *'之间传递'memcpy'的参数1

所以我的下一个想法是“让我们回到字节”,也许在那里,我会找到一种方法。 (但慢慢地,我的想法已经不多了......)

所以我做了:

functionscope ()
{
    size_t testIndex;
    myFuncpointerStruc_t structIdentifier;
    unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");  
    unsigned char * FakeFunctionPointer;

    FakeFunctionPointer = 
        (((unsigned char *)structIdentifier) + offsetof (myFuncpointerStruc_t , funcIdentifier));

    for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
    {
        FakeFunctionPointer[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
    }
}

这是一个安静的不同警告:

  

警告:ISO C禁止将函数指针转换为对象指针类型

所以最后我最蠢的尝试是:

offsetoff

即使在这里问题是,void *的第二个参数也无法转换为-std=c99,因为它是一个函数指针。

我被困了,不知道怎么走得更远,有人可以帮我找一个解决方案吗?

我只是使用gcc 4.2而不是clang来发出这些警告。

目标C版本为-std=POSIX,以避免-std=gnu99和{{1}}

但这个gcc警告听起来并不过时。 我目前在FreeBSD上工作,我真的不知道如何解决这个问题。

2 个答案:

答案 0 :(得分:2)

这有点棘手:

#define CALLING_CONVENTION 

typedef void (CALLING_CONVENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
  /*...*/
  functionType_t funcIdentifier;
  /*...*/
} myFuncpointerStruc_t;

int main()
{
  myFuncpointerStruc_t structIdentifier = {0};

  {
    functionType_t * pfuncIdentifier = &structIdentifier.funcIdentifier;

    *(void **) (pfuncIdentifier) = dlsym(handle, "calledName");
  }

  ...
}

上述解决方案只是欺骗编译器。从<{1}}开始,工作了......: - (


由于确实没有解决方案,唯一的解决方案是冷静编译器。 GNU人员对此表现出了深刻见解并发明了:-O1

我们可以在这里使用它:

__attribute__ ((__may_alias__))

顺便说一下:#define CALLING_CONVENTION typedef void * __attribute__ ((__may_alias__)) pvoid_may_alias_t; typedef void (CALLING_CONVENTION * functionType_t) (/*...*/); typedef struct myFuncpointerStruc_s { /*...*/ functionType_t funcIdentifier; /*...*/ } myFuncpointerStruc_t; int main() { myFuncpointerStruc_t structIdentifier = {0}; *(pvoid_may_alias_t *) (&structIdentifier.funcIdentifier) = dlsym(handle, "calledName"); } ... } 来自哪里?我只知道ldsym()

答案 1 :(得分:0)

使用两种类型转换:

func_type *funptr;
funptr= (func_type *)(intptr_t)dlsym();
如果代码指针和数据指针的大小不相等,

类型转换funptr会引起麻烦。