FreeBSD vs. Linux: Leistung der Kernel-Aufrufkonventionen

FreeBSD vs. Linux: Leistung der Kernel-Aufrufkonventionen

Ausint80h.org, das Tutorial zur FreeBSD-Assemblersprache

[Die Linux Calling]-Konvention hat gegenüber der Unix-Methode einen großen Nachteil, zumindest was die Assembler-Programmierung betrifft: Bei jedem Kernel-Aufruf müssen Sie die Register pushen und später wieder poppen. Dadurch wird Ihr Code umfangreicher und langsamer.

Weiter heißt es, dass FreeBSD sowohl die Linux-Konvention als auch die "Unix-Konvention" unterstützt.

Wenn Sie speziell für FreeBSD codieren, sollten Sie immer die Unix-Konvention verwenden: Es ist schneller, Sie können globale Variablen in Registern speichern, Sie müssen die ausführbare Datei nicht branden und Sie erzwingen auf dem Zielsystem nicht die Installation des Linux-Emulationspakets.

Es erscheint mir seltsam, dass der Linux-Weg sperriger und langsamer ist. Es scheint, als gäbe es zwei Möglichkeiten,

  • Speichern Sie nur die Register, die Sie unbedingt aufbewahren müssen. Diese sind entweder
    • die flüchtigen Register, die durch den Systemaufruf überschrieben werden können (soweit ich weiß ecx)
    • oder die Register, die benötigt werden, um die entsprechenden Argumente an den Kernel zu senden, um das auszuführen syscall(das können eax, ecx, edx, esi, , edi, sein ebp).
  • Speichern Sie 100 % der Argumente für den Kernel auf dem Stapel.

Es scheint, als wäre FreeBSD dasam schlimmstenFallbeispiel der Linux-Konvention. Was übersehe ich? Inwiefern ist die FreeBSD-Konvention (die sie den „Unix-Weg“ nennen) weniger sperrig und schneller?

Antwort1

Meiner Meinung nach läuft es hier wirklich auf die Meinung des Autors hinaus.

In der FreeBSD-Konvention („Unix“) legen Sie die Argumente auf dem Stapel ab, geben die Systemaufrufnummer in an EAXund rufen den Interrupt 0x80 auf (mit einem zusätzlichen Operanden auf dem Stapel, da dieser von einer separaten Funktion aufgerufen werden soll).

In der Linux i386-Konvention platzieren Sie die Argumente in den entsprechenden Registern und rufen den Interrupt 0x80 auf.

Das Argument „sperrig/langsam“ kommt vermutlich daher, dass mit der Linux-Konvention dieAnrufermuss sich mit der Verwendung von Registern befassen. Wenn der Systemaufruf Argumente in Registern benötigt, die Werte enthalten, die für den Anrufer von Bedeutung sind, muss er diese beibehalten, was zu zusätzlichem Arbeitsaufwand führt;siehe dieses Beispiel aus der C-Bibliothek. In diesem Beispiel benötigt der Systemaufruf Werte in EAX, EBX, EDX, EDI und ESI; der Aufrufer kümmert sich aber nur um die Erhaltung von EBX, EDI und ESI, also legt er nur diese auf den Stapel. Der allgemeine Fall istum einiges komplexer(das ist aber auch das Ergebnis der Arbeit mit einer Mischung aus C und Assemblersprache und dem Versuch, in allen Fällen optimalen Code zu generieren), beim Schreiben in Assemblersprache, was der Zweck der Site ist, auf die Sie sich beziehen, wäre das jedoch kein so großes Problem.

Mir scheint, es sind sechseinhalb Dutzend: In der FreeBSD-Konvention pushen Sie in allen Fällen auf den Stack, in der Linux-Konvention pushen Sie auf den Stack (oder woanders hin), je nachdem, was Sie rund um die Aufrufsite tun. Man könnte argumentieren, dass die Linux-Konvention schnelleren Code ermöglicht, da Sie alle Ihre Berechnungen in Registern durchführen können... Wieraubenweist jedoch darauf hin, dass unter Linux die Register letztlich dennoch gepusht werden (um die struct pt_regsInstanz zu erstellen, die zum Bereitstellen der Argumente für die C-Funktionen verwendet wird, die die Systemaufrufe verarbeiten), sodass die Gesamtkosten auf der Linux-Seite höher sind als auf der FreeBSD-Seite.

In jedem Fall erscheint es angesichts der Kosten für die Ausführung des Systemaufrufs selbst ziemlich pedantisch, über die Leistung zu streiten, wenn man über stapel- oder registerbasierten Code rund um einen Systemaufruf spricht. Jeder eingesparte Zyklus ist natürlich absolut gesehen gut, aber die relative Verbesserung wird gering sein.

verwandte Informationen