Where do I stop when I set a breakpoint in a function in GDB (x86)

It's very basic, but I didn't know it so far, so make a note.

When I set breakpoints on a function in GDB, I didn't know where to stop execution at the machine language level. Immediately before the caller's call? Immediately after the call? After pushing the base pointer? After securing the area for local variables?

From the conclusion, it was after allocating the area of the local variable. (That is, the minimum required stack frame processing is executed when called)

Actual operation check

The language (standard) is C99.

environment

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
Linux Vega 4.4.0-131-generic #157-Ubuntu SMP Thu Jul 12 15:51:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Confirmation code

#include <stdio.h>

int func(int a, int b){
    int c;
    c = a + b;
    return(2 * c);
}

int main(void){
    int n;

    n = func(1, 2);
    printf("%d\n", n);
    return 0;
}

x86

compile

gcc -m32 -g -O0 -std=c99 -fno-stack-protector test.c

Check with gdb

salacia@Vega:~/tmp/gdb$ gdb a.out
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) b func
Breakpoint 1 at 0x8048411: file test.c, line 5.
(gdb) r
Starting program: /home/salacia/tmp/gdb/a.out

Breakpoint 1, func (a=1, b=2) at test.c:5
5           c = a + b;
(gdb) p $eip
$1 = (void (*)()) 0x8048411 <func+6>

The instruction that stopped was placed at the address 0x8048411. (Up to the previous instruction has been executed)

Let's look at the instructions before and after.

salacia@Vega:~/tmp/gdb$ objdump -d -M intel a.out

a.out:     file format elf32-i386

=============================abridgement=============================

0804840b <func>:
 804840b:       55                      push   ebp
 804840c:       89 e5                   mov    ebp,esp
 804840e:       83 ec 10                sub    esp,0x10
 8048411:       8b 55 08                mov    edx,DWORD PTR [ebp+0x8]
 8048414:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 8048417:       01 d0                   add    eax,edx
 8048419:       89 45 fc                mov    DWORD PTR [ebp-0x4],eax
 804841c:       8b 45 fc                mov    eax,DWORD PTR [ebp-0x4]
 804841f:       01 c0                   add    eax,eax
 8048421:       c9                      leave
 8048422:       c3                      ret

804840b: Save base pointer 804840c: Set the stack pointer to the new base pointer. 804840e: Subtract esp to reserve space for local variables 8048411: Copy the argument to the register for the operation (stopped here), the processing in the function starts here

So, on x86, when I set a breakpoint on a function, I found that it runs up to the stack frame processing.

Bonus (x64)

I haven't touched the x64 assembler, so I don't know what the result will be, but I did my own research. If you make a mistake, I would appreciate it if you could point it out.

compile

gcc -g -O0 -std=c99 -fno-stack-protector test.c

Check with gdb

salacia@Vega:~/tmp/gdb$ gdb a.out
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) b func
Breakpoint 1 at 0x400530: file test.c, line 5.
(gdb) r
Starting program: /home/salacia/tmp/gdb/a.out

Breakpoint 1, func (a=1, b=2) at test.c:5
5           c = a + b;
(gdb) p $rip
$1 = (void (*)()) 0x400530 <func+10>

It stopped at the instruction at the address 0x400530. Let's look at the instructions before and after this address.

salacia@Vega:~/tmp/gdb$ objdump -d -M intel a.out

a.out:     file format elf64-x86-64

=============================abridgement=============================

0000000000400526 <func>:
  400526:       55                      push   rbp
  400527:       48 89 e5                mov    rbp,rsp
  40052a:       89 7d ec                mov    DWORD PTR [rbp-0x14],edi
  40052d:       89 75 e8                mov    DWORD PTR [rbp-0x18],esi
  400530:       8b 55 ec                mov    edx,DWORD PTR [rbp-0x14]
  400533:       8b 45 e8                mov    eax,DWORD PTR [rbp-0x18]
  400536:       01 d0                   add    eax,edx
  400538:       89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  40053b:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  40053e:       01 c0                   add    eax,eax
  400540:       5d                      pop    rbp
  400541:       c3                      ret

First, the base pointer is saved and a new base pointer is set. Next is probably the argument processing part. The Linux x64 calling convention (System V ABI) attempts to pass arguments in registers before the stack. Since there are two 4-byte arguments this time, the caller stores the values in ʻedi and ʻesi. We have copied these values into the stack frame (instructions 40052a and 40052d).

So far, we've reached a breakpoint. Unlike x86, there is no stack pointer subtraction etc. In the case of x64, is this the treatment of stack frame processing? Is it okay to think that?

It's unpleasant to end here, so I'll try a little more.

I looked at a function that does nothing in particular to find out how far the stack frame is processed.

salacia@Vega:~/tmp/gdb$ cat func.c
int func(int a, int b){
    int c;
    return 0;
}
salacia@Vega:~/tmp/gdb$ objdump -d -M intel func.o

func.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <func>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
   7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
   a:   b8 00 00 00 00          mov    eax,0x0
   f:   5d                      pop    rbp
  10:   c3                      ret

Unlike x86, it doesn't seem to subtract the stack pointer. And, after all, the argument is copied to the stack frame. After that, since the return location is put in ʻeax`, it is already in the processing in the function.

I feel that push cannot be done unless the stack pointer is subtracted, but since there are few local variables, does it mean that stack operations are unnecessary?

So, this time I tried using the stack. In x64, if the number of arguments is large and it cannot be passed in the register, the stack will be used, so I called a function with many arguments.

int func2(int a, int b, int c, int d, int e, int f, int g){
    return 0;
}

int func(int a, int b){
    int c = 0x00;
    int d = 0x11;
    int e = 0x22;
    int f = 0x33;
    int g = 0x44;
    int h = 0x55;
    int i = 0x66;
    func2(a, b, c, d, e, f, g);
    return 0;
}
salacia@Vega:~/tmp/gdb$ objdump -d -M intel func.o

func.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <func2>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
   7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
   a:   89 55 f4                mov    DWORD PTR [rbp-0xc],edx
   d:   89 4d f0                mov    DWORD PTR [rbp-0x10],ecx
  10:   44 89 45 ec             mov    DWORD PTR [rbp-0x14],r8d
  14:   44 89 4d e8             mov    DWORD PTR [rbp-0x18],r9d
  18:   b8 00 00 00 00          mov    eax,0x0
  1d:   5d                      pop    rbp
  1e:   c3                      ret

000000000000001f <func>:
  1f:   55                      push   rbp
  20:   48 89 e5                mov    rbp,rsp
  23:   48 83 ec 28             sub    rsp,0x28
  27:   89 7d dc                mov    DWORD PTR [rbp-0x24],edi
  2a:   89 75 d8                mov    DWORD PTR [rbp-0x28],esi
  2d:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  34:   c7 45 f8 11 00 00 00    mov    DWORD PTR [rbp-0x8],0x11
  3b:   c7 45 f4 22 00 00 00    mov    DWORD PTR [rbp-0xc],0x22
  42:   c7 45 f0 33 00 00 00    mov    DWORD PTR [rbp-0x10],0x33
  49:   c7 45 ec 44 00 00 00    mov    DWORD PTR [rbp-0x14],0x44
  50:   c7 45 e8 55 00 00 00    mov    DWORD PTR [rbp-0x18],0x55
  57:   c7 45 e4 66 00 00 00    mov    DWORD PTR [rbp-0x1c],0x66
  5e:   44 8b 4d f0             mov    r9d,DWORD PTR [rbp-0x10]
  62:   44 8b 45 f4             mov    r8d,DWORD PTR [rbp-0xc]
  66:   8b 4d f8                mov    ecx,DWORD PTR [rbp-0x8]
  69:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
  6c:   8b 75 d8                mov    esi,DWORD PTR [rbp-0x28]
  6f:   8b 45 dc                mov    eax,DWORD PTR [rbp-0x24]
  72:   8b 7d ec                mov    edi,DWORD PTR [rbp-0x14]
  75:   57                      push   rdi
  76:   89 c7                   mov    edi,eax
  78:   e8 00 00 00 00          call   7d <func+0x5e>
  7d:   48 83 c4 08             add    rsp,0x8
  81:   b8 00 00 00 00          mov    eax,0x0
  86:   c9                      leave
  87:   c3                      ret

When performing a stack operation in a function, it seems that the stack pointer is subtracted (0x23 instruction). Some functions have fewer instructions, so it can be said that they are more optimized than x86.

So where does it stop if you set a function that started using this stack as a breakpoint?

#include <stdio.h>

int func2(int a, int b, int c, int d, int e, int f, int g){
    return 0;
}

int func(int a, int b){
    int c = 0x00;
    int d = 0x11;
    int e = 0x22;
    int f = 0x33;
    int g = 0x44;
    int h = 0x55;
    int i = 0x66;
    func2(a, b, c, d, e, f, g);
    return 0;
}

int main(void){
    int n;

    n = func(1, 2);
    printf("%d\n", n);
    return 0;
}
salacia@Vega:~/tmp/gdb$ gdb a.out
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) b func
Breakpoint 1 at 0x400553: file test.c, line 8.
(gdb) r
Starting program: /home/salacia/tmp/gdb/a.out

Breakpoint 1, func (a=1, b=2) at test.c:8
8           int c = 0x00;
(gdb) p $rip
$1 = (void (*)()) 0x400553 <func+14>

Look before and after 0x400553.

0000000000400545 <func>:
  400545:       55                      push   rbp
  400546:       48 89 e5                mov    rbp,rsp
  400549:       48 83 ec 28             sub    rsp,0x28
  40054d:       89 7d dc                mov    DWORD PTR [rbp-0x24],edi
  400550:       89 75 d8                mov    DWORD PTR [rbp-0x28],esi
  400553:       c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  40055a:       c7 45 f8 11 00 00 00    mov    DWORD PTR [rbp-0x8],0x11
  400561:       c7 45 f4 22 00 00 00    mov    DWORD PTR [rbp-0xc],0x22
  400568:       c7 45 f0 33 00 00 00    mov    DWORD PTR [rbp-0x10],0x33
  40056f:       c7 45 ec 44 00 00 00    mov    DWORD PTR [rbp-0x14],0x44
  400576:       c7 45 e8 55 00 00 00    mov    DWORD PTR [rbp-0x18],0x55
  40057d:       c7 45 e4 66 00 00 00    mov    DWORD PTR [rbp-0x1c],0x66
  400584:       44 8b 4d f0             mov    r9d,DWORD PTR [rbp-0x10]
  400588:       44 8b 45 f4             mov    r8d,DWORD PTR [rbp-0xc]
  40058c:       8b 4d f8                mov    ecx,DWORD PTR [rbp-0x8]
  40058f:       8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
  400592:       8b 75 d8                mov    esi,DWORD PTR [rbp-0x28]
  400595:       8b 45 dc                mov    eax,DWORD PTR [rbp-0x24]
  400598:       8b 7d ec                mov    edi,DWORD PTR [rbp-0x14]
  40059b:       57                      push   rdi
  40059c:       89 c7                   mov    edi,eax
  40059e:       e8 83 ff ff ff          call   400526 <func2>
  4005a3:       48 83 c4 08             add    rsp,0x8
  4005a7:       b8 00 00 00 00          mov    eax,0x0
  4005ac:       c9                      leave
  4005ad:       c3                      ret

It seems that it stopped executing until it copied the argument into the stack frame. From here, the process of assigning the initial value to the local variable has started.

In x64, the following is the stack frame processing, and if you set a breakpoint in the function with gdb, execute it so far

--Save the base pointer and set a new base pointer --Allocate space for local variables (may not be done) --Copy arguments into stack frame

I learned a lot. ~~ (The bonus was the main story) ~~

Recommended Posts

Where do I stop when I set a breakpoint in a function in GDB (x86)
I get a can't set attribute when using @property in python
Precautions when pickling a function in python
When I get a chromedriver error in Selenium
I want to save a file with "Do not compress images in file" set in OpenPyXL
I get a java.util.regex.PatternSyntaxException when splitting a string in PySpark
I want to do something in Python when I finish
The story I was addicted to when I specified nil as a function argument in Go
A set of script files that do wordcloud in Python3
Create a function in Python
[Python] Execution time when a function is entered in a dictionary value
I wrote a function to load a Git extension script in Python