使用和不使用`-fPIC`编译的目标文件中的MWE

问题描述 投票:0回答:1

我正在使用

gcc
生成的目标文件进行一些实验。

虽然我至少表面上知道位置无关代码有什么用,但我试图具体地发现它。

我在文件中生成了这个简单的代码

timestwo.c

 int timestwo(int x)
 {
     return 2 * x;
 }

我编译的:

  • gcc -c timestwo.c
  • gcc -c -fPIC timestwo.c -o timestwo_pic.o

则生成的目标文件

timestwo.o
timestwo_pic.o
按位相同。还有
readelf -a
我看不出有什么区别。

您能否提供一个 MWE,让我可以看到

pic
和非
pic
代码之间的区别?

gcc executable object-files
1个回答
0
投票

现在,您的发行版的 GCC 编译器很可能默认生成 PIC 代码, 因此,为了确保它发出非 PIC 代码,您应该指定

-fno-PIC

无论如何,您不会看到示例代码(例如您的代码)有任何差异, 仅引用局部符号和/或常量。 PIC 仅在代码引用外部时起作用 符号 - 其运行时地址将是非位置无关的绝对值 程序,但对于位置无关的程序,将在运行时通过查找程序的全局偏移表(GOT)来计算, 它已由动态链接器使用其实际决定的符号地址进行了修补。

这是一个使用 -fPIC v. -fno-PIC 进行不同编译的基本文件:

$ cat file.c
extern int foo;

int bar()
{
    return foo;
} 


$ gcc -c -fno-PIC file.c -o file_no_PIC.o -save-temps
$ gcc -c -fPIC file.c -o file_PIC.o -save-temps

我指定

-save-temps
只是为了生成相应的程序集列表以进行比较。

对象二进制文件不同:

$ diff file_no_PIC.o file_PIC.o
Binary files file_no_PIC.o and file_PIC.o differ

以下是装配清单之间的差异:

$ diff file_no_PIC.s file_PIC.s
15c15,16
<   movl    foo(%rip), %eax
---
>   movq    foo@GOTPCREL(%rip), %rax
>   movl    (%rax), %eax

在非 PIC 代码中,只需将双字(32 位)从

foo
(相对于 PC)地址加载到
bar()
寄存器即可从
foo
返回
eax
。 在 PIC 代码中,它是通过首先将
foo
的全局偏移表值(PC 相对)地址处的 64 位加载到
rax
寄存器中来返回的 - 使得
rax
保存
foo
的运行时地址 - 然后将该地址处的 32 位(
int
)加载到
eax

© www.soinside.com 2019 - 2024. All rights reserved.