| Zeile 9: | Zeile 9: | ||
# Rückgabewert | # Rückgabewert | ||
| − | Der '''Funktionsname''' wird beim gcc 4 ( [[C]] ) nicht verändert. Nennt man die Funktion in C ''test'' so heißt diese auch | + | Der '''Funktionsname''' wird beim gcc 4 ([[C]]) nicht verändert. Nennt man die Funktion in C ''test'', so heißt diese auch in der Objektdatei ''test''. |
| − | Beim g++ ( [[C++]] ) ist das schon etwas komplizierter. Bei C++ kann man | + | Beim g++ ( [[C++]] ) ist das schon etwas komplizierter. Bei C++ kann man Namensräume verwenden, und Funktionen überladen, entsprechend wird der Funktionsname aufwändiger codiert: |
Als Beispiel folgende Funktion: | Als Beispiel folgende Funktion: | ||
<cpp>namespace namensraum | <cpp>namespace namensraum | ||
| Zeile 19: | Zeile 19: | ||
} | } | ||
}</cpp> | }</cpp> | ||
| − | + | In der Objektdatei heißt die Funktion nun ''_ZN10namensraum4testEi''. Aufgelöst bedeutet ''N10'', dass ein Namensraum mit 10 Buchstaben folgt (''namensraum''), die ''4'' gibt an, dass nun der Funktionsname mit 4 Buchstaben folgt (''test'') und nach dem ''E'' werden die Datentypen der Parameter aufgelistet – hier ein ''i'' für int.<br/> | |
| − | Aufgelöst bedeutet ''N10'' | + | Dies kann bei anderen Compilern auch anders sein; am besten einfach mal in eine Objektdatei gucken, die mit dem Compiler erstellt wurde, und die Namen, mit den Namen im entsprechenden Quelltext vergleichen.<br /> |
| − | + | Wenn man eine Funktion mit dem Namen ''test'' erstellen möchte, muss man neben dem üblichen Label den Assembler noch anweisen, dass dieses Label auch für andere „Dateien“ sichtbar sein soll. Dazu verwendet man (unter nasm) das Schlüsselwort ''global'': | |
| − | |||
| − | Dies kann bei anderen Compilern auch anders sein; | ||
| − | Wenn man eine Funktion mit dem Namen ''test'' erstellen möchte, muss man neben dem üblichen | ||
<asm>[global test] | <asm>[global test] | ||
test: | test: | ||
ret</asm> | ret</asm> | ||
| − | Damit man diese Funktion jetzt von C aus aufrufen kann, muss man in C angeben, dass irgendwo eine Funktion ist, die ''test'' heißt. Das geht über das Schlüsselwort ''extern'' | + | Damit man diese Funktion jetzt von C aus aufrufen kann, muss man in C angeben, dass irgendwo eine Funktion ist, die ''test'' heißt. Das geht über das Schlüsselwort ''extern'': |
<c>extern int test(int x);</c> | <c>extern int test(int x);</c> | ||
| − | Die '''Argumente''' | + | Die '''Argumente''' werden in C (x86) über den Stack übergeben. Dabei werden die Argumente von rechts nach links auf den Stack gepusht. |
<asm>[global test] | <asm>[global test] | ||
test: | test: | ||
mov eax, [esp+4] | mov eax, [esp+4] | ||
ret</asm> | ret</asm> | ||
| − | Unter ''[esp]'' liegt die Rücksprungadresse, unter ''[esp+4]'' liegt das | + | Unter ''[esp]'' liegt die Rücksprungadresse, unter ''[esp+4]'' liegt das erste Argument. Das zweite Argument würde unter ''[esp+8]'' liegen, usw.. |
| − | Der '''Rückgabewert''' steht in ''eax''. Mann sollte also bei der Verwendung von ''popad'' darauf achten, dass der Rückgabewert nicht | + | Der '''Rückgabewert''' steht in ''eax''. Mann sollte also bei der Verwendung von ''popad'' darauf achten, dass der Rückgabewert nicht verloren geht. Die Beispielfunktion ''test'' würde hier das Argument zurückgeben. |
| − | + | Die Assemblerdatei und die C-Datei müssen nun jeweils zu einer Objektdatei assembliert/kompiliert werden und können dann zusammen gelinkt werden. | |
| − | Ein Aufruf einer C-Funktion (oder der Funktion einer anderen Hochsprache) aus | + | Ein Aufruf einer C-Funktion (oder der Funktion einer anderen Hochsprache) aus Assemblercode geht natürlich auch: |
<c> | <c> | ||
//int a,b,c,r; | //int a,b,c,r; | ||