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)
rfgamaral
  • 16,546
  • 57
  • 163
  • 275

2 Answers2

2

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
  • 13,619
  • 5
  • 32
  • 32
  • 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] ? – rfgamaral Jun 21 '09 at 12:14
  • 2
    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 Jun 21 '09 at 17:40
0

You got it right.

What you are doing is exercising a function call using standard caller-callee conventions, creating a frame for the callee. You then perform a simple push and pop of a register before returning to the caller. This is totally correct and your understanding is correct (see http://y86tutoring.wordpress.com/2012/10/31/functioning-stacks/ for details)

Everything looks good. Only suggestion is that you do not need to define an 0x0000 word on the stack. Simply defining the Stack label would have done it.

pajacobsen
  • 44
  • 2
  • Welcome to Stack Overflow! Thanks for posting your answer! Please be sure to read the [FAQ on Self-Promotion](http://stackoverflow.com/faq#promotion) carefully. Also note that it is *required* that you post a disclaimer every time you link to your own site/product. – Andrew Barber Nov 08 '12 at 04:13