Offenbar behandeln Compiler nach dem Stand der Technik Argumente, die vom Stack als schreibgeschützt übergeben werden. Beachten Sie, dass der Aufrufer in der x86-Aufrufkonvention Argumente auf den Stack überträgt und der Aufgerufene die Argumente im Stack verwendet. Zum Beispiel kann die folgende C-Code:x86-Aufrufkonvention: Sollen Argumente, die vom Stack übergeben werden, schreibgeschützt sein?
extern int goo(int *x);
int foo(int x, int y) {
goo(&x);
return x;
}
wird durch clang -O3 -c g.c -S -m32
in OS X 10.10 in kompilierte:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 10
.globl _foo
.align 4, 0x90
_foo: ## @foo
## BB#0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 8(%ebp), %eax
movl %eax, -4(%ebp)
leal -4(%ebp), %eax
movl %eax, (%esp)
calll _goo
movl -4(%ebp), %eax
addl $8, %esp
popl %ebp
retl
.subsections_via_symbols
Hier wird der Parameter x
(8(%ebp)
) zuerst in %eax
geladen; und dann in -4(%ebp)
gespeichert; und die Adresse -4(%ebp)
wird in %eax
gespeichert; und %eax
wird an die Funktion goo
übergeben.
Ich frage mich, warum Clang-Code generiert, der den Wert in 8(%ebp)
zu -4(%ebp)
gespeichert kopieren, anstatt nur die Adresse vorbei 8(%ebp)
an die Funktion goo
. Es würde Speichervorgänge speichern und zu einer besseren Leistung führen. Ich habe auch in GCC ein ähnliches Verhalten beobachtet (unter OS X). Um genauer zu sein, frage ich mich, warum Compiler erzeugt nicht:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 10
.globl _foo
.align 4, 0x90
_foo: ## @foo
## BB#0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
leal 8(%ebp), %eax
movl %eax, (%esp)
calll _goo
movl 8(%ebp), %eax
addl $8, %esp
popl %ebp
retl
.subsections_via_symbols
ich für Dokumente durchsucht, wenn die x86-Aufrufkonvention verlangt, um die übergebenen Argumente nur gelesen werden, aber ich kann nichts zu diesem Thema finden. Hat jemand darüber nachgedacht?
Sie haben hier einen guten Punkt! '8 (% ebp)' ist im Stapelrahmen des Aufrufers, aber es ist Speicherplatz, der speziell für die Übergabe von Argumenten an 'foo' zugewiesen wurde. Wird der Aufrufer diesen Speicherplatz für seine eigenen Zwecke nutzen * nachdem * 'foo' zurückkehrt, anstatt ihn nur durch Anpassen des Stack-Zeigers zu zerstören? Wenn dies der Fall ist, ist es notwendig, den Wert in den Stapelrahmen von "foo" zu kopieren. Wenn nicht, könnte es sicher sein, dass 'foo' das Leerzeichen im Stapelrahmen des Aufrufers" borgt ", anstatt zu kopieren. Also, um zu wissen, ob deine Idee gut ist oder nicht, musst du sehen, wie der Code für 'foo's * caller * aussieht. –
@AlexD Vielen Dank für Ihren Kommentar! Da 'foo' durch eine beliebige Funktion aufgerufen werden kann, denke ich, dass es sich um eine Frage zum Aufrufen von Konventionen handelt und nicht um einen spezifischen Kontext, in dem' foo' aufgerufen wird. –
Das ist eine interessante Frage. Ich fand [diese andere Frage] (http://stackoverflow.com/questions/1684682/c-calling-conventions-and-passed-arguments?rq=1), die behauptet, dass gcc -O2 tatsächlich das gestoßene stack Argument des Anrufers änderte . – JS1