This is my C code
C:\Codes>gdb test -q
Reading symbols from C:\Codes\test.exe...done.
(gdb) list 1,15
1       #include<stdio.h>
2
3       int main()
4       {
5               int a = 12345;
6               int b = 0x12345;
7               printf("+-----+-------+---------+----------+\n");
8               printf("| Var | Dec   | Hex     | Address  |\n");
9               printf("+-----+-------+---------+----------+\n");
10              printf("|  a  | %d | 0x%x  | %p |\n",a,a,&a);
11              printf("|  b  | %d | 0x%x | %p |\n",b,b,&b);
12              printf("+-----+-------+---------+----------+\n");
13
14              return 0;
15      }
(gdb) set disassembly-flavor intel
And this is the standard output
C:\Codes>test
+-----+-------+---------+----------+
| Var | Dec   | Hex     | Address  |
+-----+-------+---------+----------+
|  a  | 12345 | 0x3039  | 0022FF4C |
|  b  | 74565 | 0x12345 | 0022FF48 |
+-----+-------+---------+----------+
This is what I'm seeing in GDB
(gdb) break 7
Breakpoint 1 at 0x40135e: file test.c, line 7.
(gdb) run
Starting program: C:\Codes/test.exe
[New Thread 4044.0xab0]
Breakpoint 1, main () at test.c:7
7               printf("+-----+-------+---------+----------+\n");
(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,0x20
   0x00401349 <+9>:     call   0x401990 <__main>
   0x0040134e <+14>:    mov    DWORD PTR [esp+0x1c],0x3039
   0x00401356 <+22>:    mov    DWORD PTR [esp+0x18],0x12345
=> 0x0040135e <+30>:    mov    DWORD PTR [esp],0x403024
   0x00401365 <+37>:    call   0x401c00 <puts>
   0x0040136a <+42>:    mov    DWORD PTR [esp],0x40304c
   0x00401371 <+49>:    call   0x401c00 <puts>
   0x00401376 <+54>:    mov    DWORD PTR [esp],0x403024
   0x0040137d <+61>:    call   0x401c00 <puts>
   0x00401382 <+66>:    mov    edx,DWORD PTR [esp+0x1c]
   0x00401386 <+70>:    mov    eax,DWORD PTR [esp+0x1c]
   0x0040138a <+74>:    lea    ecx,[esp+0x1c]
   0x0040138e <+78>:    mov    DWORD PTR [esp+0xc],ecx
   0x00401392 <+82>:    mov    DWORD PTR [esp+0x8],edx
   0x00401396 <+86>:    mov    DWORD PTR [esp+0x4],eax
   0x0040139a <+90>:    mov    DWORD PTR [esp],0x403071
   0x004013a1 <+97>:    call   0x401c08 <printf>
   0x004013a6 <+102>:   mov    edx,DWORD PTR [esp+0x18]
   0x004013aa <+106>:   mov    eax,DWORD PTR [esp+0x18]
   0x004013ae <+110>:   lea    ecx,[esp+0x18]
   0x004013b2 <+114>:   mov    DWORD PTR [esp+0xc],ecx
   0x004013b6 <+118>:   mov    DWORD PTR [esp+0x8],edx
   0x004013ba <+122>:   mov    DWORD PTR [esp+0x4],eax
   0x004013be <+126>:   mov    DWORD PTR [esp],0x40308c
   0x004013c5 <+133>:   call   0x401c08 <printf>
   0x004013ca <+138>:   mov    DWORD PTR [esp],0x403024
   0x004013d1 <+145>:   call   0x401c00 <puts>
   0x004013d6 <+150>:   mov    eax,0x0
   0x004013db <+155>:   leave
   0x004013dc <+156>:   ret
End of assembler dump.
(gdb)
The address for variables a & b is supposed to be at 0x22ff4c & 0x22ff48 respectively
(gdb) print &a
$1 = (int *) 0x22ff4c
(gdb) print &b
$2 = (int *) 0x22ff48
However, if you look at the following GDB disassemble output, the address was not 0x22ff4c & 0x22ff48, but 0x0040134e & 0x00401356
   0x0040134e <+14>:    mov    DWORD PTR [esp+0x1c],0x3039
   0x00401356 <+22>:    mov    DWORD PTR [esp+0x18],0x12345
I've also debug this on x32dbg but getting the same address too.

I'm confused here. What was the 0x0040134e & 0x00401356 if they are not the memory addresses for variables a & b?
The static variables are stored in the data segment of the memory. The data segment is a part of the virtual address space of a program. All the static variables that do not have an explicit initialization or are initialized to zero are stored in the uninitialized data segment( also known as the BSS segment).
How are variables stored in assembly? The assembler associates an offset value for each variable name defined in the data segment. Each byte of character is stored as its ASCII value in hexadecimal. Each decimal value is automatically converted to its 16-bit binary equivalent and stored as a hexadecimal number.
This system function allows you to set the highest available address in the data section. This system call takes one parameter, which is the highest memory address needed to be set. This value is stored in the EBX register. In case of any error, sys_brk() returns -1 or returns the negative error code itself.
Typically local variables are put on the "stack". This means that the compiler assigns an offset to the "stack pointer" which can be different depending on the invocation of the current function. I.e. the compiler assumes that memory locations like Stack-Pointer+4, Stack-Pointer+8, etc.
0x0040134e <+14>:    mov    DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>:    mov    DWORD PTR [esp+0x18],0x12345
No, 0x0040134e and 0x00401356 are not addresses for variables a and b. Instead they are address of the instruction in code, i.e. instruction pointer IP. a and b are initialized in these lines:
0x0040134e <+14>:    mov    DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>:    mov    DWORD PTR [esp+0x18],0x12345
Here the address of a and b are esp+0x1c and esp+0x18 respectively  where esp is the stack pointer. As address you are getting 0x22ff4c and 0x22ff48 from which you can easily deduct that current esp is 0x22ff4c - 0x1c.
Please note the this answer ignores the underlying virtual memory management or other related memory management matters of operating system, i.e. on most architecture 0x22ff4c and 0x22ff48 will be virtual memory address, not the real physical address of your RAM.
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