【发布时间】:2016-03-13 08:51:27
【问题描述】:
我有一个 C 程序,它有一个全局变量和一个局部变量。我的问题是在阅读器上。以下是我的问题; 1. 当我使用“readelf --symbols”进行地址转储时,我得到一个全局变量的地址,该地址与我在运行程序时打印的地址相同。 readelf 如何在我的程序运行或加载之前知道绝对地址? 2. 为什么没有局部变量符号的信息?我只能看到全局变量的符号。
【问题讨论】:
我有一个 C 程序,它有一个全局变量和一个局部变量。我的问题是在阅读器上。以下是我的问题; 1. 当我使用“readelf --symbols”进行地址转储时,我得到一个全局变量的地址,该地址与我在运行程序时打印的地址相同。 readelf 如何在我的程序运行或加载之前知道绝对地址? 2. 为什么没有局部变量符号的信息?我只能看到全局变量的符号。
【问题讨论】:
readelf 如何在我的程序运行或加载之前知道绝对地址?
因为当链接器完成它的工作时,为 您的全局变量是程序加载器将在该地址 必须在运行时放置该变量。链接器的工作主要是 将信息放入一个可执行文件中,告诉程序加载器在哪里 符号将被映射到内存中。
为什么没有关于局部变量符号的信息
您的程序中可能存在三种“局部”变量。
main.c
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 这样的自动变量是在运行时在堆栈上创建的
每次程序进入定义它的块,并且不再存在时
然后它离开那个块。这样的变量不占用可执行文件中的存储空间
所以它没有在符号表中表示。
像static_filescope_i 这样的变量通常被称为静态全局变量,
将其与static_local_i 等区别开来。 static_local_i不能
在定义它的块之外可以看到。 static_filescope_i可以
可以在同一目标文件 (main.o) 中定义的任何函数中看到,但
不在任何其他目标文件中:它在 main.o 内是 global 但
在整个程序中本地到该目标文件。
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
level > 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。
这应该可以解释为什么您没有看到任何“本地”符号。你是自动的 变量从不在符号表中。您的静态变量仅在 如果您已禁用所有优化,则符号表。
【讨论】: