What is the purpose of EBP in the following code?

I have two questions about the EBP register.

I understand ESP and EIP. However, I really don't understand why to use EBP.

In the code below, I push the EBP register (which is actually 0000000) onto the stack. Then I move the stack memory address to EBP so that ESP and EBP have the same data. This is a prologue. There is code that ends with syscall. Then I do the opposite (epilog), because โ€œleaveโ€ means that I move EBP to ESP (these values โ€‹โ€‹are the same thanks to prologs), and then pops the last stack value (which is EBP, which is 00000000) into EBP. This gives the EBP the same meaning as before the prologue.

Why would anyone do this? What's the point? Please answer in a simple way! Remember that I do not understand what EBP (frame pointer) actually does.

EDIT: or is it that this is a way to efficiently back up the stack (ESP) when using the function? In other words: the program can do what it does with the stack, and the "original stack" will always be in EBP. Then, when the program ends, EBP returns to how it was before. It's right? If so, is the epilogue just a selection procedure?

Besides AIUI, I can use 'enter' to replace 'push ebp / mov ebp, esp'. However, when I try to compile in nasm, I get an "error: invalid combination of opcode and operands" "leave" works fine; 'enter' no. What is the correct syntax?

Thanks!

Example: push ebp mov, ebp, esp [some code here] int 0x80 leave ret 
+4
source share
3 answers

EBP forms a fixed reference point for variables in the stack: mainly all the parameters of the function, all local parameters of the function, and finally the return address. Using this fixed point, a function can expand / change its stack almost randomly, go to the functionโ€™s epilogue anywhere, and restore the stack pointer to its original position.

The concept was next to mandatory, since the source code 8086 did not allow the use of a stack pointer with an offset, as in mov ax, [sp + 10] , but only with push and pop . A reference to anything else, but the top element should be made using mov xx, [bp + 10] .

+1
source

The idea of โ€‹โ€‹EBP really is to form a fixed reference point. Often you can play with the stack pointer (for example, by pushing parameters on a stack ready for a call) and find real pain to figure out where some of the data relates to the stack pointer. But with respect to the base pointer, it is always the same. Modern compilers can easily cope with this, but if you want to write a large piece of assembler code (manually) that uses the stack to push and pop up, it will be easier for you to refer to your local variables relative to the register (EBP), which does not change.

+1
source

enter also requires a number, which is the space for allocation, which is the key to your question: these instructions are for setting the location for your local function.

Local variables are passed through the EBP register. Let me show you an example:

 import core.stdc.stdio; void main() { int a = 8; a += 8; printf("%d\n", 8); } 

(This is D code, but it is not very important)

 Disassembly of section .text._Dmain: 00000000 <_Dmain>: 0: 55 push ebp 1: 8b ec mov ebp,esp 3: 83 ec 04 sub esp,0x4 6: b8 08 00 00 00 mov eax,0x8 b: 89 45 fc mov DWORD PTR [ebp-0x4],eax e: 01 45 fc add DWORD PTR [ebp-0x4],eax 11: 50 push eax 12: b9 00 00 00 00 mov ecx,"%d\n" 17: 51 push ecx 18: e8 fc ff ff ff call printf 1d: 31 c0 xor eax,eax 1f: 83 c4 08 add esp,0x8 22: c9 leave 23: c3 ret 

Let me break it down into each part:

  0: 55 push ebp 1: 8b ec mov ebp,esp 3: 83 ec 04 sub esp,0x4 

This is a prolog function, setting up ebp. sub esp, 0x4 deleted the 4 byte stack - this frees up space for our local variable int a 4 bytes long.

The enter instruction is rarely used, but I believe that enter 4,0 does the same thing - introduces a function with 4 bytes of the local variable space. edit: Another 0 is the nesting level, I have never seen it used ... input is usually slower than just following the steps themselves, as the compiler does. / Edit

  6: b8 08 00 00 00 mov eax,0x8 b: 89 45 fc mov DWORD PTR [ebp-0x4],eax 

This is line a=8 - the second line stores the value in the local memory of variables.

  e: 01 45 fc add DWORD PTR [ebp-0x4],eax 

Then add to it in a+=8 (the compiler reused eax here, as it recognized that the number is the same ...)

After that, it calls printf, pushing its arguments onto the stack, then zeros the eax register ( xor eax, eax ), since D returns 0 from the function.

  11: 50 push eax 12: b9 00 00 00 00 mov ecx,"%d\n" 17: 51 push ecx 18: e8 fc ff ff ff call printf 1d: 31 c0 xor eax,eax 1f: 83 c4 08 add esp,0x8 

Note that add esp, 0x8 is part of the printf call here: the caller is responsible for clearing the arguments after the function call. This is necessary because only the caller knows how many arguments he sent - this is what the arguments to the printf variable allow.

In any case, finally, we clear the local variables and return from the function:

  22: c9 leave 23: c3 ret 

edit: leave btw expands to mov esp, ebp; pop ebp; mov esp, ebp; pop ebp; - this is exactly the opposite of the installation instructions, and, as Aki Suikonen said in another answer, the good thing here is that the stack is restored as it was with the input function, regardless of what happened inside the function (well, if the function did not completely destroy the contents stack, in which case your program will most likely crash soon) ./ Change

So, on the bottom line, the ebp stuff is all about your local variables. It uses esp to get started, so it has a nice memory space that will not step on other functions (it is on the call stack), but moves it to ebp so that your locals stay at a constant offset throughout the function - variable a ALWAYS [EBP-4] in this function, even when the stack is being manipulated.

The easiest way to see it in action is by examining the function you are writing in C or something like what we did here. The linux command objdump -d -M intel somefile.o is what I used (then I manually fixed some minor things to make it more readable. If you break the .o file, all the library calls have not been resolved yet, so it can look weird, but itโ€™s not, t affect local variables!)

0
source

Source: https://habr.com/ru/post/979152/


All Articles