Frage

Ich habe für eingebettete Systeme in der Vergangenheit an Projekten gearbeitet, wo wir die Reihenfolge der Deklaration von Stack-Variablen neu angeordnet haben, die Größe der resultierenden ausführbare Datei zu verringern. Zum Beispiel, wenn wir haben:

void func()
{
    char c;
    int i;
    short s;
    ...
}

Wir würden neu anordnen, dies zu sein:

void func()
{
    int i;
    short s;
    char c;
    ...
}

Aufgrund der Ausrichtungsprobleme der ersten Folge 12 Bytes Stapelspeichers verwendet wird, und die zweite Folge nur 8 Bytes.

Ist das Standardverhalten für C-Compiler oder nur ein Manko des Compilers wir verwendet haben?

Es scheint mir, dass ein Compiler in der Lage sein sollte, Stack-Variablen neu zu ordnen kleinere Größe der ausführbaren Datei zu begünstigen, wenn sie wollte. Es wurde mir vorgeschlagen, dass einige Aspekte des C-Standard verhindert dies, aber ich habe nicht in der Lage gewesen, eine seriöse Quelle entweder Weg zu finden.

Als Bonus Frage, gilt dies auch für C ++ Compiler?

Bearbeiten

Wenn die Antwort Ja lautet, C / C ++ Compiler kann Stack-Variablen neu anordnen, können Sie ein Beispiel für einen Compiler geben, die auf jeden Fall das tut? Ich möchte Compiler Dokumentation oder etwas ähnliches sehen, dass dies sichert.

Bearbeiten Wieder

Vielen Dank allen für Ihre Hilfe. Für die Dokumentation, habe das Beste, was ich in der Lage gewesen zu finden, ist das Papier Optimale Stapel Slot Assignment in GCC (pdf), von Naveen Sharma und Sanjiv Kumar Gupta, die an dem GCC-Gipfel Verfahren im Jahr 2003 vorgestellt wurden.

Das Projekt in Frage hier war die ADS-Compiler für ARM-Entwicklung mit. Es ist für diesen Compiler in der Dokumentation erwähnt, die Erklärungen der Bestellung, wie ich verbessern gezeigt habe Leistung sowie Stack-Größe, weil, wie die ARM-Thumb-Architektur-Adressen im lokalen Stapelrahmen berechnet. Das Compiler nicht automatisch Einheimischen neu ordnen diesen Vorteil zu nehmen. Das Papier hier verknüpft sagt, dass ab 2003 GCC auch nicht den Stack-Frame neu anordnen Referenzlokalität für ARM-Thumb-Prozessoren zu verbessern, aber es bedeutet, dass Sie können.

Ich kann nichts finden, dass auf jeden Fall sagt, dass dies jemals in GCC umgesetzt wurde, aber ich denke, dass dieses Papier gilt als Beweis dafür, dass Sie alle richtig sind. Nochmals vielen Dank.

War es hilfreich?

Lösung

Wie es nichts in der Norm ist das Verbot, dass für C oder C ++ Compiler, ja, kann der Compiler das tun.

Es ist unterschiedlich für Aggregate (d.h. structs), wobei die relative Reihenfolge eingehalten werden muss, aber immer noch der Compiler kann Auffüllbytes eingefügt bevorzugte Ausrichtung zu erreichen.

IIRC neuere MSVC Compiler verwenden, dass die Freiheit in ihrem Kampf gegen Pufferüberläufe von Einheimischen.

Als Randbemerkung, in C ++, muss die Reihenfolge der Zerstörung sein umgekehrte Reihenfolge der Erklärung, auch wenn der Compiler das Speicherlayout neu ordnet.

(Ich kann nicht Kapitel und Vers zitieren, obwohl diese aus dem Speicher ist.)

Andere Tipps

Nicht nur kann der Compiler den Stack Layout der lokalen Variablen neu ordnen, es ihnen zu Registern zuweisen können, ordnen sie in den Registern manchmal zu leben und manchmal auf dem Stapel, es zwei Einheimische auf den gleichen Steckplatz im Speicher zuweisen kann (wenn ihre Live-Bereiche nicht überlappen) und es kann sogar vollständig Variablen eliminieren.

Der Stapel muss nicht einmal existieren (in der Tat, der C99-Standard keinen einziges Vorkommen des Wortes „Stack“ hat). Also ja, der Compiler ist frei zu tun, was es so lange will so dass die Semantik von Variablen mit automatischer Speicherdauer bewahrt.

Als ein Beispiel. Ich oft auf eine Situation gestoßen, wo ich nicht eine lokale Variable in dem Debugger angezeigt werden konnte, weil es in einem Register gespeichert wurde

Der Compiler ist auch frei, die Variable aus dem Stapel zu entfernen und es nur machen, wenn registriert Analyse zeigt, dass die Adresse der Variablen wird nie genommen / verwendet wird.

Ein Compiler nicht einmal sein könnte überhaupt für Daten, die einen Stapel verwenden. Wenn Sie auf einer Plattform so winzig sind, dass Sie etwa 8 vs 12 Byte Stack sind besorgniserregend, dann ist es wahrscheinlich, dass es Compiler sein, die ziemlich spezialisierte Ansätze haben. (Einige PIC und 8051 Compiler in den Sinn kommen)

Welcher Prozessor kompilieren Sie?

Der Compiler für die 62xx Texas Instruments Reihe von DSP in der Lage ist, und tut „Gesamte Programm-Optimierung.“ (Sie können es deaktivieren)

Dies ist, wo Sie den Code neu geordnet wird, nicht nur die Einheimischen. So Reihenfolge der Ausführung endet als nicht ganz das, was man erwarten könnte.

C und C ++ nicht wirklich ein Speichermodell versprechen (im Sinne der JVM sagen), so die Dinge ganz anders sein kann und noch legal.

Für diejenigen, die sie nicht kennen, sind die 62xx-Familie 8 Befehl pro Taktzyklus DSP; bei 750MHz, tun sie Peak bei 6e + 9 Anweisungen. Einige Zeit sowieso. Sie machen die parallele Ausführung, sondern Anweisung Bestellung wird im Compiler getan, nicht die CPU, wie ein Intel x86.

PIC und Kaninchen Embedded Boards nicht Haben stapelt, wenn Sie besonders nett fragen.

es ist Compiler Besonderheiten, kann man seinen eigenen Compiler machen, der die inverse tun würde, wenn er es so wollte.

Ein anständige Compiler lokale Variablen in Registern setzen, wenn er kann. Variablen sollte nur auf dem Stapel gelegt werden, wenn es übermäßiger Registerdruck (nicht genug Platz), oder wenn die Adresse der Variable genommen wird, was bedeutet, es in Erinnerung leben muss.

Soweit ich weiß, gibt es nichts, was Variablen sagt benötigt für C / C zu einem bestimmten Standort oder die Ausrichtung auf den Stapel gelegt werden ++; die Compiler sie setzt, wo immer am besten für die Leistung und / oder was auch immer für Compiler Schriftsteller bequem ist.

AFAIK gibt es nichts in der Definition von C oder C ++ angibt, wie die Compiler lokalen Variablen auf dem Stack bestellen sollte. Ich würde sagen, dass auf Berufung, was der Compiler in diesem Fall tun kann eine schlechte Idee ist, weil die nächste Version des Compilers es anders machen kann. Wenn Sie Zeit und Mühe aufwenden Ihrer lokalen Variablen, um zu bestellen ein paar Bytes des Stapels zu sparen, hatten die wenige Bytes besser für das Funktionieren des Systems wirklich kritisch sein.

Es gibt keine Notwendigkeit für müßige Spekulation darüber, was der C-Standard erfordert oder nicht erfordert: recent Entwürfe sind online frei zugänglich von der ANSI / ISO-Arbeitsgruppe .

Das ist Ihre Frage nicht beantworten, aber hier ist mein 2 Cent zu einem ähnlichen Problem ...

Ich habe nicht das Problem der Stack-Speicher-Optimierung, aber ich habe das Problem der Fehlausrichtung der doppelten Variablen auf dem Stapel. Eine Funktion kann von jeder anderen Funktion und der Stapelzeigerwert kann eine beliebige nicht-abgeglichene Wert bezeichnet werden. So habe ich unten auf die Idee kommen. Dies ist nicht der Original-Code, ich schrieb es nur ...

#pragma pack(push, 16)

typedef struct _S_speedy_struct{

 double fval[4];
 int64  lval[4];
 int32  ival[8];

}S_speedy_struct;

#pragma pack(pop)

int function(...)
{
  int i, t, rv;
  S_speedy_struct *ptr;
  char buff[112]; // sizeof(struct) + alignment

  // ugly , I know , but it works...
  t = (int)buff;
  t +=  15; // alignment - 1
  t &= -16; // alignment
  ptr = (S_speedy_struct *)t;

  // speedy code goes on...
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top