To get better understanding of this, let's modify the program a little bit and debug it in GDB.
C:\Codes>gdb test -q
Reading symbols from C:\Codes\test.exe...done.
(gdb) set disassembly-flavor intel
(gdb) list
1 #include<stdio.h>
2
3 int main()
4 {
5 int a = 12345;
6 int b = 0x12345;
7 printf("Variable a %d (decimal) or 0x%x (hex), located at %p or 0x%x\n", a,a,&a,&a);
8 printf("Variable b %d (decimal) or 0x%x (hex), located at %p or 0x%x\n", b,b,&b,&b);
9 return 0;
10 }
(gdb)
Standard Output
C:\Codes>test
Variable a 12345 (decimal) or 0x3039 (hex), located at 0022FF4C or 0x22ff4c
Variable b 74565 (decimal) or 0x12345 (hex), located at 0022FF48 or 0x22ff48
As you can see, the virtual memory addresses of variable a
and b
is actually located at 0x22ff4c
and 0x22ff48
respectively.
Let's take a look at this program in GDB.
(gdb) break 7
Breakpoint 1 at 0x40135e: file test.c, line 7.
(gdb) run
Starting program: C:\Codes/test.exe
[New Thread 3680.0xed8]
Breakpoint 1, main () at test.c:7
7 printf("Variable a %d (decimal) or 0x%x (hex), located at %p or 0x%x\n", a,a,&a,&a);
(gdb) disassemble
Dump of assembler code for function main:
0x00401340 <+0>: push ebp
0x00401341 <+1>: mov ebp,esp
0x00401343 <+3>: and esp,0xfffffff0
0x00401346 <+6>: sub esp,0x30
0x00401349 <+9>: call 0x401970 <__main>
0x0040134e <+14>: mov DWORD PTR [esp+0x2c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x28],0x12345
=> 0x0040135e <+30>: mov edx,DWORD PTR [esp+0x2c]
0x00401362 <+34>: mov eax,DWORD PTR [esp+0x2c]
0x00401366 <+38>: lea ecx,[esp+0x2c]
0x0040136a <+42>: mov DWORD PTR [esp+0x10],ecx
0x0040136e <+46>: lea ecx,[esp+0x2c]
0x00401372 <+50>: mov DWORD PTR [esp+0xc],ecx
0x00401376 <+54>: mov DWORD PTR [esp+0x8],edx
0x0040137a <+58>: mov DWORD PTR [esp+0x4],eax
0x0040137e <+62>: mov DWORD PTR [esp],0x403024
0x00401385 <+69>: call 0x401be0 <printf>
0x0040138a <+74>: mov edx,DWORD PTR [esp+0x28]
0x0040138e <+78>: mov eax,DWORD PTR [esp+0x28]
0x00401392 <+82>: lea ecx,[esp+0x28]
0x00401396 <+86>: mov DWORD PTR [esp+0x10],ecx
0x0040139a <+90>: lea ecx,[esp+0x28]
0x0040139e <+94>: mov DWORD PTR [esp+0xc],ecx
0x004013a2 <+98>: mov DWORD PTR [esp+0x8],edx
0x004013a6 <+102>: mov DWORD PTR [esp+0x4],eax
0x004013aa <+106>: mov DWORD PTR [esp],0x403064
0x004013b1 <+113>: call 0x401be0 <printf>
0x004013b6 <+118>: mov eax,0x0
0x004013bb <+123>: leave
0x004013bc <+124>: ret
End of assembler dump.
(gdb)
And focus on this line
0x0040134e <+14>: mov DWORD PTR [esp+0x2c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x28],0x12345
As you can see from the previous output, the virtual memory address of variables a
and b
is actually located at [esp+0x2c]
or 0x22ff4c
and [esp+0x28]
or 0x22ff48
respectively.
while
0x3039
& 0x12345
are the value of variables a
and b
in hexadecimal.
To verify the memory address of these variables in GDB, use print
command as follows:
(gdb) print &a
$1 = (int *) 0x22ff4c
(gdb) print &b
$2 = (int *) 0x22ff48
Also, you might wonder where the address of 0x22ff4c
or 0x22ff48
come from.
To understand this, let's check the value of current ESP register
(gdb) info registers esp
esp 0x22ff20 0x22ff20
Then, replace the actual ESP value
[esp+0x2c] = [0x22ff20 + 0x2c] = 0x22ff4c
[esp+0x28] = [0x22ff20 + 0x28] = 0x22ff48