Attached is the part of a disassembled main from a x86 binary file, generated by ghidra.

                             *                          FUNCTION                          *
                             undefined main(undefined1 param_1)
             undefined         AL:1           <RETURN>                                XREF[1]:     0804835e(W)  
             undefined1        Stack[0x4]:1   param_1                                 XREF[1]:     08048309(*)  
             undefined4        EAX:4          str_in                                  XREF[1]:     0804835e(W)  
             undefined4        Stack[0x0]:4   local_res0                              XREF[1]:     08048310(R)  
             undefined4        Stack[-0x10]:4 local_10                                XREF[6]:     08048358(R), 
             undefined4        Stack[-0x14]:4 local_14                                XREF[2]:     0804831a(W), 
             undefined4        Stack[-0x18]:4 local_18                                XREF[2]:     08048321(W), 
             undefined4        Stack[-0x2c]:4 local_2c                                XREF[3]:     08048369(W), 
             undefined4        Stack[-0x30]:4 local_30                                XREF[12]:    08048328(*), 
                             main                                            XREF[2]:     Entry Point(*), 
        08048309 8d 4c 24 04     LEA        ECX=>param_1,[ESP + 0x4]
        0804830d 83 e4 f0        AND        ESP,0xfffffff0
        08048310 ff 71 fc        PUSH       dword ptr [ECX + local_res0]
        08048313 55              PUSH       EBP
        08048314 89 e5           MOV        EBP,ESP
        08048316 51              PUSH       ECX
        08048317 83 ec 24        SUB        ESP,0x24
        0804831a c7 45 f4        MOV        dword ptr [EBP + local_14],DAT_080a6b19          = 6Ah    j
                 19 6b 0a 08
        08048321 c7 45 f0        MOV        dword ptr [EBP + local_18],s_the_ripper_080a6b1e = "the ripper"
                 1e 6b 0a 08

Same code from gdb

   0x08048309 <+0>: lea    ecx,[esp+0x4]
   0x0804830d <+4>: and    esp,0xfffffff0
   0x08048310 <+7>: push   DWORD PTR [ecx-0x4]
   0x08048313 <+10>:    push   ebp
   0x08048314 <+11>:    mov    ebp,esp
   0x08048316 <+13>:    push   ecx
   0x08048317 <+14>:    sub    esp,0x24
=> 0x0804831a <+17>:    mov    DWORD PTR [ebp-0xc],0x80a6b19

Why is ghidra changeing [ebp-0xc] to [EBP + local_14]. Similar question I found is Ghidra interpreting stack pointers wrongly but reading the answer, I'm not getting the meaning of [EBP + local_14] Here, is ghidra just renaming -0xc to a easily readable name like local_14? I'm not getting how to make sense of this exactly.

In the function header, it is shown that Stack[-0x10]:4 local_10. I assume it means that local_10 is 4 byte variable at Stack[-0x10], where Stack is the stack pointer upon entry to function. But why is it added to ebp. What's the meaning of that representation used by ghidra?

  • Before doing anything with Ghidra, I start to help Ghidra by telling it the return types of functions ( int, void, char *, etc ). Then I do the same for the function parameters. Just this step alone starts to clear up the local variables. Did you try that ? Commented Dec 8, 2020 at 17:06
  • One thing you can do that may make this more obvious is to turn off the setting that causes Ghidra to use the local_ variables directly in the assembly. You can do this via Edit -> Tool Options -> Listing Fields -> Operands Field -> Markup Stack Variable References. This will change the display to show the normal operands, with an arrow indicating what stack variable is being referenced. Commented Dec 8, 2020 at 23:09

1 Answer 1


Since local variables are usually placed on the stack in x86 and esp register can change during function execution, it is more convenient to save the value of esp register on function entry and access data relatively to that value. ebp register is used for this purpose. So you will often see

push ebp
mov ebp, esp

lines at the begining of functions. In the example you have provided it is the case - all local variables are accessed this way, through ebp.

Now, there are two different naming conventions for local variables:

  • first and more natural one: if [ebp - xxx] is accessed, it will be displayed as [ebp + local_xxx]. Here, local_xxx = -xxx, so for instance, local_18 = -0x18.
  • second and less intuitive one makes use of the esp value at the beginning of a function. In your example, two dwords are pushed on the stack before mov ebp, esp line. It means, that if some local variable was called local_xxx in the first convention, in the second one it will be named local_xxx+0x8, for instance local_18 in the first one will be local_20 in the second one, used by Ghidra.

Why do we add 0x8 in the second one? Because two dwords (8 bytes) were pushed onto the stack before esp value was saved into ebp and in x86 architecture stack "grows downwards", which means if you push something onto it, this value will be saved there and esp will be decreased accordingly (in this case, twice, by 4 bytes). So, in your particular example, you have the instruction

mov    DWORD PTR [ebp-0xc],0x80a6b19

which would be displayed as

mov    DWORD PTR [ebp+local_c],0x80a6b19

in the first convention and

mov    DWORD PTR [ebp+local_14],0x80a6b19

in the second one, implemented in Ghidra, since 0xc + 0x8 = 0x14.

  • Just to confirm. In the second convention, when it shows ebp+local_14 , ebp actually mean the value of esp at the beginning of of the function call and not the value of ebp when the instruction is ran?
    – Mah35h
    Commented Dec 9, 2020 at 4:38
  • No, it is current ebp value (which is entry_esp-8).
    – bart1e
    Commented Dec 9, 2020 at 7:41
  • then value of local_14 should be -0xC right. Else it'll point to wrong memory location when added with ebp
    – Mah35h
    Commented Dec 9, 2020 at 9:05
  • Exactly. And that's why I called this convention "less intuitive".
    – bart1e
    Commented Dec 9, 2020 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.