Assembler std-call

Ich habe mir gerade folgenden Eintrag zum Nachlesen bei wikibooks durchgelesen:
x86 Disassembly/Functions and Stack Frames

Allerdings bin ich bei folgendem Eintrag sehr stutzig:
Code:
_MyFunction3:
  push ebp
  mov ebp, esp
  sub esp, 12 ; sizeof(a) + sizeof(b) + sizeof(c)
  ;x = [ebp + 8], y = [ebp + 12], z = [ebp + 16]
  ;a = [ebp - 4] = [esp + 8], b = [ebp - 8] = [esp + 4], c = [ebp - 12] = [esp]
  mov esp, ebp ;WTF?
  pop ebp
  ret 12 ; sizeof(x) + sizeof(y) + sizeof(z)
Nach meiner Meinung wird dort der Stack doppelt abgebaut. Erst bei
Code:
mov esp, ebp
und später nochmal bei
Code:
ret 12
Ich habe dies gerade mit einem selbstgeschriebenem Programm getestet und auf dem Stack fehlen nach der Ausführung tatsächlich 8 Bytes (in meinem Programm habe ich ret 8 geschrieben).
Allerdings scheint der obige Code zu stimmen, da ich ähnliche Beispiele bei google gefunden habe. Normalerweise wird der Code
Code:
mov esp, ebp
pop ebp
durch
Code:
leave
abgekürzt.

Zur Verdeutlichung habe ich folgendes Programm geschrieben:
Code:
.data
disp_string db "%x",13,10,0
wait_string db "%d",0
.data?
_unused dd ?
.code

start:
    push 0DEADBEEFh
    call _MyProc
    pop eax ;sollte eigentlich 0xDEADBEEF sein
    push eax ;nur noch mal zur verdeutlichung pushen
    push offset disp_string 
    call crt_printf     ;hier wird definitiv nicht DEADBEEF angezeigt
    ;========>Daraus folgere ich: Der stack wird korrumpiert. Aber warum?
_exit:
    ;wait
    push offset _unused
    push offset wait_string
    call crt_scanf
    ;exit
    push 0 
    call ExitProcess
    
_MyProc:
    push ebp
    mov ebp, esp
    sub esp, 8 ;2x DWORD lokale variablen
    ;===========>
    ;=====>
    mov esp, ebp
    pop ebp
    ret 8 ;2x DWORD
    
end start
 
Allerdings bin ich bei folgendem Eintrag sehr stutzig:
Code:
_MyFunction3:
  push ebp  ; alter Basepointer gesichert
  mov ebp, esp ;alter ESP Wert wird zum neuen "Basepointer"
  sub esp, 12 ; anlegen der lokalvariablen
 ...
  mov esp, ebp ; EBP == ESP beim Aufruf der Funktion, quasi wiederherstellen des vorhergigen ESP, "freigeben" der lokalen Variablen
  pop ebp ; alter EBP 
  ret 12 ; hier sind die Paparameter gemeint, nicht die lokalen Variablen!
Vielleicht etwas verwirrend, da es sowohl 3 lokale Variablen wie auch 3 Parameter gibt.
RET 12 "räumt" die Parameter weg (wie es sich für eine STDCALL Konvention gehört ;) ). Die lokalen Variablen werden
mit "mov esp, ebp" freigegeben.

Ich habe dies gerade mit einem selbstgeschriebenem Programm getestet und auf dem Stack fehlen nach der Ausführung tatsächlich 8 Bytes (in meinem Programm habe ich ret 8 geschrieben).
Code:
_MyProc:
    push ebp
    mov ebp, esp
    sub esp, 8 ;2x DWORD lokale variablen
    ;===========>
    ;=====>
    mov esp, ebp ; ESP == alter Wert (vor dem anlegen) => hiermit werden die lokalen Variablen freigegeben.
    pop ebp
    ret 8 ; die 4 Bytes des Args freigeben + 4 Bytes "einfach so"
Ja, die Funktion wird mit 1 Parameter aufgerufen (4 Byte), räumt aber am Ende 8 weg. Kein Wunder also, dass da was fehlt ;).
 
Danke für eure Hilfe, aber ich habe noch ein Problem. Ich möchte gerne eine float-Variable mit scanf einlesen und wieder ausgeben. Allerdings funktioniert printf nicht.
Code:
.data
float_display db "%f", 13, 10, 0
float_format db "%f", 0
wait_string db "%d",0
myfloat dd 2.5
.data?
_unused dd ?
.code

start:
    call _MyProc
_exit:
    ;wait
    push offset _unused
    push offset wait_string
    call crt_scanf
    ;exit
    push 0 
    call ExitProcess
    
_MyProc:
    push ebp
    mov ebp, esp
    sub esp, 4 ;float
    ;==========>
    lea eax, DWORD PTR SS:[EBP-4]
    push eax
    push offset float_format
    call crt_scanf 
    mov eax, DWORD PTR SS:[EBP-4] ;float laden
    ;=============>BIS HIER FUNKTIONIERT IM DEBUGGER ALLES!
    push eax
    push offset float_display
    call crt_printf
    ;=====>
    mov esp, ebp
    pop ebp
    ret 0 ;2x DWORD
    
end start

Frage 2: Gibt es auch eine sichere Möglichkeit in Assembler einen String einzulesen? scanf("%s") bietet anscheinend keine Möglichkeit zur Verhinderung eines Buffer Overflows.
 
1.Ich gehe davon aus, dass der korrekte Aufruf so lautet: printf("format", arg)
bei cdecl werden die Argumente in "umgekehrter Reihenfolge" auf den Stack gepusht
Code:
push arg1
push arg2
call
hier:
Code:
push eax
push offset float_display
call crt_printf
haben wir aber sowas als Ergebnis: printf(floatnum, "%f") => also Parameter vertauscht.

2.Die "klassische" Methode wäre zeichenweise einzulesen ;)
Ansonsten gibt es fgets. => fgets(bla, int arg, blub), also mit einem "Begrenzer".

PS: ob man die Funktionen in einer Fremdbibliothek nun in Assembly aufruft oder in C, macht keinen Unterschied ;)
 
Hi!

Zusätzlich solltest du nach dem call von crt_scanf bzw. crt_printf auch noch den Stack bereinigen, da die beiden Funktion die cdecl Aufrufkonvention benutzen.

d.h.

push arg1
push arg2
call crt_scanf ; crt_printf
add esp, 8 ; (2 Argumente * 4)
 
haben wir aber sowas als Ergebnis: printf(floatnum, "%f") => also Parameter vertauscht.
Oh man, war das billig. Ich glaube echt ich sollte bevor ich was poste erst mal nen Kaffee trinken -.-

Zusätzlich solltest du nach dem call von crt_scanf bzw. crt_printf auch noch den Stack bereinigen, da die beiden Funktion die cdecl Aufrufkonvention benutzen.
Das wusste ich noch nicht. Dankeschön

€dit:
Entschuldigung für den Doppelpost. Ich habe den zweiten Post hier eingefügt:
Hallo, ich habe den Fehler doch noch gefunden. Es scheint daran zu liegen, dass printf nur 64-Bit Double akzeptiert. Kann man diesen "Schönheitsfehler" auch noch beheben?
Richtig:
Code:
    fld DWORD PTR SS:[EBP-4] ;lade den float (32-Bit)
    sub esp, 8 ;reserviere platz auf dem stack
    fstp QWORD PTR SS:[ESP] ;speichere den float als 64-Bit-Wert auf dem Stack
    push offset float_display
    call crt_printf
    add esp, 12
Falsch:
Code:
    fld DWORD PTR SS:[EBP-4] ;lade den float
    sub esp, 4 ;reserviere platz auf dem stack
    fstp DWORD PTR SS:[ESP] ;speichere den float als 32-Bit-Wert auf dem Stack
    push offset float_display
    call crt_printf
    add esp, 8
 
Zuletzt bearbeitet:
Zurück
Oben