Kosten von Push vs. Mov (Stack vs. Near Memory) und der Overhead von Funktionsaufrufen

Lesezeit: 3 Minuten

Benutzer-Avatar
Assad Ebrahim

Frage:

Ist der Zugriff auf den Stack genauso schnell wie der Zugriff auf den Speicher?

Zum Beispiel könnte ich mich dafür entscheiden, einige Arbeiten innerhalb des Stapels zu erledigen, oder ich könnte direkt mit einer gekennzeichneten Stelle im Speicher arbeiten.

Also konkret: ist push ax die gleiche Geschwindigkeit wie mov [bx], ax? Ebenso ist pop ax die gleiche Geschwindigkeit wie mov ax, [bx]? (Angenommen, bx hat einen Standort in near Erinnerung.)

Motivation für die Frage:

In C ist es üblich, von trivialen Funktionen abzuraten, die Parameter annehmen.

Ich habe immer gedacht, dass dies nicht nur daran liegt, dass die Parameter auf den Stack geschoben und dann vom Stack entfernt werden müssen, sobald die Funktion zurückkehrt, sondern auch daran, dass der Funktionsaufruf selbst den Kontext der CPU bewahren muss, was mehr Stack-Nutzung bedeutet.

Aber vorausgesetzt, man kennt die Antwort auf die Frage mit der Überschrift, sollte es möglich sein, den Aufwand, den die Funktion verwendet, um sich selbst einzurichten (Push / Pop / Erhaltung des Kontexts usw.), in Bezug auf eine äquivalente Anzahl direkter Speicherzugriffe zu quantifizieren. Daher die überschriebene Frage.


(Bearbeiten: Klarstellung: near oben verwendet ist im Gegensatz zu far in dem Segmentiertes Speichermodell der 16-Bit-x86-Architektur.)

  • Wow. Ich bin ein Entdecker. Ich habe gerade eine gute Nicht-n00b-Frage auf StackOverflow gefunden. Ich feiere meine Erkundung mit Champagner und einer positiven Bewertung!

    Benutzer529758

    7. Oktober 2012 um 6:11 Uhr


  • Ich habe die Dekrement-/Inkrement-Operationen von Push/Pop-Aufrufen auf ESP immer als Overhead im Vergleich zu mov angesehen … aber ich denke, es sollte noch viel mehr dahinterstecken.

    – loxxy

    7. Oktober 2012 um 6:30 Uhr


  • Am Beispiel von x86 haben die 16-Bit-Compiler normalerweise alle Parameter auf den Stack geschoben, aufgerufen, einen Stack-Frame erstellt, ausgeführt, den Stack-Frame entfernt und zurückgegeben. Für die 32- und 64-Bit-Compiler werden die ersten paar Parameter in Registern übergeben, der Aufruf erfolgt, der Stapelrahmen kann erstellt/entfernt werden oder nicht. Das Einzige, woran sich der Compiler anpassen muss, ist die Laufzeitumgebung: Was im Inneren passiert, hängt von der Magie des Compilers ab, und einige Compiler sind wirklich fantastisch.

    – Olof Forshell

    7. Oktober 2012 um 7:35 Uhr

  • @AKE: Ja, mov [bx], ax wird kürzer sein als mov [0x1234], ax.

    – Alexey Frunze

    7. Oktober 2012 um 7:48 Uhr

  • Es kann schneller sein oder auch nicht. Es kann dasselbe sein, wenn es alleine ausgeführt wird (was ziemlich schwierig ist, oder? :)), aber es kann je nach den umgebenden Anweisungen schneller sein. Was ist, wenn dieses einzelne Byte ausreicht, um einen Cache-Miss zu verursachen?

    – Alexey Frunze

    7. Oktober 2012 um 8:05 Uhr

  • @AKE Das hättest du klären sollen. Einige haben nie für 16-Bit-DOS programmiert und hätten keine Ahnung, was nah oder fern bedeuten könnte. Ich habe mich entschieden, hier keine Annahmen zu treffen. Es kann eine Strafe für die Verwendung eines Segmentüberschreibungspräfixes geben oder nicht. Die CPU speichert in sich selbst genügend Informationen über die Segmentdeskriptoren für die Segmente, auf die cs, ds, es, fs, gs, ss zeigen, sodass es möglicherweise keinen Unterschied gibt, wenn das Segmentregister bereits mit dem richtigen Wert geladen ist.

    – Alexey Frunze

    7. Oktober 2012 um 8:10 Uhr

  • Auf dem x86-nahen Speicher wird über die Standardsegmentregister cs für die Ausführung, ds für Daten und ss für den Stack auf den Speicher zugegriffen. Einige Anweisungen verwenden es auch als Standardregister. Jedes Mal, wenn ein Code mit einem expliziten (Abrufen von Daten aus dem Speicher! = Standardspeicher mit einer Segmentregisterüberschreibung) oder einem impliziten Segmentregister (Far Calls) zugreift, arbeiten Sie weit. Zusammenfassend lässt sich sagen, dass Near Intra-Segment und Far Inter-Segment ist.

    – Olof Forshell

    7. Oktober 2012 um 8:13 Uhr


1373420cookie-checkKosten von Push vs. Mov (Stack vs. Near Memory) und der Overhead von Funktionsaufrufen

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

Privacy policy