Zaibis Zaibis - 3 months ago 10
C Question

How to assign dlsym()'s return value to function type?

My problem is as follows:

I have a structure containing function pointers like this:

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

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


Now I want to assign a functionpointer of exactly that type to it.
But sadly
dlsym()
is returning a
void *
instead of something like
function_poitner_type


So my first try:

functionscope ()
{
myFuncpointerStruc_t structIdentifier;

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


ended in the warning:


WARNING: ISO C forbids assignment between function pointer and 'void *'


Ok, that confused me... gcc was never talking that harsh to me.
But OK lets get tricky I thought there will probably be any backdoor to keep it standard conform. So I tried this:

functionscope ()
{
myFuncpointerStruc_t structIdentifier;

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


Hm.... obviously...


warning: dereferencing type-punned pointer will break strict aliasing rules


As I don't know what happens
dlsym()
internally I can't know I will break, as I get returned a real
void *
that aliases my function, or something quite different, can I?

So I cant know, will the use of this function pointer now break strict-aliasing rules or won't it?

But anyway: For my company it is law to use the compilerflag
-fstrict-aliasing
.
So this is also not a possible solution for me, even if it would be conform.

So I tried it by going on.

My next idea was: what about to parse a
char *
version of
dlsym()
into memcopy?

The result:

functionscope ()
{
myFuncpointerStruc_t structIdentifier;

unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");

memcpy (g_interfaceSvCheck.pfnPFD_SVCHK_GET_VERSION, localTestPtr, sizeof (localTestPtr));
}


The warning I'm getting now is pretty specific again:


warning: ISO C forbids passing argument 1 of ´memcpy´ between function pointer and ´void *´


So my next idea was kind of "lets go back to the bytes" maybe there I will get a way it will be working on.
(But slowly I'm running out of ideas...)

So I did:

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];
}

}


This ended in a quiet different warning:


WARNING: ISO C forbids conversion of function pointer to object pointer type


So finally my freakiest try was:

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];
}
}


And even here the problem is, that
offsetoff
's second parameter can't get converted to
void *
as it is a function pointer.

I'm stucked and don't know how to get further, could anyone help me please finding a solution?

I just have these warnings by using gcc 4.2 not with clang.

The targeted C version is
-std=c99
to avoid is
-std=POSIX
and
-std=gnu99


But this gcc warnings don't sound outdated to me.
I'm working currently on FreeBSD and I have really no idea left how to solve this.

alk alk
Answer

This is kind of tricky:

#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");
  }

  ...
}

The above solution just tricks to compiler. The does not work from -O1 on anymore ... :-(


As there indeed is no solution, the only solution is to calm down the compiler. And the GNU people showed insight on this and invented: __attribute__ ((__may_alias__))

Here we can use it as follows:

#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");
  }

  ...
}

And btw: Where does ldsym() come from? I only know dlsym().