Überprüfen der Stack-Nutzung zur Kompilierzeit

Lesezeit: 7 Minuten

Benutzer-Avatar
Schodanex

Gibt es eine Möglichkeit, die von einer Funktion zur Kompilierzeit in C benötigte Stapelgröße zu kennen und auszugeben? Hier ist, was ich gerne wissen möchte:

Nehmen wir eine Funktion:

void foo(int a) {
    char c[5];
    char * s;
    //do something
    return;
}

Wenn ich diese Funktion kompiliere, würde ich gerne wissen, wie viel Stapelplatz sie verbraucht, wenn sie aufgerufen wird. Dies kann nützlich sein, um die On-Stack-Deklaration einer Struktur zu erkennen, die einen großen Puffer versteckt.

Ich suche etwas, das so etwas drucken würde:

Datei foo.c : Funktion foo Stack-Nutzung ist n Bytes

Gibt es eine Möglichkeit, die generierte Assembly nicht anzusehen, um das zu wissen? Oder ein Limit, das für den Compiler gesetzt werden kann?

Update: Ich versuche nicht, einen Laufzeitstapelüberlauf für einen bestimmten Prozess zu vermeiden, ich suche nach einer Möglichkeit, vor der Laufzeit herauszufinden, ob eine vom Compiler festgelegte Verwendung des Funktionsstapels als Ausgabe des Kompilierungsprozesses verfügbar ist.

Anders ausgedrückt: Ist es möglich, die Größe aller Objekte zu kennen, die lokal zu einer Funktion gehören? Ich denke, die Compiler-Optimierung wird nicht mein Freund sein, weil einige Variablen verschwinden, aber ein höheres Limit ist in Ordnung.

  • Falls Sie sich fragen, ich habe das geheime Zeichen „}“ eingegeben

    – 1800 INFORMATIONEN

    24. September 2008 um 8:33 Uhr

  • Die Frage erscheint mir unklar. Ich denke, wenn Sie mehr darüber schreiben, warum Sie das wissen möchten und warum das Überprüfen der Disassemblierung oder der ausführbaren Datei (was der einfachste Weg ist, die Compilerausgabe zu überprüfen) nicht akzeptabel ist, könnte vielleicht jemand eine einfache Lösung finden?

    – Suma

    24. September 2008 um 11:28 Uhr

Linux-Kernel-Code läuft auf einem 4K-Stack auf x86. Daher kümmern sie sich. Was sie verwenden, um das zu überprüfen, ist ein von ihnen geschriebenes Perl-Skript, das Sie als scripts/checkstack.pl in einem aktuellen Kernel-Tarball finden können (2.6.25 hat es). Es läuft auf der Ausgabe von objdump, die Verwendungsdokumentation befindet sich im Anfangskommentar.

Ich glaube, ich habe es schon vor Ewigkeiten für User-Space-Binärdateien verwendet, und wenn Sie sich ein wenig mit Perl-Programmierung auskennen, ist es einfach, das zu beheben, wenn es kaputt ist.

Wie auch immer, was es im Grunde tut, ist, automatisch auf die Ausgabe von GCC zu schauen. Und die Tatsache, dass Kernel-Hacker ein solches Tool geschrieben haben, bedeutet, dass es keine statische Möglichkeit gibt, dies mit GCC zu tun (oder vielleicht, dass es erst kürzlich hinzugefügt wurde, aber ich bezweifle es).

Übrigens, mit objdump aus dem Mingw-Projekt und ActivePerl oder mit Cygwin sollten Sie das auch unter Windows und auch auf Binärdateien tun können, die mit anderen Compilern erhalten wurden.

  • Update: Michael Greene bemerkte unten, dass GCC 4.6 -fstack-usage für C verfügbar hat: gcc.gnu.org/gcc-4.6/changes.html; -fstack-usage wird unten in der Antwort von Shodanex beschrieben: stackoverflow.com/a/126490/53974.

    – Blaisorlade

    2. September 2012 um 17:56 Uhr

Benutzer-Avatar
Schodanex

StackAnlyser scheint den ausführbaren Code selbst sowie einige Debugging-Informationen zu untersuchen. Was in dieser Antwort beschrieben wird, ist das, wonach ich suche, Stack-Analyzer sieht für mich wie ein Overkill aus.

Etwas Ähnliches wie für ADA wäre in Ordnung. Sehen Sie sich diese Handbuchseite aus dem Gnat-Handbuch an:

22.2 Statische Stack-Nutzungsanalyse

Eine mit -fstack-usage kompilierte Unit generiert eine zusätzliche Datei, die die maximale Menge an verwendetem Stack pro Funktion angibt. Die Datei hat denselben Basisnamen wie die Zielobjektdatei mit der Erweiterung .su. Jede Zeile dieser Datei besteht aus drei Feldern:

* The name of the function.
* A number of bytes.
* One or more qualifiers: static, dynamic, bounded. 

Das zweite Feld entspricht der Größe des bekannten Teils des Funktionsrahmens.

Der Qualifizierer static bedeutet, dass die Framegröße der Funktion rein statisch ist. Dies bedeutet normalerweise, dass alle lokalen Variablen eine statische Größe haben. Das zweite Feld ist dabei ein zuverlässiges Maß für die Auslastung des Funktionsstacks.

Der Qualifizierer dynamisch bedeutet, dass die Funktionsrahmengröße nicht statisch ist. Dies geschieht hauptsächlich, wenn einige lokale Variablen eine dynamische Größe haben. Wenn dieser Qualifizierer allein erscheint, ist das zweite Feld kein zuverlässiges Maß für die Analyse des Funktionsstapels. Wenn es mit begrenzt qualifiziert ist, bedeutet dies, dass das zweite Feld ein zuverlässiges Maximum der Funktionsstapelauslastung ist.

  • Dies ist eine alte Frage, aber fwiw GCC 4.6 hat -fstack-usage für C verfügbar: gcc.gnu.org/gcc-4.6/changes.html

    – Michael Grün

    26. April 2011 um 16:47 Uhr

  • @Michael Greene: Es könnte eine Antwort sein! Vielen Dank !

    – Schodanex

    27. April 2011 um 7:29 Uhr

Benutzer-Avatar
Isak Savo

Ich verstehe nicht, warum eine statische Codeanalyse dafür keine ausreichend gute Zahl liefern könnte.

Es ist trivial, alle lokalen Variablen in einer bestimmten Funktion zu finden, und die Größe für jede Variable kann entweder über den C-Standard (für eingebaute Typen) oder durch Berechnung (für komplexe Typen wie Strukturen und Vereinigungen) ermittelt werden.

Sicher, die Antwort kann nicht zu 100 % korrekt sein, da der Compiler verschiedene Arten von Optimierungen vornehmen kann, z. B. Auffüllen, Variablen in Register einfügen oder unnötige Variablen vollständig entfernen. Aber jede Antwort, die es gibt, sollte zumindest eine gute Schätzung sein.

Ich habe eine schnelle Google-Suche gemacht und gefunden StackAnalyzer aber ich vermute, dass andere Tools zur statischen Codeanalyse ähnliche Fähigkeiten haben.

Wenn Sie eine 100% genaue Zahl wünschen, müssen Sie sich die Ausgabe des Compilers ansehen oder sie während der Laufzeit überprüfen (wie Ralph in seiner Antwort vorgeschlagen hat).

  • StackAnalyzer scheint nett zu sein, aber es erfüllt nicht die angeforderte Aufgabe, da es die ausführbare Datei analysiert, nicht den Quellcode. Während das Schreiben eines solchen Tools theoretisch wirklich möglich sein sollte, glaube ich nicht, dass es ein solches Tool gibt – das Überprüfen der Stack-Nutzungslaufzeit oder basierend auf Assemblierung ist sehr praktisch.

    – Suma

    24. September 2008 um 11:25 Uhr

  • Ich sage nur einen Funktionsnamen, und Sie wissen, warum die statische Codeanalyse nicht ausreicht, um den verwendeten Stapelspeicher einer Funktion zu ermitteln: alloca. Sobald eine Funktion es verwendet (mit nicht konstantem Wert), können Sie es nicht machen. Eine andere Sache, die bereits erwähnt wurde: Rekursion.

    – flolo

    12. Januar 2009 um 9:04 Uhr

Nur der Compiler würde es wirklich wissen, da er der Typ ist, der all Ihre Sachen zusammenfügt. Sie müssten sich die generierte Assembly ansehen und sehen, wie viel Platz in der Präambel reserviert ist, aber das berücksichtigt nicht wirklich Dinge wie alloca die zur Laufzeit ihr Ding machen.

Angenommen, Sie befinden sich auf einer eingebetteten Plattform, stellen Sie möglicherweise fest, dass Ihre Toolchain dies versucht. Gute kommerzielle eingebettete Compiler (wie zum Beispiel der Arm/Keil-Compiler) erstellen oft Berichte über die Stack-Nutzung.

Natürlich liegen Interrupts und Rekursion normalerweise etwas darüber, aber es gibt Ihnen eine ungefähre Vorstellung davon, ob jemand irgendwo einen schrecklichen Fehler mit einem Multi-Megabyte-Puffer auf dem Stack begangen hat.

Nicht genau “Kompilierzeit”, aber ich würde dies als Post-Build-Schritt tun:

  • Lassen Sie den Linker eine Kartendatei für Sie erstellen
  • Lesen Sie für jede Funktion in der Zuordnungsdatei den entsprechenden Teil der ausführbaren Datei und analysieren Sie den Funktionsprolog.

Dies ist ähnlich wie StackAnalyzer, aber viel einfacher. Ich denke, die Analyse der ausführbaren Datei oder der Disassemblierung ist der einfachste Weg, um zur Compilerausgabe zu gelangen. Obwohl der Compiler diese Dinge intern weiß, befürchte ich, dass Sie sie nicht davon bekommen können (Sie könnten den Compiler-Anbieter bitten, die Funktionalität zu implementieren, oder wenn Sie einen Open-Source-Compiler verwenden, könnten Sie es selbst tun oder jemanden tun lassen für dich).

Um dies zu implementieren, müssen Sie:

  • Kartendatei parsen können
  • Format der ausführbaren Datei verstehen
  • wissen, wie ein Funktionsprolog aussehen kann und können ihn “decodieren”.

Wie einfach oder schwierig dies wäre, hängt von Ihrer Zielplattform ab. (Embedded? Welche CPU-Architektur? Welcher Compiler?)

All dies kann definitiv in x86/Win32 durchgeführt werden, aber wenn Sie so etwas noch nie gemacht haben und das alles von Grund auf neu erstellen müssen, kann es ein paar Tage dauern, bis Sie fertig sind und etwas funktioniert.

Benutzer-Avatar
xmjx

Nicht im Allgemeinen. Das Halteproblem in der theoretischen Informatik legt nahe, dass Sie nicht einmal vorhersagen können, ob ein allgemeines Programm bei einer bestimmten Eingabe anhält. Die Berechnung des für einen Programmlauf verwendeten Stacks im Allgemeinen wäre noch komplizierter. Also: nein. Vielleicht in besonderen Fällen.

Angenommen, Sie haben eine rekursive Funktion, deren Rekursionsebene von der Eingabe abhängt, die beliebig lang sein kann, und Sie haben bereits Pech.

  • Sie sprechen über den Prozessstapel, nicht darüber, wie viel jeder Aufruf der Funktion verwenden wird

    – Schodanex

    24. September 2008 um 10:18 Uhr

  • Das Halteproblem stoppt nicht die statische Analyse (z. B. in Compilern) und ungefähre Antworten, indem man sich den Programmtext ansieht. Tatsächlich ist das Rechnen eine große Herausforderung, wenn zwei verschiedene Programme äquivalent sind, sodass zwei äquivalente Programme bei der statischen Analyse unterschiedliche Ergebnisse liefern können.

    – Blaisorlade

    12. Januar 2009 um 8:46 Uhr

1382120cookie-checkÜberprüfen der Stack-Nutzung zur Kompilierzeit

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy