Search notes:

x86/x64 - Stackframe, base pointer

Within an established stack frame, the ebp register allows to access passed parameters (especially on the x86) and local variables with fixed offsets relative to the ebp.

x86

#include <stdio.h>
#include <stdint.h>

#ifdef _MSC_VER

   #define MOVE_REGISTER_VALUE_TO_VARIABLE(reg, var) \
                                                     \
          __asm mov var, reg;

#elif defined __GNUC__

   #define MOVE_REGISTER_VALUE_TO_VARIABLE(reg, var) \
                                                     \
          asm("movl %%" #reg ", %0\n" :              \
              "=r"( var ));


#else
   #error "Neither Microsoft nor GNU compiler"
#endif


uint32_t  retVal;
uint32_t* basePointer;

int __cdecl func(int param_1, char* param_2, int param_3) {

      int local_1;
      int local_2;

      MOVE_REGISTER_VALUE_TO_VARIABLE(ebp, basePointer)

      local_1 = 101;
      local_2 = 102;

#ifdef __GNUC__
      printf("EBP -4: Local 2 (gcc)   = %d\n",   basePointer[- 4]);
      printf("EBP -3: Local 1 (gcc)   = %d\n",   basePointer[- 3]);
#elif defined _MSC_VER
      printf("EBP -2: Local 2 (cl )   = %d\n",   basePointer[- 2]);
      printf("EBP -1: Local 1 (cl )   = %d\n",   basePointer[- 1]);
#else
      #error "Use Microsoft cl or gcc"
#endif

      printf("EBP  0: ?               = %d\n",   basePointer[  0]);

      printf("EBP  1: Return address  = %d\n",   basePointer[  1]);
      printf("EBP  2: Parameter 1     = %d\n",   basePointer[  2]);
      printf("EBP  3: Parameter 2     = %s\n",   basePointer[  3]);
      printf("EBP  4: Parameter 3     = %d\n",   basePointer[  4]);

      return 42;
}


int main() {

    printf("Address of func         = %d\n", &func);

 // printf("ESP before call: %d\n", basePointer[0]);
 // MOVE_REGISTER_VALUE_TO_VARIABLE(esp, basePointer)

    func(1, "hello world", 3);

    MOVE_REGISTER_VALUE_TO_VARIABLE(eax, retVal)

    printf("EAX   : Return value    = %d\n", retVal);

    return 0;
}
Github repository about-assembler-x86-x64, path: /stackframe/base-pointer/x86.c

Compile

With gcc:
gcc -c -O0 prog.c
gcc        prog.o

# objdump -d -S prog.o
cl /nologo /c prog.c
cl /nologo    prog.obj

Output

.\a.exe  
Address of func         = 4199760
EBP -4: Local 2 (gcc)   = 102
EBP -3: Local 1 (gcc)   = 101
EBP  0: ?               = 2686664
EBP  1: Return address  = 4200043
EBP  2: Parameter 1     = 1
EBP  3: Parameter 2     = hello world
EBP  4: Parameter 3     = 3
EAX   : Return value    = 42

prog.exe
Address of func         = 19730432
EBP -2: Local 2 (cl )   = 102
EBP -1: Local 1 (cl )   = 101
EBP  0: ?               = 3931604
EBP  1: Return address  = 19730659
EBP  2: Parameter 1     = 1
EBP  3: Parameter 2     = hello world
EBP  4: Parameter 3     = 3
EAX   : Return value    = 42

x64

#include <stdio.h>
#include <stdint.h>

#ifdef _MSC_VER

   #todo ...

   #define MOVE_REGISTER_VALUE_TO_VARIABLE(reg, var) \
                                                     \
          __asm mov var, reg;

#elif defined __GNUC__

   #define MOVE_REGISTER_VALUE_TO_VARIABLE(reg, var) \
                                                     \
          asm("movq %%" #reg ", %0\n" :              \
              "=r"( var ));


#else
   #error "Neither Microsoft nor GNU compiler"
#endif


uint64_t  retVal;
uint64_t* basePointer;
uint64_t  RDI, RSI, RDX;

int func(int param_1, char* param_2, int param_3) {

    uint64_t local_1;
    uint64_t local_2;

    MOVE_REGISTER_VALUE_TO_VARIABLE(rbp, basePointer)
    MOVE_REGISTER_VALUE_TO_VARIABLE(rdi, RDI        )
    MOVE_REGISTER_VALUE_TO_VARIABLE(rsi, RSI        )
    MOVE_REGISTER_VALUE_TO_VARIABLE(rdx, RDX        )

    local_1 = 101;
    local_2 = 102;

#ifdef __GNUC__
    printf("RBP -2: Local 2 (gcc)   = %d\n",   basePointer[- 2]);
    printf("RBP -1: Local 1 (gcc)   = %d\n",   basePointer[- 1]);
#elif defined _MSC_VER

# todo
    printf("RBP -2: Local 2 (cl )   = %d\n",   basePointer[- 2]);
    printf("RBP -1: Local 1 (cl )   = %d\n",   basePointer[- 1]);
#else
    #error "Use Microsoft cl or gcc"
#endif

    printf("RBP  0: ?               = %d\n",   basePointer[  0]);

    printf("RBP  1: Return address  = %ld\n",  basePointer[  1]);
    printf("RDI   : Parameter 1     = %d\n",   RDI             );
    printf("RSI   : Parameter 2     = %s\n",   RSI             );
    printf("RDX   : Parameter 3     = %d\n",   RDX             );

    return 42;
}


int main() {

    printf("Address of func         = %ld\n", &func);

 // printf("ESP before call: %d\n", basePointer[0]);
 // MOVE_REGISTER_VALUE_TO_VARIABLE(esp, basePointer)

    func(1, "hello world", 3);

    MOVE_REGISTER_VALUE_TO_VARIABLE(rax, retVal)

    printf("RAX   : Return value    = %ld\n", retVal);

    return 0;
}
Github repository about-assembler-x86-x64, path: /stackframe/base-pointer/x64.c

See also

Assembler (x86/x64)
The masm example for functions

Index