首页 > 解决方案 > 位置无关的可执行文件和固定入口点地址

问题描述

可以从虚拟地址空间内的任意地址加载和运行与位置无关的 ELF 可执行文件。

我尝试构建以下简单程序:

馅饼.c

#include <stdio.h>

void main(void)
{
    printf("hello, pie!\n");
}

构建命令:

gcc pie.c -o pie -pie

可执行文件的 ELF 标头是:

馅饼

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x530 <================= FIXED entry point
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6440 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

所以入口点地址是固定的。

它是_start那里的符号:

0000000000000530 T _start

所以这意味着_start必须放在0x530.

这与位置独立不是矛盾的吗?

2021 年 8 月 16 日上午 10 点 44 分添加

我试图在没有-pie标志的情况下构建相同的程序:

gcc pie.c -o pie_not

生成的 ELF 头是:

pie_not

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x530  <============ Still the same value as with -pie flag
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6440 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

我进一步比较了构建的结果piepie_not. 它们的二进制文件是相同的。

那么操作系统如何判断哪一个应该被视为与位置无关的代码呢?

添加 2 - 2021 年 8 月 16 日上午 10:56

我想我想通了。似乎 gcc-pie默认使用。为避免这种情况,我必须-no-pie明确添加标志。

gcc pie.c -o pie_not -no-pie

而生成的ELF头是这样的:

pie_not

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file) <==== File type also changed!!!
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400400 <===== Entry point address changed!
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6376 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

我相信加载器依赖于 ELF 标头中的类型来决定如何处理二进制文件。

标签: gccposition-independent-code

解决方案


对于与位置无关的可执行文件,ELF 标头中的入口点地址不用作入口点的绝对地址。相反,它被用作与随机选择的基地址的偏移量。

因此,在您的示例中,如果基地址被随机选择为0x567812340000,则执行将从绝对地址开始0x567812340530


推荐阅读