汇编:C编程中变量的内存地址
Assembly: Memory address of variables in C Programming
这是我的 C 代码
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
这是标准输出
C:\Codes>test
+-----+-------+---------+----------+
| Var | Dec | Hex | Address |
+-----+-------+---------+----------+
| a | 12345 | 0x3039 | 0022FF4C |
| b | 74565 | 0x12345 | 0022FF48 |
+-----+-------+---------+----------+
这就是我在 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)
变量a
和b
的地址应该分别在0x22ff4c
和0x22ff48
(gdb) print &a
= (int *) 0x22ff4c
(gdb) print &b
= (int *) 0x22ff48
但是,如果您查看以下 GDB 反汇编输出,地址不是 0x22ff4c
& 0x22ff48
,而是 0x0040134e
& 0x00401356
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
我也在 x32dbg 上调试过这个,但也得到了相同的地址。
我在这里很困惑。如果 0x0040134e
& 0x00401356
不是变量 a
& b
的内存地址,那么它们是什么?
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
不,0x0040134e
和 0x00401356
不是变量 a
和 b
的地址。相反,它们是代码中指令的地址,即 instruction pointer IP。 a
和 b
在这些行中初始化:
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
这里a
和b
的地址分别是esp+0x1c
和esp+0x18
,其中esp
是stack pointer。作为地址,您将获得 0x22ff4c
和 0x22ff48
,您可以从中轻松推断出当前 esp
是 0x22ff4c - 0x1c
。
请注意这个答案忽略了操作系统的底层虚拟内存管理或其他相关的内存管理问题,即在大多数架构上 0x22ff4c
和 0x22ff48
将是虚拟内存地址,而不是真实的RAM 的物理地址。
这是我的 C 代码
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
这是标准输出
C:\Codes>test
+-----+-------+---------+----------+
| Var | Dec | Hex | Address |
+-----+-------+---------+----------+
| a | 12345 | 0x3039 | 0022FF4C |
| b | 74565 | 0x12345 | 0022FF48 |
+-----+-------+---------+----------+
这就是我在 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)
变量a
和b
的地址应该分别在0x22ff4c
和0x22ff48
(gdb) print &a
= (int *) 0x22ff4c
(gdb) print &b
= (int *) 0x22ff48
但是,如果您查看以下 GDB 反汇编输出,地址不是 0x22ff4c
& 0x22ff48
,而是 0x0040134e
& 0x00401356
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
我也在 x32dbg 上调试过这个,但也得到了相同的地址。
我在这里很困惑。如果 0x0040134e
& 0x00401356
不是变量 a
& b
的内存地址,那么它们是什么?
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
不,0x0040134e
和 0x00401356
不是变量 a
和 b
的地址。相反,它们是代码中指令的地址,即 instruction pointer IP。 a
和 b
在这些行中初始化:
0x0040134e <+14>: mov DWORD PTR [esp+0x1c],0x3039
0x00401356 <+22>: mov DWORD PTR [esp+0x18],0x12345
这里a
和b
的地址分别是esp+0x1c
和esp+0x18
,其中esp
是stack pointer。作为地址,您将获得 0x22ff4c
和 0x22ff48
,您可以从中轻松推断出当前 esp
是 0x22ff4c - 0x1c
。
请注意这个答案忽略了操作系统的底层虚拟内存管理或其他相关的内存管理问题,即在大多数架构上 0x22ff4c
和 0x22ff48
将是虚拟内存地址,而不是真实的RAM 的物理地址。