[LINUX] Function pointer and objdump ~ C language ~

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

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;
}

Look up the function address with objdump

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 \ :". This display differs depending on the processing system.

※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>:

Function call

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.

For addresses other than functions ...

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

Function pointer and objdump ~ C language ~
Socket communication by C language and Python
C ++ simple sleep function
C language ALDS1_3_B Queue
[C language algorithm] Endianness
Go language to see and remember Part 7 C language in GO language
Call the C function with dart: ffi and call the Dart function callback
I tried to illustrate the time and time in C language
[Golang] Basics of Go language About value receiver and pointer receiver
[C language algorithm] Block movement
Machine language embedding in C language
C language ALDS1_4_B Binary Search
Heapsort made in C language
About fork () function and execve () function
[C language] readdir () vs readdir_r ()
C language ALDS1_4_A Linear Search
django timezone and language settings
Boundary between C and Golang
[C language] How to create, avoid, and make a zombie process