[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


Anmelden zum Antworten