Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    [assembly] esp e costanti numeriche

    ciao a tutti!

    sono alle prime armi dell'assembly e volevo vedere come era un programma in c trasformato in linguaggio assembly.
    ho digitato un po di codice e mandato in esecuzione con il debug e GDB.

    arrivato qui:

    int a= 262144;

    la istruzione assembly equivalente dovrebbe essere questa:

    0x004013be <+14>: mov DWORD PTR [esp+0x18],0x40000

    ptr è usato per le conversioni e in questo caso la conversione è a 32 bit.
    non ho capito invece perchè bisogna mettere in esp( stack pointer ) + 0x18 il valore 262144?

    un altra cosa: 262144 è rappresentato in forma esadecimale ma quello che non mi è familiare è lo 0x davanti al valore( mi ricordavo che si utilizzava per gli indirizzi )... ma se con le costanti allora si usa questa forma, con gli indirizzi come si fa?

    grazie mille in anticipo

  2. #2
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    1,123
    Puoi postare il codice C che stai utilizzando?
    Tieni anche presente che il compilatore esegue delle ottimizzazioni al codice che scrivi, quindi non è proprio di immediata comprensione se guardi l'assembly.

  3. #3
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,465
    Il valore di 0x18 dipende dalla posizione nello stack della variabile in questione. Considera che nello stack ci stanno anche altre informazioni (ad esempio l'indirizzo di rientro).

    0x viene usato per qualsiasi valore esadecimale costante, anche se è un indirizzo.
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  4. #4
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    1,123
    Rileggendo ora mi sono accorto di aver letto male ieri sera. Io pensavo invece non capissi perchè veniva utilizzato esp, ecco perchè ti avevo chiesto il codice.
    Ad ogni modo concordo con oregon. La variabile che stai utilizzando suppongo quindi sia dichiarata in una funzione.

  5. #5
    Quote Originariamente inviata da maluz1 Visualizza il messaggio
    0x004013be <+14>: mov DWORD PTR [esp+0x18],0x40000

    ptr è usato per le conversioni e in questo caso la conversione è a 32 bit.
    Non è questione di conversioni, DWORD PTR [indirizzo] è la sintassi Intel per dire che l'operando a cui si fa riferimento è una DWORD (32 bit) situata all'indirizzo specificato tra le quadre; essenzialmente è come dereferenziare un puntatore a int.
    non ho capito invece perchè bisogna mettere in esp( stack pointer ) + 0x18 il valore 262144?
    ESP contiene lo stack pointer corrente, ovvero la posizione della cima dello stack; normalmente su x86 lo stack cresce "verso il basso" (ovvero, parte da indirizzi alti e cresce verso indirizzi bassi), per cui all'inizio di ogni funzione troverai una cosa del tipo:
    codice:
    sub esp, 0x20
    dove 0x20 è un valore che cambia a seconda della funzione; questo espande lo stack verso il basso di 0x20 (32) byte, riservando così i byte in questione per le variabili locali. Quindi, nel resto della funzione, per fare riferimento allo spazio così riservato si usano sempre offset positivi rispetto a esp, come nel tuo caso.
    un altra cosa: 262144 è rappresentato in forma esadecimale ma quello che non mi è familiare è lo 0x davanti al valore( mi ricordavo che si utilizzava per gli indirizzi )... ma se con le costanti allora si usa questa forma, con gli indirizzi come si fa?
    Come ti è stato detto, 0x è un generico prefisso per l'esadecimale. In ogni caso, non è particolarmente rilevante il fatto che ti venga mostrato come tale, nell'eseguibile è memorizzato come valore binario "grezzo", è solo una scelta del disassembler mostrartelo in esadecimale o decimale.
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #6
    innanzi tutto grazie mille per le risposte

    vorrei solo accertarmi di una cosa: il programma in c che ho mandato in esecuzione conteneva l'unica funzione necessaria per eseguire il programma, cioè il main. Quindi siccome le prime righe del "disassemblaggio" salvavano l'indirizzo di ritorno ed eventuali parametri devo dedurre che il sistema operativo tratta il main come una funzione da inserire nello stack?

    quando quindi viene chiamata una funzione, prima si salvano i parametri, l'sfp( saved frame pointer ) e l'indirizzo di ritorno nel frame pointer e poi si provvede a sottrarre dal top dello stack lo spazio relativo del frame pointer?

    grazie ancora

  7. #7
    Quote Originariamente inviata da maluz1 Visualizza il messaggio
    innanzi tutto grazie mille per le risposte

    vorrei solo accertarmi di una cosa: il programma in c che ho mandato in esecuzione conteneva l'unica funzione necessaria per eseguire il programma, cioè il main. Quindi siccome le prime righe del "disassemblaggio" salvavano l'indirizzo di ritorno ed eventuali parametri devo dedurre che il sistema operativo tratta il main come una funzione da inserire nello stack?
    Ni. Il sistema operativo normalmente fa riferimento ad un entrypoint specificato negli header del file eseguibile, che credo possa omettere il normale preambolo della funzione; il punto è che il tuo main non è il "vero" main, il compilatore specifica automaticamente come entrypoint una funzione che si occupa di inizializzare le strutture della libreria C, eventualmente recuperare e parsare la linea di comando e alla fine chiamare il tuo main come una normale funzione.
    quando quindi viene chiamata una funzione, prima si salvano i parametri, l'sfp( saved frame pointer ) e l'indirizzo di ritorno nel frame pointer e poi si provvede a sottrarre dal top dello stack lo spazio relativo del frame pointer?
    Sui parametri e i registri, dipende dalla calling convention. I parametri possono essere passati in parte in registri e in parte sullo stack, e la responsabilità della pulizia (pop) dei parametri passati sullo stack può essere della procedura chiamante o di quella chiamata (nel primo caso è possibile avere chiamate a funzioni con numero di parametri variabile, nel secondo si ha risparmio in termini di dimensioni dell'eseguibile dato che il codice di pulizia viene scritto una sola volta in fondo alla procedura invece che a tutti i siti di chiamata).
    L'indirizzo di ritorno su x86 viene salvato automaticamente dall'istruzione CALL, e quindi in genere segue immediatamente il push dei parametri.
    Il saved frame pointer (ovvero il valore generato da PUSH esp) può essere necessario o meno; in genere se la procedura non contiene array allocati sullo stack di dimensione non nota non è necessario - il compilatore sa esattamente di quanto ha spostato esp, e può quindi generare la RET di conseguenza.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    capito, grazie mille MItaly
    solo una cosa: ma il saved frame pointer è quello generato da PUSH EBP, o sbaglio?
    Ultima modifica di maluz1; 05-01-2014 a 15:54

  9. #9
    Sì pardon, ho fatto un attimo confusione; normalmente il prologo è del tipo
    codice:
    push    ebp
    mov ebp, esp
    sub esp, <dimensione variabili locali>
    e alla fine
    codice:
    mov esp, ebp
    pop ebp
    ret
    (nel caso di una funzione cdecl, altrimenti dopo ret ci sarebbe anche un parametro, che indica di spostare esp in modo da ripulire lo stack dai parametri della funzione)

    push ebp salva il frame pointer corrente, che viene quindi cambiato all'esp attuale, facendo sì che ebp punti sempre alla base dello stack frame corrente. In questa maniera, in caso di allocazioni sullo stack non note a compile-time, il compilatore può fare riferimento alle variabili locali riferendosi a [ebp-offset] (dal momento che, facendo allocazioni sullo stack non note a compile-time, esp non è più un punto di riferimento "fissato" per la funzione corrente). Inoltre, i vari valori di ebp pushati sullo stack costituiscono di fatto una lista linkata che consente ad un debugger di risalire facilmente ai vari stack frame.

    D'altra parte, se non si fanno allocazioni sullo stack a runtime e non serve questo aiuto per ricostruire gli stack frame, è possibile in genere segnalare al compilatore di omettere il push ebp (e il corrispondente pop alla fine), liberando un registro altrimenti costantemente occupato (e questo, su un'architettura register-starved come x86, può dare in alcuni casi vantaggi di prestazioni sensibili).
    Amaro C++, il gusto pieno dell'undefined behavior.

  10. #10
    ok grazie ancora per la spiegazione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.