首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >R_X86_64_PLT32的地址是如何计算的?

R_X86_64_PLT32的地址是如何计算的?
EN

Stack Overflow用户
提问于 2020-10-19 09:35:33
回答 1查看 1.2K关注 0票数 2

我正在努力理解链接是如何工作的。我有一个简单的C++代码

代码语言:javascript
运行
复制
#include "a.h"

int Other() { 
  return 1;
}

int SomeFunction() {
  Other();
  Other();
  Other();

  return 0;
}

它生成以下重定位表。

代码语言:javascript
运行
复制
$ readelf -r a.o

Relocation section '.rela.text' at offset 0x240 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000018  000900000004 R_X86_64_PLT32    0000000000000000 _Z5Otherv - 4
00000000001d  000900000004 R_X86_64_PLT32    0000000000000000 _Z5Otherv - 4
000000000022  000900000004 R_X86_64_PLT32    0000000000000000 _Z5Otherv - 4

Relocation section '.rela.eh_frame' at offset 0x288 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
000000000040  000200000002 R_X86_64_PC32     0000000000000000 .text + f

看起来,其他()函数的调用站点都标记为R_X86_64_PLT32类型。当我检查R_X86_64_PLT32的定义时,它表示L+ and,其中L表示用于符号的过程链接表条目的位置(区段偏移或地址),A表示用于计算可重定位字段的值的加载项,P表示要重新定位的存储单元的位置(区段偏移或地址)(使用r_offset计算)。

我不知道PLT作为符号的位置意味着什么。我的问题是

  1. 对于这种情况,L,A,P的值是多少?
  2. 据我理解,PLT是由动态对象使用的。为什么其他()被标记为PLT32,即使这只是一个静态函数。
  3. 如何找到ELF文件的PLT以及如何在其中找到其他的()?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-12 16:42:02

我不是一个专家,有点晚,但据我所知,较新的GCC版本使用R_X86_64_PLT32而不是R_X86_64_PC32标记32位PC相关分支。

在x86-64上,对于32位PC相关分支,我们可以生成PLT32重定位,而不是PC32重定位,后者也可以用作32位PC相对分支的标记。如果在本地定义函数,链接器总是可以将PLT32重定位减少到PC32。本地函数应该使用PC32重新定位。(相关承诺)

因此,尽管重新定位条目的类型是R_X86_64_PLT32,链接器仍将使用R_X86_64_PC32计算(S +A)来修改重新定位目标,其中:

  • S是符号的值(st_value of Elf64_Sym)
  • A是加载项(在您的例子中是-4)
  • P是被重新定位的内存位置的地址( call的地址开始到Other)。

因为Other是一个本地函数。所以PLT在你的情况下根本不起作用。

如果您想获得关于所有节标题的概述(包括。.plt,.got,.got.plt .)您可以在EXEC/ DYN文件(编译和链接)上使用readelf -S。或者只需使用objdump -d <file,它也会显示不同的部分以及转储。

我希望这能解释一点。

为了完整起见,下面的例子类似于您的示例(我使用了C,但这不应该有什么区别):

我有一个文件rel.c,它在other.c中调用函数Other。首先,我编译了两个文件gcc -c -o <name>.o <name>.c

readelf -r rel.o

代码语言:javascript
运行
复制
Relocation section '.rela.text' at offset 0x198 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000015  000500000004 R_X86_64_PLT32    0000000000000000 Other - 4

如您所见,A (加载项)是-4,最终地址SP尚不清楚。

在使用gcc -o main rel.o other.o链接所有内容之后,我使用objdump -M intel -d main获得二进制文件的完整转储。有趣的部分如下所示。

代码语言:javascript
运行
复制
...
0000000000001139 <main>:
    1139:   55                      push   rbp
    113a:   48 89 e5                mov    rbp,rsp
    113d:   48 83 ec 10             sub    rsp,0x10
    1141:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
    1144:   48 89 75 f0             mov    QWORD PTR [rbp-0x10],rsi
    1148:   b8 00 00 00 00          mov    eax,0x0
    114d:   e8 07 00 00 00          call   1159 <Other>
    1152:   b8 00 00 00 00          mov    eax,0x0
    1157:   c9                      leave
    1158:   c3                      ret

0000000000001159 <Other>:
    1159:   55                      push   rbp
    115a:   48 89 e5                mov    rbp,rsp
...

可以看到,DWORD at 0x114e持有偏移量0x7,它可以与IP一起使用以跳转到Other子例程(0x1152 + 0x7 = 0x1159)的地址。

这是使用S + A - P = 0x1159 - 0x4 - 0x114e = 7计算的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64424692

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档