注明: 以下结论的可靠性不予担保。
1. 实验方法
- 给出两个C++源代码文件,主要文件如下,辅助文件定义了全局变量g_ext, g_ext_ini。
#include <stdio.h> extern int g_ext; extern int g_ext_ini; int g_a=10, g_b, g_array1[15], g_array2[5]; int main() { int i = 0; i = g_array1[3] + g_array2[0] + g_a + g_b+g_ext + g_ext_ini; printf("i=%d\n", i); return 0; }
- 用#gcc -g global.c命令得到二进制文件global;再利用dwarfdump工具输出其调试信息,global.c对应的部分调试信息如下:
可以看出,定义的变量分配了地址;声明的外部变量没有分配地址。<2>< 145> DW_TAG_variable // 局部变量i DW_AT_name i DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 7 DW_AT_type <79> DW_AT_location DW_OP_breg4+28 <1>< 158> DW_TAG_variable // 全局变量 DW_AT_name g_ext DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 2 DW_AT_type <79> DW_AT_external yes(1) DW_AT_declaration yes(1) <1>< 171> DW_TAG_variable // 全局变量 DW_AT_name g_ext_ini DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 3 DW_AT_type <79> DW_AT_external yes(1) DW_AT_declaration yes(1) <1>< 184> DW_TAG_variable // 全局变量 DW_AT_name g_a DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 4 DW_AT_type <79> DW_AT_external yes(1) DW_AT_location DW_OP_addr 0x804a014 <1>< 202> DW_TAG_variable // 全局变量 DW_AT_name g_b DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 4 DW_AT_type <79> DW_AT_external yes(1) DW_AT_location DW_OP_addr 0x804a09c <1>< 220> DW_TAG_array_type DW_AT_type <79> DW_AT_sibling <236> <2>< 229> DW_TAG_subrange_type DW_AT_type <107> DW_AT_upper_bound 14 <1>< 236> DW_TAG_variable DW_AT_name g_array1 DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 4 DW_AT_type <220> DW_AT_external yes(1) DW_AT_location DW_OP_addr 0x804a060 <1>< 254> DW_TAG_array_type DW_AT_type <79> DW_AT_sibling <270> <2>< 263> DW_TAG_subrange_type DW_AT_type <107> DW_AT_upper_bound 4 <1>< 270> DW_TAG_variable DW_AT_name g_array2 DW_AT_decl_file 1 /home/rallylee/Develop/test/global/global.c DW_AT_decl_line 4 DW_AT_type <254> DW_AT_external yes(1) DW_AT_location DW_OP_addr 0x804a040
- 利用pin工具,得到global运行时的指令序列,进而得到该序列的反汇编序列(左边),与原来的global.s文件进行对比:
-
...省略其它函数调用 %push ebp %mov ebp, esp %and esp, 0xfffffff0 %sub esp, 0x20 %mov dword ptr [esp+0x1c], 0x0 %mov edx, dword ptr [0x804a06c] %mov eax, dword ptr [0x804a040] %add edx, eax %mov eax, dword ptr [0x804a014] %add edx, eax %mov eax, dword ptr [0x804a09c] %add edx, eax %mov eax, dword ptr [0x804a0a0] %add edx, eax %mov eax, dword ptr [0x804a018] %lea eax, ptr [edx+eax*1] %mov dword ptr [esp+0x1c], eax %mov eax, 0x80484e0 %mov edx, dword ptr [esp+0x1c] %mov dword ptr [esp+0x4], edx %mov dword ptr [esp], eax %call 0x80482f4 ...省略其它函数调用 %mov eax, 0x0 %leave %ret ...省略其它函数调用
.globl main .type main, @function main: .LFB0: .file 1 "global.c" .loc 1 6 0 .cfi_startproc pushl %ebp .LCFI0: .cfi_def_cfa_offset 8 movl %esp, %ebp .cfi_offset 5, -8 .LCFI1: .cfi_def_cfa_register 5 andl $-16, %esp subl $32, %esp .loc 1 7 0 movl $0, 28(%esp) .loc 1 8 0 movl g_array1+12, %edx movl g_array2, %eax addl %eax, %edx movl g_a, %eax addl %eax, %edx movl g_b, %eax addl %eax, %edx movl g_ext, %eax addl %eax, %edx movl g_ext_ini, %eax leal (%edx,%eax), %eax movl %eax, 28(%esp) .loc 1 9 0 movl $.LC0, %eax movl 28(%esp), %edx movl %edx, 4(%esp) movl %eax, (%esp) call printf .loc 1 10 0 movl $0, %eax .loc 1 11 0 leave
可以看出:
- 编译时给全局变量分配的逻辑地址,在运行时没有发生变化。
- 编译时给局部变量生成的是基于ESP寄存器的地址表达式,运行时会计算出该表达式的值。