我有一个 C 程序,它有一个全局变量和一个局部变量。我的问题是在readelf上。以下是我的问题;1. 当我使用“readelf --symbols”进行地址转储时,我得到的全局变量地址与我运行程序时打印的地址相同。readelf 如何在我的程序运行或加载之前知道绝对地址?2. 为什么没有局部变量符号的信息?我只能看到全局变量的符号。
1 回答
readelf 如何在我的程序运行或加载之前知道绝对地址?
因为当链接器完成其工作时,为全局变量计算的地址就是程序加载器在运行时必须放置该变量的地址。链接器的工作主要是将信息放入可执行文件中,该可执行文件告诉程序加载器符号在内存中的映射位置。
为什么没有关于局部变量符号的信息
您的程序中可能存在三种“局部”变量。
主程序
static int static_filescope_i = 1;
int f()
{
static int static_local_i = 2;
return static_local_i;
}
int g()
{
int automatic_i = 3;
return automatic_i;
}
int global_i = 4;
int main()
{
return global_i + f() + g() + static_filescope_i;
}
automatic_local_i
每次程序进入定义它的块时,都会在运行时在堆栈上创建一个自动变量 like ,并停止存在然后离开该块。这样的变量不占用可执行文件中的存储空间,因此它不在符号表中表示。
变量 likestatic_filescope_i
通常称为静态全局变量,以将其与 like 区分开来static_local_i
。static_local_i
在定义它的块之外看不到。static_filescope_i
可以main.o
在同一个main.o
目标文件(
当程序第一次使用变量时,两者static_filescope_i
和都static_local_i
必须具有其初始值,然后保留它具有的任何值或分配给它的任何新值,直到下一次使用它 - 跨函数调用,直到程序结束。这意味着这些变量需要存储在可执行文件中,而不是堆栈中,并且它们可能会或可能不会在符号表中表示。
global_i
,当然,对整个程序来说是全局的:它可以在
main.o
我们可能链接到的任何其他文件中看到main.o
。
如果我们main.c
使用默认选项编译(无优化):
$ gcc -c main.c
然后我们发现:
$ readelf -s main.o | grep automatic_i
$
automatic_i
...没有.的符号
$ readelf -s main.o | grep global_i
12: 0000000000000004 4 OBJECT GLOBAL DEFAULT 3 global_i
... 的全局符号global_i
。
$ readelf -s main.o | grep static_filescope_i
5: 0000000000000000 4 OBJECT LOCAL DEFAULT 3 static_filescope_i
...本地符号static_filescope_i
$ readelf -s main.o | grep static_local_i
6: 0000000000000008 4 OBJECT LOCAL DEFAULT 3 static_local_i.1833
...也是 的本地符号static_local_i
,但附加了范围区分后缀。
在这里,GLOBAL
手段可以被链接器看到,LOCAL
手段不能被链接器看到。
因此,出于main.o
与任何其他目标文件或库链接以制作可执行文件的目的,static_filescope_i
还不static_local_i
如不存在。
这并不意味着它们在目标文件中完全没用。它们对于调试很有用。它们对于调查可执行文件的静态存储是由什么组成的很有用,就像我们现在所做的那样。
但是它们对链接器没有用,因此,如果您main.c
使用任何 > 0 的优化级别进行编译,那么编译器将假定您需要不是用于调试或调查目的的目标代码,并且它不会发出任何本地符号:
$ gcc -O1 -c main.c
$ readelf -s main.o | grep static_local_i
$ readelf -s main.o | grep static_filescope_i
$ readelf -s main.o | grep global_i
11: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_i
……只剩下global_i
。
这应该可以解释为什么您没有看到任何“本地”符号。您的自动变量永远不会在符号表中。如果您禁用了所有优化,您的静态变量仅在符号表中。