While learning C, I have always viewed function pointers as being like object pointers (i.e. values representing memory addresses), except that, being a function pointer, it is callable like a function. In order to get a better understanding of function pointers, I tried to allocate machine instructions on the stack, have a function pointer to these instructions, and then call them as one would normally call a function. So I wrote a simple function:
int three(void) { return 3; }
and viewed its machine code representation using objdump -d
:
00000001400017d0 <three>:
1400017d0: b8 03 00 00 00 mov $0x3,%eax
1400017d5: c3 ret
1400017d6: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
1400017dd: 00 00 00
I wrote this program to actually allocate the function on the stack and call it:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint8_t f[] = {
0xb8u, 0x03u, 0x00u, 0x00u, 0x00u,
0xc3u,
0x66u, 0x2eu, 0x0fu, 0x1fu, 0x84u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u
};
printf("%d\n", ((int (*)(void)) f)());
return 0;
}
but my program seems to exit with a failure when I actully run the code using a recent version of clang
.
I tried to verify the objdump
with this program:
for (size_t i = 0; i < 1000; i++) {
printf("%02X ", ((uint8_t *) three)[i]);
if (i % 16 == 15)
putchar('\n');
}
}
and it seemed to be correct.
What exactly is happening here? Is my understanding of function pointers incorrect or is my implementation erroneous? I am using a Windows machine and MSVCRT for my runtime, so this may be causing some issues, but that notwithstanding, it seems that the code should work as intended anyways, because then how else are actual functions implemented?
P.S. It is my understanding that casting between an object pointer and a function pointer is nonstandard C, but clang
allows the above code to compile even when using -Wpedantic -Werror
even though gcc
does not. This may relate to the problem; I'm not sure.