为什么链接器会在 .rela.plt 中生成看似无用的重定位?

2023-12-19

首先,我正在玩的玩具程序:

prog.c:

int func1();

int main(int argc, char const *argv[])
{
    func1();
    return 0;
}

lib.c:

int func1()
{
    return 0;
}

构建:

gcc -O3 -g -shared -fpic ./lib.c -o liba.so
gcc prog.c -g -la -L. -o prog -Wl,-rpath=$PWD

为了完整性:

$ gcc --version
gcc (GCC) 6.3.1 

$ ld --version
GNU ld version 2.26.1

现在,我的问题。我已经确认了我所读到的有关动态符号的惰性绑定如何工作的内容,即 最初的 GOT 条目为func1直接返回 PLT,指向跳转后的指令:

$ gdb prog    

(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400666 <+0>: push   rbp
   0x0000000000400667 <+1>: mov    rbp,rsp
   0x000000000040066a <+4>: sub    rsp,0x10
   0x000000000040066e <+8>: mov    DWORD PTR [rbp-0x4],edi
   0x0000000000400671 <+11>:    mov    QWORD PTR [rbp-0x10],rsi
   0x0000000000400675 <+15>:    mov    eax,0x0
   0x000000000040067a <+20>:    call   0x400560 <func1@plt>    <<< call to shared lib via PLT
   0x000000000040067f <+25>:    mov    eax,0x0
   0x0000000000400684 <+30>:    leave  
   0x0000000000400685 <+31>:    ret    
End of assembler dump.
(gdb) disassemble 0x400560
Dump of assembler code for function func1@plt:
   0x0000000000400560 <+0>: jmp    QWORD PTR [rip+0x200ab2]        # 0x601018 <<< JMP to address stored in GOT
   0x0000000000400566 <+6>: push   0x0             <<< ... which initially points right back here
   0x000000000040056b <+11>:    jmp    0x400550
End of assembler dump. 
(gdb) x/g 0x601018
0x601018:   0x400566   <<< GOT point back right after the just-executed jump

这可以。现在,检查 .got.plt 部分0x601018,其中包含此指针返回0x400566显示二进制文件本身保存地址,动态链接器在加载时不执行任何操作。这是有道理的,因为这个地址在链接时是已知的:

$ readelf -x .got.plt ./prog 

Hex dump of section '.got.plt':
 NOTE: This section has relocations against it, but these have NOT been applied to this dump.
  0x00601000 ???????? ???????? ???????? ???????? ..`.............
  0x00601010 ???????? ???????? 66054000 ???????? ........f.@.....

(where 66054000是小端代表。为地址0x400566最初存储在GOT中)

很好,很好。但是之后...

$ readelf -r prog                             
<...>
Relocation section '.rela.plt' at offset 0x518 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000601018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 func1 + 0

Why is there a relocation entry for this GOT address? we've seen that the correct address is already there, in the binary, placed there at link time. I've also experimentally edited this relocation to make it ineffectual, and the program runs fine. So the reloc seems to contribute nothing. What is it doing there, and more generally what are the scenarios in which the relocations in rela.plt actually do matter?

更新#1:

需要明确的是,这是关于 PIC 代码和 64 位代码。以下是相关部分地址,以帮助阐明地址所属的位置:

$ readelf -S ./prog
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 9] .rela.dyn         RELA             00000000004004e8  000004e8
       0000000000000030  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400518  00000518
       0000000000000018  0000000000000018  AI       5    23     8
  [12] .plt              PROGBITS         0000000000400550  00000550
       0000000000000020  0000000000000010  AX       0     0     16
  [21] .dynamic          DYNAMIC          0000000000600e00  00000e00
       00000000000001f0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000600ff0  00000ff0
       0000000000000010  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000020  0000000000000008  WA       0     0     8

更新#2:

编辑节标题.rela.plt不会更改进程映像,因此我没有禁用重新定位。 我还尝试过更改 reloc 地址(更改为另一个可写地址),这似乎也没有什么区别,但事实证明,解析器在惰性绑定期间并未使用该地址,尽管 reloc 的其余部分是。仅当使用以下命令关闭惰性绑定时才使用地址本身LD_BIND_NOW.

谢谢@yugr


这可以。现在,检查 0x601018 处的 .got.plt 部分, 其中包含指向 0x400566 的指针显示 二进制文件本身保存地址,无需动态链接器 在加载时做任何事情。

并不真地。请注意,0x400566 处的代码最终跳转到 0x400550,即 16 个字节prior到 PLT 存根。 0x400550 处的代码会将 GOT 的地址压入堆栈并调用动态链接器。欲了解更多信息,请查看这个演示文稿 http://www.slideshare.net/kentarokawamoto/runtime-symbol-resolution(幻灯片 14)。

这是有道理的,因为这个地址在链接时是已知的

是吗?该地址将来自共享库,由于 ASLR,该共享库将在启动时加载到随机地址,因此静态链接器无法知道该地址...

为什么这个GOT地址会有重定位条目呢?

当 PLT 存根调用动态链接器时(第一次调用时),它会将 GOT 条目的地址传递给它。动态链接器将搜索 .rela.plt 以找出如何重新定位 GOT 条目(即函数名称和偏移量)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么链接器会在 .rela.plt 中生成看似无用的重定位? 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 如何在 Java 中从原始 byte[] 创建 BMP 文件

    我有一个 C 应用程序 它与相机通信并获取原始图像数据 然后我有一个 C 中的 Byte 我想用 JNI 将其发送到 Java 但是 我需要将原始 Byte 转换为真实的文件格式 bmp 是我的第一选择 如果我使用 BITMAPFILEIN
  • 从R中的循环返回单独的txt文件

    我想返回循环中每次迭代的结果 并将其写入单独的文本文件中 但由于某种原因 它似乎不起作用 我的代码是 for i in length traject player lt subset traject i subset dt 1 test l
  • 哪种排序方法最适合并行处理?

    我现在正在查看我以前的学校作业 想找到问题的答案 哪种排序方法最适合并行处理 冒泡排序 快速排序 归并排序 选择排序 我想快速排序 或合并排序 就是答案 我对么 与合并排序一样 快速排序由于其分而治之的性质也可以轻松并行化 单独的就地分区操
  • 通过 List 发布多个文件

    我只想通过模型将多个文件发布到控制器 class myModel public List
  • Android MediaPlayer 未从prepareAsync 返回

    我在使用特定 URI 启动 MediaPlayer 的 Logcat 中得到以下信息 通常 每个 Uri 无论好坏 都会播放或返回错误 除了这个特定的 Uri I MPS PrepAsync started V MediaPlayer me
  • 如何在 F# 中编写函子在 OCaml 中执行的操作的代码?

    我有很多用 OCaml 编写的程序 其中一些使用函子 现在 我正在考虑用 F 编写和重写部分代码 以受益于 OCaml 不具备的一些优点 我担心的一件事是在 F 中编写函子在 OCaml 中执行的操作的代码 例如 我们如何模仿这个例子来自
  • 在 PHP 开关中使用 strstr

    我只是想不出代码 我有太多 if 语句 我想将其更改为 switch 语句 但我找不到逻辑 目前我有 if strstr var texttosearch echo string contains texttosearch if strst
  • org.h2.jdbc.JdbcSQLException:未找到列“ID”

    我的代码中有以下 DDL CREATE TABLE IF NOT EXISTS SOMETABLE id BIGINT AUTO INCREMENT NOT NULL FOREIGN KEY id REFERENCES OTHERTABLE
  • Javascript (MVC) 从数据库加载图像(字节数组)

    Stack 上有很多这个问题的答案 但没有一个对我有用 我需要通过对控制器的 ajax 调用检索字节数组 在 javascript 中设置图像标签的 src 属性 我必须在客户端执行此操作 因为我正在动态构建一些 html 在下面的简单示例
  • 如何在 ASP.Net 中转储响应标头

    我正在使用 VSTS 2008 C Net 3 5 来开发 ASP Net 我想转储特定 aspx 文件返回给客户端的所有响应标头 有什么想法可以轻松做到这一点吗 我知道如何使用 Response Headers 集合 但我的困惑是在哪里枚
  • 如何告诉屏幕阅读器链接已禁用?

    我有一个页面n部分 这些部分是隐藏的 只能通过单击各自的链接来显示 页面加载时 只有第一个链接处于活动状态 其余 n 1 个链接处于活动状态href 基于某种逻辑 其他链接被单独激活 如何让屏幕阅读器理解该链接是disabled or 停用
  • Handsontable:隐藏一些列而不更改数据数组/对象

    我有一个数据要在网格中显示 我正在使用 Handsontable 来显示数据 每个第三列都计算为前两列的差值 例如 第三列渲染为第一列和第二列的总和 这是由自定义渲染器通过取总和来完成的i 1 and i 2列 这是我的 差异 列的自定义渲
  • React - Axios 调用发出太多请求

    我通过制作游戏项目来学习 React 和 Redux 我想通过API获取数据 属性 但它导致太多请求 我猜它可以与直接在功能性反应组件中放置 axios 调用有关 但我不知道如何修复它 function Attributes attribu
  • 如何在 Android 中下载并保存图像

    如何在 Android 中从给定的 URL 下载并保存图像 编辑截至 2015 年 12 月 30 日 图像下载终极指南 最后一次重大更新 2016 年 3 月 31 日 TL DR 又名 别再说了 给我代码吧 跳到这篇文章的底部 复制Ba
  • 如何将前导零的数字转换为字符串并保留原​​始数字

    我正在尝试将以 0 开头的数字转换为字符串 例如 变量 x 01127160037 but when I convert it to string it become 157081631 我期望得到字符串中 01127160037 的实际结
  • 页面刷新后QWebEngineView问题

    当我切换用户代理时问题就解决了 但不知怎的 当我刷新页面或从whatsapp注销时它又回来了 我已经实现了一个用户代理打印机来检查用户代理是否重置回来 但事实并非如此 如何我能解决这个问题吗 code import sys from PyS
  • Java - 检查 JTextField 是否为空

    所以我知道这是一个很受欢迎的问题并且已经找到了解决方案 但当我尝试这样做时 它无法正常工作 我的 JTextField 为空并且按钮未启用 当我在文本字段中写入内容时 按钮不会启用 所以我的程序应该每秒检查该字段是否为空 一旦有人在文本字段
  • ORA-06550 和 PLS-00103

    HI 我正在使用 UNIX 操作系统并在 oracle 上工作 我收到以下错误消息 E ORA 06550 line 1 column 8 PLS 00103 Encountered the symbol when expecting on
  • 将多个文件夹压缩为 1 个 zip - Google 云端硬盘脚本

    我想为 Google Drive 制作一个脚本 我想每周备份我的文件夹并将它们存储在 Google 云端硬盘中的另一个文件夹中 关于每周触发 我已经可以了 但是我遇到了问题 因为我找不到压缩整个文件夹的方法 我要压缩的文件夹有多个子文件夹和
  • 为什么链接器会在 .rela.plt 中生成看似无用的重定位?

    首先 我正在玩的玩具程序 prog c int func1 int main int argc char const argv func1 return 0 lib c int func1 return 0 构建 gcc O3 g shar