Domanda

Ho creato questo codice assembly semplice e inutile (Y86) per vedere se capisco tutto ciò che accade nello stack quando vengono utilizzate le istruzioni call, pushl, popl e ret.

Come ho detto, questo codice è inutile, è solo a scopo di test / apprendimento. Tuttavia, tutti gli indirizzi di memoria sono stati calcolati correttamente (si spera) e non sono casuali.

Il codice assembly è il seguente:

     | .pos 0
0x00 |   irmovl Stack, %esp
0x06 |   rrmovl %esp, %ebp
0x08 |   irmovl $5, %eax
0x0E |   call func
0x13 |   halt
0x14 | func:
0x14 |   pushl %ebp
0x16 |   rrmovl %esp, %ebp
0x18 |   pushl %eax
0x1A |   popl %eax
0x1C |   popl %ebp
0x1E |   ret
     | .pos 50
0x32 | Stack: .long 0

Quello che segue è il mio meglio per disegnare una pila e spiegare cosa fa ogni passaggio (istruzione) con la pila. Nota che ho usato SP e BP per riferirmi rispettivamente a% esp e% ebp perché sono usati molto e ne facilitano la lettura.

Quello che voglio sapere è se ho tutto sopra a destra o se ho perso qualcosa. Sentiti libero di copiare / incollare quello che vuoi e correggere alcuni passaggi nella tua risposta.

Nota anche che la mia comprensione di questo è molto importante, ho un esame lunedì per il quale devo essere preparato e vorrei la migliore risposta che puoi darmi. A seconda delle tue risposte, potrei (o meno) avere alcune domande correlate che dovremo occuparci della sezione commenti.

- INSTRUCTION: irmovl Stack, %esp
- INSTRUCTION: rrmovl %esp, %ebp
  1) Point %esp (SP) and %ebp (BP) to Stack

     |  ...  |
0x2E |-------|
     |       |
0x32 |-------| <--- SP & BP

- INSTRUCTION: irmovl $5, %eax
  1) Sets %eax = 5

- INSTRUCTION: call func
  1) Decrements SP by 4 (0x32 -> 0x2E)
  2) Saves return address (0x13) in memory location pointed by SP (0x2E)
  3) Jumps to "func" memory address (0x14)

     |  ...  |
0x2A |-------|
     | 0x13  |
0x2E |-------| <--- SP
     |       |
0x32 |-------| <--- BP

- INSTRUCTION: pushl %ebp
  1) Decrements SP by 4 (0x2E -> 0x2A)
  2) Saves BP value (0x32) in memory location pointed by SP (0x2A)

     |  ...  |
0x26 |-------|
     | 0x32  |
0x2A |-------| <--- SP
     | 0x13  |
0x2E |-------|
     |       |
0x32 |-------| <--- BP

- INSTRUCTION: rrmovl %esp, %ebp
  1) Sets BP = SP (0x32 -> 0x2A)

     |  ...  |
0x26 |-------|
     | 0x32  |
0x2A |-------| <--- SP & BP
     | 0x13  |
0x2E |-------|
     |       |
0x32 |-------|

- INSTRUCTION: pushl %eax
  1) Decrements SP by 4 (0x2A -> 0x26)
  2) Saves %eax value (5) in memory location pointed by SP (0x26)

     |  ...  |
0x22 |-------|
     |   5   |
0x26 |-------| <--- SP
     | 0x32  |
0x2A |-------| <--- BP
     | 0x13  |
0x2E |-------|
     |       |
0x32 |-------|

- INSTRUCTION: popl %eax
  1) Saves value (5) in memory location pointed by SP (0x26) in %eax
  2) Increments SP by 4 (0x26 -> 0x2A)

     |  ...  |
0x22 |-------|
     |   5   |
0x26 |-------|
     | 0x32  |
0x2A |-------| <--- SP & BP
     | 0x13  |
0x2E |-------|
     |       |
0x32 |-------|

- INSTRUCTION: popl %ebp
  1) Saves value (0x32) in memory location pointed by SP (0x2A) in %ebp
  2) Increments SP by 4 (0x2A -> 0x2E)

     |  ...  |
0x22 |-------|
     |   5   |
0x26 |-------|
     | 0x32  |
0x2A |-------|
     | 0x13  |
0x2E |-------| <--- SP
     |       |
0x32 |-------| <--- BP

- INSTRUCTION: ret
  1) Jumps to memory address (0x13) in memory location pointed by SP (0x2E)
  2) Increments SP by 4 (0x2E -> 0x32)
È stato utile?

Soluzione

Per quanto ne so, hai capito bene.

Un punto minore che posso sottolineare è che probabilmente è più intuitivo scrivere gli indirizzi sopra il valore in quegli indirizzi. Cioè:

0x2E |-------|
     | 0x13  |
0x32 |-------|

Il motivo è che l'intervallo di indirizzi copre il valore ( 0x2E , 0x2F , 0x30 , 0x31 ) va all'indirizzo successivo 0x32 .

Naturalmente, potresti voler usare la notazione prevista dal tuo insegnante durante l'esame.

Altri suggerimenti

Hai capito bene.

Quello che stai facendo è esercitare una chiamata di funzione usando convenzioni standard di chiamata del chiamante, creando un frame per la chiamata. Quindi esegui un semplice push e pop di un registro prima di tornare al chiamante. Questo è totalmente corretto e la tua comprensione è corretta (vedi http: //y86tutoring.wordpress .com / 2012/10/31 / funzionamento-pile / per dettagli)

Sembra tutto a posto. L'unico suggerimento è che non è necessario definire una parola 0x0000 nello stack. La semplice definizione dell'etichetta Stack lo avrebbe fatto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top