【问题标题】:g++ -fPIC not producing position independent codeg++ -fPIC 不产生与位置无关的代码
【发布时间】:2016-12-24 09:17:05
【问题描述】:

我已阅读主题GCC -fPIC option

所以我创建了我的 testlib.cpp。

int foo(int num)
{   
    int result;

    if (num != 0)
    {
        result = 1;
    }
    else
    {
        result = 2;
    }

    return result;
}

当我编译为 g++ -c -o testlib.o testlib.cpp 并作为 g++ -fPIC -c -o testlib.o testlib.cpp testlib.o 对应的 objdump 是一样的:

objdump -d testlib.o -M intel

testlib.o:     file format elf32-i386

Disassembly of section .text:

00000000 <_Z3fooi>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 ec 10                sub    esp,0x10
   6:   83 7d 08 00             cmp    DWORD PTR [ebp+0x8],0x0
   a:   74 09                   je     15 <_Z3fooi+0x15>
   c:   c7 45 fc 01 00 00 00    mov    DWORD PTR [ebp-0x4],0x1
  13:   eb 07                   jmp    1c <_Z3fooi+0x1c>
  15:   c7 45 fc 02 00 00 00    mov    DWORD PTR [ebp-0x4],0x2
  1c:   8b 45 fc                mov    eax,DWORD PTR [ebp-0x4]
  1f:   c9                      leave  
  20:   c3                      ret   

我希望 jumpje 命令的参数地址在使用 -fPIC 编译时与位置无关。所以这两个objdumps应该是不同的。我哪里理解错了?

【问题讨论】:

  • 在 x86 中,短跳转(可以使用显式完整地址写入,但是那么它是 5 个字节而不是 2 个字节,没有理智的汇编程序会发出这样的指令。
  • @MatteoItalia,感谢您的评论!抱歉,我已经投了赞成票,但顺便撤销了我在智能手机上的投票,并且不能再次投票,因为 SO 禁止它。 :(((
  • 别担心,它一直在发生 =)

标签: c++ g++ dynamic-linking fpic


【解决方案1】:

-fPIC 在较新的gcc 版本中默认开启。即使没有选项,代码也是位置无关的:

eb 07                   jmp    1c <_Z3fooi+0x1c>

这是与位置无关的,查看 2 字节操作码,即使反汇编打印符号及其偏移量也是如此。

请注意,无论选项如何,编译器很可能会为这种短跳转生成与位置无关的代码。

所以这个标志现在不是很有用。但是您可以使用-fno-PIC 开关禁用PIC。

【讨论】:

  • 感谢您的回答。现在我明白这是与位置无关的代码:“74 09”表示进一步跳转 09 个字节,“eb 07”表示进一步跳转 07 个字节,对吧?但是现在我尝试编译为 g++ -fno-pic -c -o testlib.o testlib.cpp 并且仍然得到相同的 objdump。为什么 -fno-pic 不起作用?
  • 正确的 asm。你试过-fno-PIC 吗?也许它不适用于跳跃。
  • @Jean-FrançoisFabre "-fPIC 在较新的 gcc 版本中默认启用" - 任何证明链接?
  • @Jean-FrançoisFabre,是的,我也试过 -fno-PIC。不幸的是,它也会产生相同的 objdump。
  • @yugr:已经够了。至少对于 x86 它没有效果:stackoverflow.com/questions/20637310/…。可能是因为在 x86 上编写 PIC 代码很容易(例如,相对于 68k,您无法写入相对于 PC 的内存,您必须使用地址寄存器)
【解决方案2】:

GCC 编译器没有能力故意生成与位置相关的代码。这种能力没有任何实际意义。

GCC 可以做的实际上是生成与位置无关的代码(带有-fPIC 选项)或“随便”代码(不带-fPIC 选项)。当您使用“whatever”模式时,编译器会简单地忽略位置依赖性问题,并将其关于代码生成的决定基于其他考虑因素。这意味着即使您没有请求-fPIC,您仍然可能很容易纯粹“偶然”地得到与位置无关的代码:因为碰巧位置无关的代码由于其他原因工作得最好(更紧凑,跑得更快等)

如果你想观察差异,你需要一个更有代表性的例子。在您的示例中,所有跳跃都接近跳跃。它们自然是通过相对(基于偏移的)跳转指令实现的。任何明智的编译器都会在这种情况下使用这种相对跳转。这样做的副作用是,即使您没有明确请求,您最终也会得到与位置无关的代码。在这种情况下,位置独立是“免费的”。

如果您想观察差异,您需要一个位置无关性不会“免费”出现的示例。您需要在位置独立性和其他重要因素(如效率和/或规模)之间进行明确权衡的东西。如果你想出这样一个例子,你就会看到-fPIC 的不同之处。

【讨论】:

  • 非常感谢您的回答。这是非常明智的。但是,在另一个答案中,建议使用 -fno-PIC 编译器选项来获取与位置相关的代码。我试过了,但没有帮助。你能就这一点发表评论吗?我真的很想看看位置相关的代码。
  • @JenyaKh:正如我上面所说,这是不可能的(对于你的例子)。您只能向 GCC 请求以下两件事之一:“我想要与位置无关的代码”(-fpic-fPIC,保证位置独立)或“我不在乎”(-fno-pic-fno-PIC ,不保证位置独立性)。无论您使用什么选项,您都只能在这两种模式之间切换。没有选项可以让 GCC 以某种方式故意强制其生成的代码“依赖于位置”。这样的选择根本没有意义。如果你想看到不同 - 你需要一个不同的例子。
猜你喜欢
  • 2016-11-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2015-09-28
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多