.so 部分之间的距离是否始终保留,无论 .so 加载到内存中的哪个位置?

Are the distances between .so sections always preserved, no matter where in memory the .so gets loaded?

TLDR:.so 不知道它会被加载到哪里,但是每个段肯定知道其他段相对于它自己的位置?


我有以下 .c 文件:

int shared_variable = 3;

int shared_func()
{
    return shared_variable;
}

我用PIC编译它:gcc -fpic -c -g shared.cobjdump它,看到正在使用的GOT(第1行),以及GOT入口的重定位(第2行),然后最后获取 shared_variable 的值(第 3 行):

8:  48 8b 05 00 00 00 00    mov    rax,QWORD PTR [rip+0x0]        # f <shared_func+0xf>
        b: R_X86_64_REX_GOTPCRELX   shared_variable-0x4
f:  8b 00                   mov    eax,DWORD PTR [rax]

然后我创建了一个共享库:gcc -shared -o libshared.so shared.oobjdump,然后看到 GOT 条目的重定位已经解决:

1101:   48 8b 05 d0 2e 00 00    mov    rax,QWORD PTR [rip+0x2ed0]        # 3fd8 <shared_variable-0x48>
1108:   8b 00                   mov    eax,DWORD PTR [rax]

因此这段代码现在假定 GOT 条目位于 .text 部分的这一部分的 0x2ed0 字节处。事实上,如果我 运行 readelf 我看到 .text0x1040 开始,.got0x3fd00x2f90 开始离开。我还看到 .text.got 在不同的段中。

.so 无法知道它将 实际上 加载到内存中的哪个位置,所以我假设地址在 readelf 部分 headers 只是建议。但是由于到 GOT 条目 (mov rax,QWORD PTR [rip+0x2ed0]) 的距离是硬编码的,我假设 之间的距离 .so 的段将始终如程序 headers?这也感觉很明智,因为 .so 中的代码将如何找到 GOT?

The .so can't know where in memory it will actually be loaded though,

正确。

so I assume the addresses in readelfs section headers are just suggestions.

不正确。

在静态 link 之后,headers 部分的地址是固定的,并且将保持原样(相对于彼此)。但是请注意,headers 部分在运行时不是必需的,可以删除(例如,通过 strip 命令)——运行时没有任何东西关注它们。

But since the distance to the GOT entry (mov rax,QWORD PTR [rip+0x2ed0]) is hard coded, I assume the distances between the segments of the .so will always be as specified in the program headers?

正确。所有(可加载)段一起加载。也就是说,加载器计算出加载段需要多少 space all,然后执行单个 mmap(0, ...)1mmap(此 .so 的负载基础)的结果决定了此 .so 所有 段所在的位置。


1假设 non-prelinked .so.

我找到了一个来源。在 John R. Levine 的链接器和加载器中,第 10.2 章:

Because the GOT is in the same loadable ELF file as the code that references it, and the relative addresses within a file don't change regardless of where the program is loaded, the code can locate the GOT with a relative address, load the address of the GOT into a register, and then load pointers from the GOT whenever it needs to address static data. [my emphasis]

因此,当链接文件时,ELF 文件内部 的相对地址确实是已知的,并且可以解决同一文件(例如 GOT)中符号的重定位那么