Ogelami
Ogelami

Reputation: 365

casting unsigned char * buffer to a callable void pointer that can take an argument

The problem i have is that i don't know how to do the casting properly, my objective is to call the method that will be placed in the buf.

This is my compiler error.

error: ‘buf’ cannot be used as a function

This is my current code

...

unsigned char *getFileBuffer(const char filename[], long &fileSize)
{
    ...
}

void (*ptrox)(int &) = NULL;

int main()
{
    long filesize = -1;
    int x = 3;

    //buf will consist of a operation, that takes an referenced int as an argument.
    unsigned char *buf = getFileBuffer("foo", filesize);

    //This is obviously not correct and does not match the description.
    ptrox = (void *)&buf(int &);

    ptrox(x);

    cout << x;
}

And this is the actual method / buffer.

void i(int &x)
{
    x += 2;
}

__Z1iRi:
0000000100000cbb    55                  pushq   %rbp
0000000100000cbc    4889e5              movq    %rsp, %rbp
0000000100000cbf    48897df8            movq    %rdi, -0x8(%rbp)
0000000100000cc3    488b45f8            movq    -0x8(%rbp), %rax
0000000100000cc7    8b00                movl    (%rax), %eax
0000000100000cc9    8d5002              leal    0x2(%rax), %edx
0000000100000ccc    488b45f8            movq    -0x8(%rbp), %rax
0000000100000cd0    8910                movl    %edx, (%rax)
0000000100000cd2    5d                  popq    %rbp
0000000100000cd3    c3                  ret

Upvotes: 0

Views: 869

Answers (2)

Sergey L.
Sergey L.

Reputation: 22542

A correct typecast would look like this:

ptrox = (void (*)(int &))buf;

Why don't you use dlopen/dlsym for loading functions? Will be less error prone. Also by default your memory into which you load your function will not be executable, so if you try to run ptrox it will get a SIGSEGV.

In order to use libdl you would need to compile your function foo for example in a shared library and load it like this:

void * libhandle = dlopen("foo.so", RTLD_NOW);
if (!libhandle) {
    perror("dlopen");
    abort();
}
ptrox = (void (*)(int &))dlsym(libhandle,
    "foo" // C function name (use extern "C" where appropriate)
    );
if (!ptrox) {
    perror("dlsym");
    abort();
}

If you require to load a C++ function pointer to be loaded then you will need to use it's mangled function name. Consult nm foo.so for it.

How to mmap executable memory:

void * getFileBuffer(const char filename[], long fileSize) {
    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("open");
        abort();
    }
    void * buf = mmap(
          NULL
        , fileSize
        , PROT_READ | PROT_EXEC
        , MAP_PRIVATE
        , fd
        , 0
    );
    if (buf == MAP_FAILED) {
        perror("map");
        abort();
    }

    return buf;
}

Upvotes: 2

George Nechifor
George Nechifor

Reputation: 439

For me the following construct works: ptrox = (void (*)(int &))buf; but don't know why the paranthesis around * is needed.

how i usually handle this:

typedef void *pfunc(int &);

then i can use

ptrox = (pfunc)buf;

Upvotes: 0

Related Questions