Benvenuto! Per postare e godere delle funzionalità del forum registrati, occorrono pochi secondi ed è gratis!

Piccolo Dubbio

Iscritto
Messaggi: 270
Discussioni: 40
Registrato: 10-2013
Mix: 0
Salve a tutti Happywide
Spesso mi imbatto in roba tipo :

Codice:
void __stdcall funzione()
oppure
Codice:
void __cdecl funzione()

avete già capito Tounge , il mio dubbio riguarda __stdcall e __cdecl
ho letto vari articoli su questi , ma non sono riuscito a capire.
C'è qualche buon samaritano così buono da spiegarmi? ( Asd )

28/10/2013, 1:24
#1
Cerca
(Questo messaggio è stato modificato l'ultima volta il: 28/10/2013, 2:25 da digger.)

Il criceto mannaro
Messaggi: 3,536
Discussioni: 201
Registrato: 03-2011
Mix: 3,737
la differenza è molto semplice, ma devi avere già chiaro in testa come funziona a livello assembly il passaggio di parametri nella chiamata a funzioni.

In generale, sia con chiamate stdcall che cdecl quando chiami una funzione e gli vuoi passare un parametro, quello che fai è "pushare" quel parametro sullo stack, quindi chiami la funzione, all'interno della funzione il parametro è ancora disponibile sullo stack e da li viene prelevato per svolgere i compiti della funzione.

La differenza tra i due consiste in CHI si deve preoccupare di sistemare lo stack dopo che finisce l'esecuzione della funzione e si ritorna al chiamante.

cdecl: è la funzione, all'interno del proprio codice, che si preoccupa di sistemare lo stack togliendo i parametri pushati dal chiamante prima dell'esecuzione della funzione

stdcall: è il chiamante che deve preoccuparsi di togliere dallo stack i parametri una volta tornati dalla funzione

Il modo migliore di vederlo comunque è se ti scrivi un piccolissimo programma in C dove nel main chiami 2 funzioni, una con cdecl e una con stdcall passando ad entrambe un parametro.
Poi vai a debuggare con OllyDbg il tuo programmino e allora vedi esattamente quello che sto dicendo.

Ad esempio:
    C++ Programming
  1. int _stdcall funz1(int val)
  2. {
  3. return (val*2);
  4. }
  5.  
  6. int _cdecl funz2(int val)
  7. {
  8. return (val*3);
  9. }
  10.  
  11. int main(int argc, char* argv[])
  12. {
  13. int res = funz1(10);
  14. int res2 = funz2(res);
  15. return res2;
  16. }



Se andiamo a vedere con Olly troviamo questo:

funz1 (cdecl):
    ASM Programming
  1. PUSH EBP
  2. MOV EBP,ESP
  3. MOV EAX,DWORD PTR SS:[ARG.1]
  4. SHL EAX,1
  5. POP EBP
  6. RETN 4 <--- la funz. ripulisce lo stack togliendo una DWORD, il parametro



funz2 (stdcall):
    ASM Programming
  1. PUSH EBP
  2. MOV EBP,ESP
  3. MOV EAX,DWORD PTR SS:[ARG.1]
  4. IMUL EAX,EAX,3
  5. POP EBP
  6. RETN <---- qui NON è la funzione a ripulire



E vediamo il codice nella funzione main, ovvero il chiamante:
(ho lasciato solo la parte che ci interessa)

chiamata a funz1 (cdecl)
    ASM Programming
  1. PUSH 0A <-- pushiamo il parametro sullo stack
  2. CALL funz1 <-- dentro la funzione pulisce lo stack



chiamata a funz2 (sdcall)
    ASM Programming
  1. PUSH EAX <-- pushiamo il parametro sullo stack
  2. CALL funz2 <-- la funzione dentro NON pulisce lo stack quindi...
  3. ADD ESP,4 <--- deve farlo il chiamante, togliendo una DWORD dallo stack



Finchè sei tu che chiami le tue funzioni nel tuo programma non ha molta imporanza che la chiamata sia cdecl (il default) o che sia stdcall.
L'importanza nasce nel momento in cui chiami funzioni che si trovano in altre librerie o comunque esterne al tuo programma.
Un esempio sono le API di windows, che solitamente usano la chiamata stdcall.
Il problema di chiamare una funzione con la convenzione sbagliata è di ottenere un crash sicuro perchè quello che succede è che lo stack viene corrotto.


digger
28/10/2013, 2:19
#2
Cerca
(Questo messaggio è stato modificato l'ultima volta il: 28/10/2013, 11:30 da Cyanstack.)

Iscritto
Messaggi: 270
Discussioni: 40
Registrato: 10-2013
Mix: 0
Grazie mille digger, solo un altra domanda, cosa cambia in __fastcall? Happywide

28/10/2013, 11:30
#3
Cerca

Il criceto mannaro
Messaggi: 3,536
Discussioni: 201
Registrato: 03-2011
Mix: 3,737
fastcall è un puttanaio perchè consiste nel passare uno o piu parametri usando alcuni dei registri, peccato che questa convenzione di chiamata ogni compilatore se l'è implementata a modo suo e non ci sia uno standard univoco


digger
29/10/2013, 0:25
#4
Cerca


Discussioni simili
Discussione Autore Risposte Letto Ultimo messaggio
  Dubbio float Cyanstack 4 1,790 20/11/2013, 12:58
Ultimo messaggio: Cyanstack



Utenti che stanno guardando questa discussione: 1 Ospite(i)