0

Here is my stack frame and corresponding registers(imagine rectangular boxes):

<+80 through +120> = unused
<+48 through +80> = unused
<+40 through +48> = rcx
<+32 through +40> = unused
<+24 through +32> = rax
<+16 through +24> = rdx
<+8 through +16> = rsi
< 0 through +8> = rdi
(stack pointer is at zero)

Then the following commands are applied:

mov 88(%rsp), % rax
add 80(%rsp), % rax
add 96(%rsp), % rax
add 104(%rsp), % rax
add $120, %rsp

I know that the last command will move the stack pointer back to 120. However, the other four don't make much sense. In all cases the return value (rax) will either have a new value (mov) or have its value added to (add). However, my teacher says that the stack frame will change. Can anyone show what will change (other than stack pointer and rax being also moved to +88 to +96).

zx485
  • 28,498
  • 28
  • 50
  • 59
sam_18
  • 1
  • 2
  • This is not related to C. The rest is unclear. Note the C standard does not require using a stack (just in case there actually **is** a connection to C you did not mention). And things are not that simple since compilers became smarter - in the 80ies and 90ies. – too honest for this site Feb 24 '16 at 16:19
  • I added a new tag so that it's propagated in the right channels. – zx485 Feb 24 '16 at 16:27
  • Assuming AT&T syntax, you are correct - only the value of `rax` changes, except for when the stack frame is removed with the add to `rsp`. – 500 - Internal Server Error Feb 24 '16 at 17:55

1 Answers1

0

AT&T syntax (usually identifiable by %) generally follows this format:

operation src, dest

which has the effect of doing:

dest = dest operation src

So for instance:

add %rdx, %rax

means add the contents of register rdx to register rax and store the result in register rax (ie: rax += rdx).

Personally, I tend to find Intel syntax (what you will find in the instruction set architecture specifications) a bit easier to read:

operation dest, src

So for instance, the same example as above would be written as add rax, rdx.

Therefore, let me first rewrite your code into Intel assembly:

mov rax, QWORD PTR [rsp + 88]
add rax, QWORD PTR [rsp + 80]
add rax, QWORD PTR [rsp + 96]
add rax, QWORD PTR [rsp + 104]
add rsp, 120

The first line is simply a quadword (64-bit) load from rsp + 88. The next few lines add various values to the value that we just loaded. The final line increases the stack pointer by 120 bytes. In C-like pseudocode, that looks like this:

// Given:
//    byte *stack;
//    uint64_t rax;
rax = *(u64 *) &stack[88];
rax += *(u64 *) &stack[90];
rax += *(u64 *) &stack[96];
rax += *(u64 *) &stack[104];
stack += 120;

So at the end of the block, the stack pointer should have been increased by 120 bytes (thus decreasing the stack by 120 bytes, because the stack grows downward on x86_64). If we reorder what we have so far and combine common operations, we get this:

u64 *nums = (u64 *) &stack[80];
// sizeof (u64) = 8
// 80, 88, 96, 104
rax = nums[0] + nums[1] + nums[2] + nums[3];
stack + 120;

TL;DR: the code presented doesn't move anything. It takes the sum of four 64-bit integers from the stack and places it into register rax, after which it decreases the stack pointer (increases rsp) by 120 bytes.

Community
  • 1
  • 1
haneefmubarak
  • 1,911
  • 1
  • 21
  • 32