While coding an assembly code, can I directly use the stack pointer to access function parameters and local variables without saving the base pointer into the stack and setting the new base pointer in the called function?
3 Answers
Yes, in 32 bit and 64 bit assembly you can use the stack pointer with ESP and RSP respectively to access local variables. The reason for using a base stack pointer to access variables is that it's always at a constant location versus the stack pointer which may change location on a push or pop. This would cause you to keep track of how many pushes and pops you do and adjust the variables location accordingly. Look at this for an example: (This is x64)
sub rsp, 16 ; Align stack mov DWORD PTR[rsp], 4 mov DWORD PTR[rsp + 4], 20 mov QWORD PTR[rsp + 8], 175 push 25 ; Push 25 to the stack. push 50 ; Push 8 to the stack. ... Now if later in your code you wanted to access the variables you placed into the stack at the beginning, their locations have changed because of the push statement. A push statement is equivalent to:
sub rsp, 8 mov QWORD PTR[rsp], 45 If you tried to access the variables as you placed them in the stack, you will get the wrong number.
mov rax, QWORD PTR[rsp + 8] ; This is not 175, since you did two pushes ; and moved the stack pointer back another 16 bytes. ; You will get 25 as the answer. Now your going to have to keep track manually of how many pushes you've done and adjust the variables location to access them. You can see how much of a problem this is going to cause when your project gets larger.
Now if you use a stack base pointer to access variables it's location is constant and you can access them at the same location everytime (As long as you don't modify the base pointer itself)
push rbp ; Save the old value of RBP. mov rbp, rsp sub rsp, 16 ; Align stack mov DWORD PTR[rbp - 4], 4 mov DWORD PTR[rbp - 8], 20 mov QWORD PTR[rbp - 16], 175 push 25 ; Push 25 to the stack. push 50 ; Push 8 to the stack. ... mov eax, DWORD PTR[rbp - 8] ; This will give you 20 because the ; stack base pointer's location is constant to ; the variables in the stack. The push statements ; only affect the stack pointers location, not the ; base pointer. ... mov rsp, rbp pop rbp ; After you pop the previous pushed values. Comments
In 32-bit (IA-32) and 64-bit code (x86-64) yes, in 16-bit code (8086 ... 80286) no. sp cannot be used in addressing in any way, esp and rsp can.
Wikipedia has a useful list of possible x86 and x86 addressing modes.
Using bp or some other register that can be used for addressing (bx, si, di) is only needed in 16-bit code.
12 Comments
mov bp/ebp/rsp, sp/esp/rsp; sub sp/esp/rsp, something, then your local variables are safe independently of the number of interrupts triggered and independently of how much stack the interrupts use.You can do that if you use ESP or RSP, but not SP because there's no SP-relative memory addressing, only ESP-relative and RSP-relative.
2 Comments
[ebp + 8] will store the 8 as a signed byte. Due to an oddity in the instruction encoding, there's no signed byte form for [esp + 8] - it will take four bytes to store the 8. I suspect (guessing!) that the situation is worse for rsp.mov reg, imm have 64-bit integers encoded in them.