[LINUX] Wo höre ich auf, wenn ich in einer Funktion in GDB (x86) einen Haltepunkt setze?

Es ist sehr einfach, aber ich wusste es bisher nicht, also notieren Sie es sich.

Als ich einen Haltepunkt für eine Funktion in GDB festlegte, wusste ich nicht, wo ich ihn auf Maschinensprachenebene stoppen sollte. Unmittelbar vor dem Anruf des Anrufers? Unmittelbar nach dem Anruf? Nach dem Drücken des Basiszeigers? Nach dem Sichern des Bereichs für lokale Variablen?

Aus der Schlussfolgerung ging hervor, dass "nach Zuweisung des Bereichs der lokalen Variablen". (Das heißt, die minimal erforderliche Stapelrahmenverarbeitung wird beim Aufruf ausgeführt.)

Tatsächliche Funktionsprüfung

Die Sprache (Standard) ist C99.

Umgebung

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

Bestätigungscode

#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

kompilieren

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

Fragen Sie bei gdb nach

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>

Der Befehl, der gestoppt wurde, war die Anweisung an der Adresse "0x8048411". (Bis zum vorherigen Befehl wurde ausgeführt)

Schauen wir uns die Befehle vorher und nachher an.

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

a.out:     file format elf32-i386

=============================Kürzung=============================

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: Basiszeiger speichern 804840c: Setzen Sie den Stapelzeiger auf den neuen Basiszeiger. 804840e: Subtrahiere esp, um Platz für lokale Variablen zu reservieren 8048411: Kopieren Sie das Argument in das Register für die Operation (hier gestoppt), die Verarbeitung in der Funktion von hier

Wenn Sie also in x86 einen Haltepunkt für eine Funktion festlegen, stellt sich heraus, dass "die Verarbeitung des Stapelrahmens ausgeführt wird".

Bonus (x64)

Ich habe den x64-Assembler nicht berührt, daher weiß ich nicht, wie das Ergebnis aussehen wird, aber ich habe meine eigenen Nachforschungen angestellt. Wenn Sie einen Fehler machen, würde ich es begrüßen, wenn Sie darauf hinweisen könnten.

kompilieren

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

Bestätigung mit 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>

Es stoppte bei der Anweisung unter der Adresse "0x400530". Schauen wir uns die Anweisungen vor und nach dieser Adresse an.

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

a.out:     file format elf64-x86-64

=============================Kürzung=============================

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

Zunächst wird der Basiszeiger gespeichert und ein neuer Basiszeiger gesetzt. Als nächstes folgt wahrscheinlich der Teil der Verarbeitung der Argumente. Die x64-Aufrufkonvention von Linux (System V ABI) versucht, Argumente vor dem Stapeln in Registern zu übergeben. Da es diesmal zwei 4-Byte-Argumente gibt, speichert der Aufrufer die Werte in "edi" und "esi". Wir haben diese Werte in den Stapelrahmen kopiert (Anweisungen 40052a und 40052d).

Bisher haben wir einen Haltepunkt erreicht. Im Gegensatz zu x86 gibt es keine Stapelzeigersubtraktion usw. Ist dies im Fall von x64 die Behandlung der Stapelrahmenverarbeitung? Ist es in Ordnung, das zu denken?

Es ist unangenehm, hier zu enden, also werde ich ein bisschen mehr versuchen.

Ich habe mir eine Funktion angesehen, die nichts Besonderes tut, um herauszufinden, wie weit sie Stapelrahmen verarbeitet.

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

Im Gegensatz zu x86 scheint es den Stapelzeiger nicht zu subtrahieren. Und schließlich wird das Argument in den Stapelrahmen kopiert. Da sich der Rückgabeort danach in "eax" befindet, befindet er sich bereits in der Verarbeitung in der Funktion.

Ich bin der Meinung, dass Push nur ausgeführt werden kann, wenn der Stapelzeiger subtrahiert wird. Bedeutet dies jedoch, dass Stapeloperationen nicht erforderlich sind, da nur wenige lokale Variablen vorhanden sind?

Also habe ich diesmal versucht, den Stack zu benutzen. Wenn in x64 die Anzahl der Argumente groß ist und nicht im Register übergeben werden kann, wird der Stapel verwendet. Daher habe ich eine Funktion mit vielen Argumenten aufgerufen.

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

Wenn eine Stapeloperation in einer Funktion ausgeführt wird, scheint der Stapelzeiger subtrahiert zu sein (Anweisung "0x23"). Einige Funktionen haben weniger Anweisungen, daher kann gesagt werden, dass sie optimierter sind als x86.

Wo hört die Funktion, die diesen Stapel verwendet hat, auf, wenn sie als Haltepunkt festgelegt wird?

#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>

Suchen Sie vor und nach 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

Es scheint, dass die Ausführung gestoppt wurde, bis das Argument in den Stapelrahmen kopiert wurde. Von hier aus hat der Prozess der Zuweisung des Anfangswertes zur lokalen Variablen begonnen.

In x64 wird der Stapelrahmen wie folgt verarbeitet. Wenn Sie mit gdb einen Haltepunkt in der Funktion festlegen, führen Sie ihn bisher aus

Ich habe viel gelernt. ~~ (Der Bonus war die Hauptgeschichte) ~~

Recommended Posts

Wo höre ich auf, wenn ich in einer Funktion in GDB (x86) einen Haltepunkt setze?
Bei Verwendung von @property in Python wird ein Attribut nicht festgelegt
Vorsichtsmaßnahmen beim Beizen einer Funktion in Python
Wenn ich einen Chrom-Treiberfehler in Selenium bekomme
Ich erhalte eine java.util.regex.PatternSyntaxException, wenn ich einen String in PySpark teile
Ich möchte am Ende etwas mit Python machen
Eine Geschichte, nach der ich süchtig war, als ich in Go nil als Funktionsargument angab
Eine Reihe von Skriptdateien, die Wordcloud mit Python3 ausführen
Erstellen Sie eine Funktion in Python
[Python] Ausführungszeit, wenn eine Funktion in einen Wörterbuchwert eingegeben wird
Ich habe eine Funktion zum Laden des Git-Erweiterungsskripts in Python geschrieben