Reputation: 6555
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.
Upvotes: 2
Views: 2642
Reputation: 377
Use two type-casts:
func_type *funptr;
funptr= (func_type *)(intptr_t)dlsym();
Type-casting funptr will cause troubles if size of code-pointers and data-pointers aren't equal.
Upvotes: 1
Reputation: 70981
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()
.
Upvotes: 2