C language: two sample analyses based on function Pointers

  • 2020-04-01 23:31:41
  • OfStack

The first:
------------------------------------------------------


#include <stdio.h>
#include <string.h>
void tell_me(int f(const char *, const char *));
int main(void)
{
   tell_me(strcmp);
   tell_me(main);
   return 0;
}
void tell_me(int f(const char *, const char *))
{
   if (f == strcmp) 
      printf("Address of strcmp(): %pn", f);
   else
      printf("Function address: %pn", f);
}

--------------------------------------------------------------
Among them, what I don't understand is that this program should say that f is a pointer to a function, and when determining whether f refers to the function STRCMP, if so, it will output the address of the function STRCMP; if not, it will output the address of the main function
Because the function name can be used as a pointer, if (f == STRCMP) should be used to determine whether two Pointers have the same address, right?
I use GDB breakpoint to here,print f and printfstrcmp get different addresses, and can find that f and *f content is the same, STRCMP and * STRCMP is the same, what is the reason, how to explain?

Print f (GDB)
$1 = (int (*)(const char *, const char *)) 0x8048310 < STRCMP @ PLT >
Print STRCMP (GDB)
$2 = { < Text variable, no debug info > } 0 xb7e59d20 < STRCMP >
N (GDB)
Printf ("Address of STRCMP (): %p\n", f);
Print STRCMP (GDB)
$3 = { < Text variable, no debug info > } 0 xb7e59d20 < STRCMP >
Print * STRCMP (GDB)
$4 = { < Text variable, no debug info > } 0 xb7e59d20 < STRCMP >
Print * f (GDB)
$5 = {int (const char *, const char *)} 0x8048310 < STRCMP @ PLT >
N (GDB)
The Address of STRCMP () : 0 x8048310
19}
N (GDB)
Later, I found that PLT refers to the process link table. Does it mean that the address of f and the location of STRCMP should be pointed to the same location only when f == STRCMP is executed?

Later discovered by others through disassembly:
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
The next few lines in red, main and STRCMP are now constants (you will also notice that there is no.data section). In assembly code, he is writing these two constants to the function stack, then calling the function, making a comparison, and then output. And what you call f, the function argument, is really just a pre-assignment reference (you can't find f in assembly code).
-------------------------------------------------------------------------------------
. The file "1 c"
The text
. Globl main
The main, @ function
Main:
Leal 4 (esp) %, % ecx
Andl $- 16, % esp
Pushl - 4 (% ecx)
Pushl % ebp
Movl % esp, % ebp
Pushl % ecx
% subl $4, esp
Movl $STRCMP, esp (%)
Call tell_me
Movl $main, % eax
Movl % eax and % (esp)
Call tell_me
Movl $0. % eax
Addl $4, % esp
Popl % ecx
Popl % ebp
Leal - 4 (% ecx), % esp
ret
. The size, the main - the main
. Section. Rodata
LC0:
. String "Address of STRCMP (): %p\n"
LC1:
The string "Function address: % p \ n"
The text
. Globl tell_me
The tell_me, @ function
Tell_me:
Pushl % ebp
Movl % esp, % ebp
Subl $8, % esp
CMPL $STRCMP, 8 (% ebp)
Developed. L4
Movl 8 (% ebp), % eax
Movl % eax, 4 (% esp)
Movl $LC0, esp (%)
Call printf
JMP. L6
L4:
Movl 8 (% ebp), % eax
Movl % eax, 4 (% esp)
Movl $LC1, esp (%)
Call printf
L6:
leave
ret
. The size tell_me,. - tell_me
Ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
. Section. Note. The GNU - stack, ", "@ progbits
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
00401090 disassembly of push ebp // problem 1
00401091 mov ebp, esp
00401093 sub esp, 40 h
00401096 push ebx
00401097 push esi
00401098 push edi
00401099 lea edi, 40 h] [ebp -
0040109 c mov ecx, 10 h
Mov eax, 0cccccccccch // should say that the address of f and STRCMP are the same when the function is passed
004010A6 rep stos dword PTR [edi]
13: printf (" % % 0 0 x \ t \ n "x, f, STRCMP); // look here, the output f and the address of STRCMP are the same
Push offset STRCMP (004011a0)
004010AD mov eax,dword PTR [ebp+8]
004010 b0 push eax
004010B1 push offset string "%0x\t%0x\n" (0042201c)
004010 b6 call printf (00401120).
004010 bb add esp, 0 ch
14: if (f == STRCMP)// after comparison, the output address is the same,
Offset STRCMP (004011a0)
004010 c5 developed tell_me + 4 ah da (004010)
15: printf("Address of STRCMP (): %0x\n", f);
004010C7 mov ecx,dword PTR [ebp+8]
Ca 004010 push ecx
004010CB push offset string "Address of STRCMP (): %0x\n" (00422044)
004010 do call printf (00401120).
004010 d5 add esp, 8
16: the else
004010 d8 JMP tell_me + 5 bh (eb) 004010
17: printf("Function address: %p\n", f);
004010DA mov edx,dword PTR [ebp+8]
004010 dd push edx
Function address: %p\n" (00422028)
004010 e3 call printf (00401120).
004010 e8 add esp, 8 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

The second:
--------------------------------------------------------------------------------------------


#include <stdio.h>
#include <string.h>
int main(void)
{
   char p1[20] = "abc", *p2 = "pacific sea";
   printf("%s %s %sn", p1, p2, strcat(p1, p2)); 
   return 0;
}

---------------------------------------------------------------------------------------------
I think the output should be p1 first, and strcat can be executed later after p2. However, the actual output is as follows:
Abcpacific sea
You can see that strcat executes before p1 and changes the contents of p1. What is the internal order of this? Isn't printf executed sequentially?
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

The answer:
Different compiler printf function arguments in different stack order, printf function strcat can see the disassembly code.
6: printf (" % s \ n \ \ t t % s % s ", p1, p2, strcat (p1, p2));
00401045 mov edx,dword PTR [ebp-18h]
00401048 push edx
00401049 lea eax, 14 h] [ebp -
0040104 c push eax
0040104D call strcat (00401130) // you can see that the strcat function is called first,
00401052 the add esp, 8
00401055 push eax
00401056 mov ecx,dword PTR [ebp-18h]
00401059 push ecx
0040105 a lea edx, 14 h] [ebp -
0040105 d push edx
E push offset string "%s\t%s\t%s\n" (0042201c)
Call printf (004010a0) // last call printf function output
00401068 the add esp, 10 h
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
The compilation is intuitive and simple to illustrate some questions...
Now, how GCC generates assembly code:
1: gcc-s main.c can be generated
2: gcc-c main.c generates main.o
Objdump - S - D main. O > The main. Asm
I prefer the second.


Related articles: