[FASM] Verständnisproblem "invoke printf" und Stackverwaltung
-
Hallo,
ich habe begonnen, mich etwas mit Assemblerprogrammierung zu beschäftigen. Dabei bin ich auf folgendes Problem gestoßen. Mein Miniprogramm soll drei mal "Hallo Welt" ausgeben, und dann auf eine Eingabe warten. Aber es läuft in einer Endlosschleife. Es dürfte mit den Befehlen PUSH/POP ECX zusammenhängen, da alternativ das Sichern und Wiederherstellen über mit MOV-Befehl funktioniert. Leider erkenne ich die Ursache dafür nicht. Ich dachte beim Aufruf von PRINTF mit INVOKE wird im Anschluss automatisch der Stack gesäubert, so das der Stackpointer wieder auf die richtige Stelle zeigt, und somit das ECX-Register mit dem richtigen Wert (aktueller Zählerstand) geladen wird.
format PE CONSOLE 4.0 entry start Include 'win32ax.inc' ;------------------------------------------------- section '.code' code readable executable ;------------------------------------------------- start: mov ecx,3 ;zaehler loop01: push ecx ; mov [save],ecx invoke printf, string pop ecx ; mov ecx,[save] dec ecx jnz loop01 invoke getchar invoke ExitProcess,0 ;------------------------------------------------- section '.data' data readable writeable ;------------------------------------------------- string db 'Hallo Welt!',13,10,0 save dd '0' ;------------------------------------------------- section '.idata' import data readable writeable ;------------------------------------------------- library kernel32,'kernel32.dll',\ msvcrt,'msvcrt.dll' import kernel32,\ ExitProcess,'ExitProcess' import msvcrt,\ getchar,'getchar',\ printf,'printf'
Ich würde mich freuen, wenn mir jemand diesen Sachverhalt erklären könnte.
Viele Grüße
Hardi
-
invoke -> ccall/cinvoke
Auserdem: Stimmt das name mangling? ***_*printf?
-
fasmer schrieb:
Auserdem: Stimmt das name mangling? ***_*printf?
Ja, das Mangling stimmt. Die Sache mit dem Unterstrich ("Decoration") braucht man nur, wenn man mit LIB-Dateien arbeitet. Der Linker von FASM greift aber direkt auf die jeweilige DLL zu.
KORREKTUR: Er greift gar nicht zu, sondern trägt DLL- und Funktionsnamen ohne weitere Prüfung in die ausführbare EXE-Datei ein. Einen Fehler gibts also schlimmstenfalls erst zur Laufzeit des Programms (dann aber sicher).
viele grüße
ralph
-
Das macht IDA aus dem Codeteil:
.code:00401000 public start .code:00401000 start: .code:00401000 mov ecx, 3 .code:00401005 .code:00401005 loc_401005: ; CODE XREF: .code:00401013j .code:00401005 push ecx .code:00401006 push offset aHalloWelt ; "Hallo Welt!\r\n" .code:0040100B call ds:printf .code:00401011 pop ecx .code:00401012 dec ecx .code:00401013 jnz short loc_401005 .code:00401015 call ds:getchar .code:0040101B push 0 .code:0040101D call ds:ExitProcess .code:0040101D ; --------------------------------------------------------------------------- .code:00401023 db 0 .code:00401024 align 200h .code:00401024 _code ends
...sieht doch gleich viel eindeutiger aus. ^^
-
Hallo,
danke für die Antworten.
Ersetze ich "invoke printf,..." durch "cinvoke printf, ..." oder "ccall [printf],..." läuft das Programm wie gewünscht.
@nachtfeuer,
ein Bild sagt mehr als tausend Worte - danke.In der englischen Wikipedia fand ich unter "x86 calling conventions/Callee clean-up" folgenden Text: "... When the callee cleans the arguments from the stack it needs to be known at compile time how many bytes the stack needs to be adjusted. Therefore, these calling conventions are not compatible with variable argument lists, e.g. printf()..."
Viele Grüße
hardi