You can insert platform specific assembly language code to accomplish what you want. Just be warned that it is not portable.
Let's see two versions of a slightly simplified version of your program:
Version 1 (clean code):
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(int) = &func;
f(-2);
return 0;
}
Version 2 (hackish code):
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(void) = (void (*)(void))&func;
return 0;
}
You can use gcc -S
to generate the assembly code for both versions.
Assembly code for version 1 in my environment:
.file "soc.c"
.section .rdata,"dr"
.LC0:
.ascii "%p : %d\12\0"
.text
.globl func
.def func; .scl 2; .type 32; .endef
.seh_proc func
func:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
movl %eax, %r8d
leaq 16(%rbp), %rdx
leaq .LC0(%rip), %rcx
call printf
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq func(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movl $-2, %ecx
call *%rax
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 4.9.3"
.def printf; .scl 2; .type 32; .endef
Assembly code for version 2 in my environment:
.file "soc.c"
.section .rdata,"dr"
.LC0:
.ascii "%p : %d\12\0"
.text
.globl func
.def func; .scl 2; .type 32; .endef
.seh_proc func
func:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
movl %eax, %r8d
leaq 16(%rbp), %rdx
leaq .LC0(%rip), %rcx
call printf
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq func(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
call *%rax
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 4.9.3"
.def printf; .scl 2; .type 32; .endef
The only difference between the assembly code of the two versions is line 44.
movl $-2, %ecx
If you inject the same assembly code into the second version of the program as:
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(void) = (void (*)(void))&func;
__asm__("movl $-2, %ecx");
f();
return 0;
}
the compiler generates the expected assembly code. When I run the above program, I get:
0x22cae0 : -2
which is the same output you would see with the first version of the program.