1

I would like to have an universal function pointer in C which only specifies the number of arguments, but their size should be of any kind. I thought the following program would crash, but somehow it does work on some devices with 64 Bit architecture but not on 32 Bit. I am not sure if the wideness of architecture is the reason for the different results.

#include <stdio.h>                                         
#include <stdlib.h>                                                                                                   
typedef int METHOD(int64_t, int64_t, int64_t, int64_t);    
int foo(int i, char c, short s, long l){                           
    printf("i: %d, c: %c s: %hd l:%ld\n", i, c, s, l);         
    return 5;                                          
}                                                                                                                     
int main(int argc, char ** argv){                                  
    METHOD * ptr=(METHOD*)&foo;                                
    printf("res: %d\n", 
    ptr(1,'2',3,4));                       
    printf("res: %d\n", 
    foo(1,'2',3,4));                       
    return 0;                                          
}

Is there a way to make this work on any architecture?

6
  • 1
    I believe the reason for not working on 32 bits is this type int64_t Commented Mar 12, 2020 at 18:05
  • 1
    You may need to cast your arguments to int64_t (or a void *) and cast it back when accepting them, but probably there's an easier and more type-safe way to do whatever it is you want. Commented Mar 12, 2020 at 18:09
  • I need this for the JVM. On some point of execution the JVM would like to call a native C method which can have different size arguments. Maybe there is a way to do this with assembler-code... Commented Mar 12, 2020 at 18:14
  • Unfortunately casting can't be done, because the size of the arguments is known only at runtime. Commented Mar 12, 2020 at 18:26
  • For the JVM I could use only int32_t and store long and double in two int32_t values. Commented Mar 12, 2020 at 18:32

1 Answer 1

3

No, there is not.

It works on x64 because the first 4 integer parameters are passed in the register rcx, rdx, r8 and r9. It doesn't matter how big the parameters actually are - they each get a 64-bit register regardless. Only the bottom part of the register is used. Since int and char and short and long are all passed this way, your program runs and the function is about to access the parameters.

Different architectures pass parameters differently. In particular, they may be pushed on the stack (x86 does this). char and short might be converted to int before pushing, but int64_t certainly will not. So on a 32-bit architecture which pushes arguments on the stack, the caller pushes 4*64 bits, and the function tries to read 4*32 bits, and they don't line up correctly.

Even worse, in some calling conventions (e.g. x86 __stdcall) the function has to remove the arguments from the stack. If you have the wrong arguments on this architecture, it corrupts the stack and crashes your program.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.