gpt4 book ai didi

linux - 为什么 gcc 在显然不需要时生成 PLT?

转载 作者:行者123 更新时间:2023-12-02 02:26:38 24 4
gpt4 key购买 nike

考虑这段代码:

int foo();
int main() {
foo();
while(1){}
}

int foo() 在共享对象中实现。

使用 gcc -o main main.c -lfoo -nostdlib -m32 -O2 -e main --no-pic -L./shared 编译这段代码会得到以下对话框:

$ objdump -d ./main

./main: file format elf32-i386


Disassembly of section .plt:

00000240 <.plt>:
240: ff b3 04 00 00 00 pushl 0x4(%ebx)
246: ff a3 08 00 00 00 jmp *0x8(%ebx)
24c: 00 00 add %al,(%eax)
...

00000250 <foo@plt>:
250: ff a3 0c 00 00 00 jmp *0xc(%ebx)
256: 68 00 00 00 00 push $0x0
25b: e9 e0 ff ff ff jmp 240 <.plt>

Disassembly of section .text:

00000260 <main>:
260: 8d 4c 24 04 lea 0x4(%esp),%ecx
264: 83 e4 f0 and $0xfffffff0,%esp
267: ff 71 fc pushl -0x4(%ecx)
26a: 55 push %ebp
26b: 89 e5 mov %esp,%ebp
26d: 51 push %ecx
26e: 83 ec 04 sub $0x4,%esp
271: e8 fc ff ff ff call 272 <main+0x12>
276: eb fe jmp 276 <main+0x16>

具有以下重定位:

$ objdump -R ./main

./main: file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
00000272 R_386_PC32 foo
00001ffc R_386_JUMP_SLOT foo

注意:

  1. 代码是用--no-pic编译的,所以不是PIC
  2. .text 部分(main 函数)对 foo() 的调用不是通过 PLT。相反,它只是一个简单的 R_386_PC32 重定位,我假设它将在加载时直接重定位到 foo 函数的地址。这对我来说很有意义,因为代码不是 PIC,因此无需通过 PLT 添加额外的间接寻址。
  3. 即使未被使用,PLT 仍在生成中。 foo 的条目在那里,我们甚至有一个 R_386_JUMP_SLOT 重定位以在加载时在 GOT 中设置 foo 条目(这是PLT 指向)。

我的问题很简单:我没有看到代码中的任何地方都使用了 PLT,我也没有看到这里有必要,那么为什么 gcc 会创建它?

最佳答案

--no-pic不像-no-pie , 它似乎是 -fno-pic 的同义词或 -fno-pie影响代码生成但不影响链接。假设您的发行版的 GCC 默认创建一个 PIE,您正在创建一个 PIE,因此没有对 foo@plt 的调用转换。 .

我收到链接器警告 /tmp/ccyRsNtd.o: warning: relocation against 'getpid@@GLIBC_2.0' in read-only section '.text.startup'/warning: creating DT_TEXTREL in a PIE . (但是可执行文件确实可以运行,不像它是 64 位的,其中 call rel32 不能重定位到整个地址空间。)

是的,ld 构建了一个未使用的 PLT 条目出于某种原因,但您链接的方式完全不标准。


构建 PLT 的正常原因是:

ld链接非 PIE 时将转换 call foo进入call foo@plt而不是在每次加载程序时都需要运行时修复的每个调用点都包含文本重定位。

使用 -fno-plt获得更高效的 asm,特别是对于 64 位模式,其中甚至 PIE 代码也可以有效地直接引用 GOT。

为了做一个更简单的例子,我使用了 libc ( getpid ) 中的函数而不是自定义库。使用 gcc -fno-pie -no-pie -m32 -O2 foo.c 正常编译,我得到 5 字节 e8 d5 ff ff ff调用 rel32:call 8049040 <getpid@plt> .

但添加-fno-plt为此,我得到 6 字节 ff 15 f4 bf 04 08 call [disp32] - call DWORD PTR ds:0x804bff4 .不涉及 PLT,仅涉及用绝对地址引用的 GOT 条目。

无需运行时重定位;本页的.text部分可以保持“干净”作为可执行文件的文件支持的私有(private)映射。 (运行时重定位会弄脏它,如果内核想要驱逐该页面,则使其仅由交换空间支持。)

此外,它使用需要早期绑定(bind)的“正常”GOT 条目。这甚至适用于 -nostdlib -lc和不明智的-e main而不是称它为_start像一个正常人。由于它是一个动态链接的可执行文件,因此动态链接器会在您的入口点之前运行并设置 GOT。

关于linux - 为什么 gcc 在显然不需要时生成 PLT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65554551/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com