I have recently been learning assembly, and decided to disassemble some of my own executables to study from. I've noticed online resources often reference esp and ebp, the stack and base pointer. I wrote this program:
int comp(int a, int b) {
return a == b;
}
int main() {
int a = 1;
int b = 2;
comp(a, b);
}
And in Radare 2 this disassembles into:
0x0040050e 55 push rbp
| 0x0040050f 4889e5 mov rbp, rsp
| 0x00400512 4883ec10 sub rsp, 0x10
| 0x00400516 c745f801000. mov dword [rbp-0x8], 0x1
| 0x0040051d c745fc02000. mov dword [rbp-0x4], 0x2
| 0x00400524 8b55fc mov edx, [rbp-0x4]
| 0x00400527 8b45f8 mov eax, [rbp-0x8]
| 0x0040052a 89d6 mov esi, edx
| 0x0040052c 89c7 mov edi, eax
| 0x0040052e e8c3ffffff call sym.comp
| sym.comp(unk)
| 0x00400533 b800000000 mov eax, 0x0
| 0x00400538 c9 leave
\ 0x00400539 c3 ret
Why is it using rbp and rsp? Is this just the way my compiler likes to do things? Also, why is it rbp-value to create space on the stack, shouldn't it be rbp+value to allocate more space?
EBP = Evidence-based practice; RBP = Research-based practice.
The register 'ESP' is used to point to the next item on the stack and is referred to as the 'stack pointer'. EBP aka the 'frame pointer' serves as an unchanging reference point for data on the stack. This allows the program to work out how far away something in the stack is from this point.
%rbp is the base pointer, which points to the base of the current stack frame, and %rsp is the stack pointer, which points to the top of the current stack frame. %rbp always has a higher value than %rsp because the stack starts at a high memory address and grows downwards.
This means that -4(%ebp) refers to the first local variable. Perform the function's purpose At this point, the stack frame is set up correctly, and this is represented by the diagram to the right. All the parameters and locals are offsets from the %ebp register: 16(%ebp)
You are compiling for 64-bit, so rbp
and rsp
are just the 64-bit equivalents to the 32-bit ebp
and esp
variables. Even in 64-bit code you often see the 32-bit (e**
) registers used when possible - but you won't see that with rsp
or rbp
usually1 since they hold pointers that almost always need to be 64-bit.
Since rbp
points to the the base of your stack frame (i.e., the top of the stack on function entry) and stacks on x86 grow downwards (towards lower addresses), the local arguments will be accessed at negative addresses relative to rbp
.
1 You might occasionally see ebp
used in 64-bit code, but that's just because the compiler has relieved it from its usual frame-pointer duties and is just using it as another GP register.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With