Reputation: 459
So far I've been learning to write some x86_64 assembly. I read that you can subtract the RSP to grow the stack downwards and allocate space, so I wrote the following code:
push %rbp
movq %rsp, %rbp
subq $16, %rsp
movq $200, -8(%rsp)
movq $300, -16(%rsp)
popq %rbp
retq
From my understanding, this will make a function where it sets up a the stack frame, then it allocates 16 bytes on the stack and sets the values at -8 and -16 to 200 and 300 respectively.
However, when I run this with gcc, I get a segmentation fault. Though if I remove the sub
part of the program, it works perfectly. I assume I've misunderstood something, so what is actually going on here?
Upvotes: 0
Views: 1292
Reputation: 365991
As Jester says, the problem is that when you pop %rbp
/ ret
, the stack pointer is pointing somewhere else, so you're not getting the old %rbp
and the return address. (You never write to the locations you pop, due to another potential-bug, so I can't tell you exactly which invalid address you ret
to.)
If you make a stack frame at all (mov %rsp, %rbp
), then it's normal to use offsets relative to %rbp
. Fun fact: movq $200, -8(%rbp)
takes one byte less machine code than the equivalent movq $200, 8(%rsp)
. (Using %rsp
as the base register unfortunately always requires a SIB byte to encode the effective address.)
Using %rbp
also means the expression that references any given stack address doesn't change even if you're pushing/popping stuff (common in 32bit code with a stack-args ABI, but rare in 64bit code. 64bit gcc switched to -fomit-frame-pointer before 32bit).
Your movq $200, -8(%rsp)
uses space outside the 16B you reserved. This is the "other potential bug" I referred to earlier.
Using up to 128B below the current %rsp
is actually NOT an error in the SysV ABI: asynchronous events (signal handlers and so on) avoid clobbering the red zone, so small functions that don't call any other functions can avoid spending instructions modifying %rsp
to reserve space. x86-64 has 15 general-purpose registers (not counting the stack pointer), so small and medium size functions typically don't need to use the stack other than to save/restore call-preserved registers. Or for local arrays.
The Windows ABI doesn't use a red zone, so memory below %rsp
can potentially be stepped on, even when you don't do it yourself with a call
.
See the x86 tag wiki for links about calling conventions / ABIs.
Upvotes: 5