views:

343

answers:

1

I've created this simple and pointless assembly (Y86) code to see if I understand everything that's happening in the stack when the instructions call, pushl, popl and ret are used.

Like I said, this code is pointless, it's just for testing/learning purposes. Although, all memory addresses were correctly (hopeful) calculated and are not random.

The assembly code is the following:

     | .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

The following is my best to draw a stack and explain what each step (instruction) does with the stack. Please note that I used SP and BP to refer to %esp and %ebp respectively cause they are used a lot and makes it easier to read.

What I want to know is if I got everything above right or if I missed anything. Please feel free to copy/paste whatever you want and fix some step(s) in your answer.

Also note that my understanding of this is very important, I have an exam Monday for which I need to be prepared and I would like the best answer you can give me. Depending on your answers, I might (or not) have some related questions that we shall take care in the comments section.

- 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)
+2  A: 

As far as I can tell you've got it all right.

One minor point I can make is that it is probably more intuitive to write the addresses above the value at those addresses. That is:

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

The reason being that the address range covering the value (0x2E,0x2F,0x30,0x31) goes towards the next address 0x32.

Of course, you might want to use the notation expected by your teacher when doing the exam.

mweerden
Actually I don't know the "notation" used :/ In that example, I always though that 0x13 was going to be saved in [0x2E, 0x2D, 0x2C, 0x2B], it just made more sense to me. This would lead me to another question if someone answered me that "you got it all right": Why the hell do we leave an empty block in [0x32, 0x31, 0x30, 0x2F] ?
Nazgulled
That explains why you illustrated it as you did, but note that a stack only /grows/ downwards (i.e. a new element is below the last) which does not mean the elements themselves are also stored backwards. A (4-byte) element at x is always stored at x,x+1,x+2,x+3. Reversing this for the stack would also mean that you cannot easily use addresses from the stack in "normal" code. Regarding the empty block at the bottom of the stack: this is a consequence of the fact that pushl v stores v at %esp-4 instead of %esp. Of course, in many cases you can avoid this by changing the initial value of %esp.
mweerden