Dave
Dave

Reputation: 2994

Iterate through macro defined functions

Came across this code in an existing project that consist of injecting a DLL in a process and operating from there.

They declare some function pointers offsets and then they iterate trough them to add the specific dll offset to it.

I have trouble iterating trough the macro defined functions. It seems to work fine if I have only 5-6 functions but it doesn't work when I add more.

#pragma optimize ( "", off )

#define DLLOFFSET(a1,b1) ((DLLNO_##a1)|((b1)<<8))
#define FUNCPTR(d1,v1,t1,t2,o1) typedef t1 d1##_##v1##_t t2; d1##_##v1##_t *d1##_##v1 = (d1##_##v1##_t *)DLLOFFSET(d1,o1);
#define ASMPTR(d1,v1,o1)  DWORD d1##_##v1 = DLLOFFSET(d1,o1);


#define _PTRS_START PREFIX1_aaa
...
FUNCPTR(PREFIX1, aaa, ....., 0xFFFFF)
...
FUNCPTR(PREFIX3, fff, ....., 0xFFFFF)
...
FUNCPTR(PREFIX2, ggg,  ....., 0xFFFFF)
...
ASMPTR(PREFIX1, jjj, 0xFFFFF)
...
#define _PTRS_END   PREFIX1_jjj


void DefineOffsets()
{
    DWORD *p = (DWORD *)&_PTRS_START;
    do {
        *p = "call update pointer function here"    
    } while(++p <= (DWORD *)&_PTRS_END);
}

#pragma optimize( "", on ) 

If there are only a few functions defined, the loop works just fine. However, when there are many, it seems that the compiler doesn't place the code all in one chunk. Thus why we can't loop on them by incrementing a pointer.

I found another way by copying the functions and declaring a new array but I'd prefer to not have to maintain the same code in two files.

A programmer of the projet said that he had the same problem and he fixed it by removing project optimisation from : project-> properties->c++->optimisation->disabled.

Which I tried. Also tried project-> properties->c++->Code gen->Enable minimal build-> No.

I'm using vs 2012.

Upvotes: 0

Views: 204

Answers (1)

Alex Celeste
Alex Celeste

Reputation: 13390

This does sound like it would be much easier if you could simply place the pointers into an array. Except you have the problem that you can't declare the functions/types and populate an array at the same time (can't interleave declarations with initializers, can't put effectful statements at the toplevel), which means that to do so would mean duplicating the function name list.

This sounds like a job for X-macros. X-macros are essentially a preprocessor variant of higher-order functions: a macro invocation is formed and held separately from the context where the macro is defined. This makes it possible to change which macro is expanded, or apply more than one.

e.g. functions.h:

FUNCTION(void, f1, puts("in f1"))
FUNCTION(void, f2, puts("in f2"))
FUNCTION(void, f3, puts("in f3"))
FUNCTION(void, f4, puts("in f4"))
FUNCTION(void, f5, puts("in f5"))

main.c:

#define FUNCTION(T, N, B) T N (void){ B; }
#include "functions.h"
#undef FUNCTION

#define FUNCTION(T, N, B) (fptr)N,
typedef void(*fptr)(void);
fptr funcs[] = {
    #include "functions.h"
};

int main(void) {
    for (int i = 0; i < 5; i ++) {
        funcs[i]();
    }
}

The function list only needs to be maintained in one place, but the context it's included into changes, and changes the meaning of the function declaration macro so that it can be reused for multiple purposes.

It's also possible to use "true" higher-order macros in the preprocessor, but doing so requires either a bit of boilerplate or a metaprogramming library, so while it's far more elegant, it may not be worth the hassle for a single piece of metacode.

Upvotes: 1

Related Questions