Experiment to call a function from the created program using a function pointer and objdump.
You can get a little idea of what it means to call a function and how the function is executed.
The experimental environment is Linux (CentOS7 64bit) + gcc (version 4.8.5).
Source code used for experiments. This is a sample that uses a function pointer to execute the processing of the address passed as an argument when the program is executed.
sample.c
#include <stdio.h>
#include <stdlib.h>
void dog(void)
{
printf("wan wan\n");
}
void cat(void)
{
printf("nyaaan\n");
}
void birds(void)
{
printf("piyo piyo\n");
printf("chun chun\n");
printf("kah kah\n");
}
int main(int argc, char* argv[])
{
void (*myfunc)(void); /*This is a function pointer*/
if (argc != 2) {
printf("%s <address>\n", argv[0]);
exit(EXIT_FAILURE);
}
/*Convert the hexadecimal string passed as an argument to a number*/
myfunc = (void(*)(void))strtol(argv[1], NULL, 16);
/*Run*/
myfunc();
return 0;
}
Compile the created source code and analyze the completed program with objdump.
$ gcc sample.c
$ objdump -d a.out
~ Omitted ~
000000000040060d <dog>:
40060d: 55 push %rbp
40060e: 48 89 e5 mov %rsp,%rbp
400611: bf 50 07 40 00 mov $0x400750,%edi
400616: e8 a5 fe ff ff callq 4004c0 <puts@plt>
40061b: 5d pop %rbp
40061c: c3 retq
000000000040061d <cat>:
40061d: 55 push %rbp
40061e: 48 89 e5 mov %rsp,%rbp
400621: bf 58 07 40 00 mov $0x400758,%edi
400626: e8 95 fe ff ff callq 4004c0 <puts@plt>
40062b: 5d pop %rbp
40062c: c3 retq
000000000040062d <birds>:
40062d: 55 push %rbp
40062e: 48 89 e5 mov %rsp,%rbp
400631: bf 5f 07 40 00 mov $0x40075f,%edi
400636: e8 85 fe ff ff callq 4004c0 <puts@plt>
40063b: bf 69 07 40 00 mov $0x400769,%edi
400640: e8 7b fe ff ff callq 4004c0 <puts@plt>
400645: bf 73 07 40 00 mov $0x400773,%edi
40064a: e8 71 fe ff ff callq 4004c0 <puts@plt>
40064f: 5d pop %rbp
400650: c3 retq
~ Omitted ~
The address of the function is where the function name and number are set, such as "000000000040060d \
※Caution
In the case of Debian system (Debian, Ubuntu, Mint, etc.), it seems that PIE (function used for security enhancement) may be enabled by default at compile time. In that case it won't work, so add -no-pie to the gcc options.
When PIE is enabled, the address value will be smaller as shown below, and the higher address (the part displayed as 0) will change each time the program is executed.
0000000000000855 <dog>:
Now that you know the address of the function, try it out.
Call dog () (0x40060d)
$ ./a.out 0x40060d
wan wan
Call cat () (0x40061d)
$ ./a.out 0x40061d
nyaaan
Call birds () (0x40062d)
$ ./a.out 0x40062d
piyo piyo
chun chun
kah kah
I was able to call the function as expected.
In the previous example, we specified the address of the function in the function pointer and called any function.
But what if you specify another address?
Let's pass the address in the middle of birds ().
000000000040062d <birds>:
40062d: 55 push %rbp
40062e: 48 89 e5 mov %rsp,%rbp
400631: bf 5f 07 40 00 mov $0x40075f,%edi
400636: e8 85 fe ff ff callq 4004c0 <puts@plt>
40063b: bf 69 07 40 00 mov $0x400769,%edi
400640: e8 7b fe ff ff callq 4004c0 <puts@plt>
400645: bf 73 07 40 00 mov $0x400773,%edi
★^^^^^^^^Let's specify the address of this line.
40064a: e8 71 fe ff ff callq 4004c0 <puts@plt>
40064f: 5d pop %rbp
400650: c3 retq
Execution example
$ ./a.out 0x400645
kah kah
Segmentation fault (Core dump)
I was able to execute the process from the middle of the function. However, it ended abnormally with a core dump.
The reason for the core dump is that I don't know which address to return to after myfunc () has finished executing (return address is incorrect).
Once you understand this area, C language will become a little more fun.
Recommended Posts