Readelf查找绝对地址

3

我有一个C程序,其中有一个全局变量和一个局部变量。我的问题是关于readelf的。以下是我的问题: 1. 当我使用“readelf --symbols”获取地址转储时,我得到了一个全局变量的地址,该地址与我运行程序时打印的地址相同。在我的程序运行或加载之前,readelf如何知道绝对地址? 2. 为什么没有关于局部变量符号的信息?我只能看到全局变量的符号。

1个回答

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中是全局的,但在整个程序中是局部于该目标文件

当程序首次使用变量时,static_filescope_istatic_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

这里,GLOBAL 表示可以被链接器看到,而 LOCAL 表示不能被链接器看到

因此,为了将 main.o 与其他目标文件或库链接以创建可执行文件,static_filescope_istatic_local_i 可能不存在

但这并不意味着它们在目标文件中完全没有用处。它们有助于调试,有助于研究可执行文件的静态存储是由什么组成的,就像我们现在正在做的那样。

但它们对于链接器没有用处,因此,如果您使用任何优化级别 > 0 编译 main.c,则编译器将假定您想要的对象代码不是用于调试或研究目的,并且它不会生成任何本地符号:


$ 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保留。

这就解释了为什么你看不到任何“局部”符号。你的自动变量从未出现在符号表中。只有当你禁用所有优化时,你的静态变量才会出现在符号表中。


谢谢Mike。这解答了我关于局部变量的第二个问题。但是我第一个问题还有一些疑问。如果我正在为不同的机器构建代码,我的本地链接器如何知道远程机器的内存结构?全局变量的地址在两台机器上打印出来是相同的,而局部变量的地址则不同。我注意到全局变量的地址是6位数,而局部变量的地址是12位数。这意味着全局变量的地址不是物理内存的地址吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接