8

我正在为 Android 5.0 重新编译一些可执行文件,因为它要求可执行文件是PIE. 我能够ARM在配置(使用独立工具链)时添加一些参数来重新编译它:

export CFLAGS="-I/softdev/arm-libs/include -fPIE"
export CPPLAGS="$CPPFLAGS -fPIE"
export CXXLAGS="$CXXFLAGS -fPIE"
export LDFLAGS="-L/softdev/arm-libs/lib -static -fPIE -pie"

ARM没有错误:

configure:3406: arm-linux-androideabi-gcc -o conftest -I/softdev/arm-libs/include -fPIE  -L/softdev/arm-libs/lib -static -fPIE -pie conftest.c  >&5
configure:3410: $? = 0

但是我无法做同样的事情,x86因为我收到了错误:

export CFLAGS="-I/softdev/x86-libs/include -fPIE"
export CPPLAGS="$CPPFLAGS -fPIE"
export CXXLAGS="$CXXFLAGS -fPIE"
export LDFLAGS="-L/softdev/x86-libs/lib -static -fPIE -pie"

错误:

configure:3336: i686-linux-android-gcc -I/softdev/x86-libs/include -fPIE  -L/softdev/x86-libs/lib -static -fPIE -pie conftest.c  >&5
/softdev/x86-toolchain-gcc4.8/bin/../lib/gcc/i686-linux-android/4.8/../../../../i686-linux-android/bin/ld: fatal error: -pie and -static are incompatible
collect2: error: ld returned 1 exit status
configure:3340: $? = 1

我需要静态链接可执行文件。出了什么问题,我该如何解决?

PS。还尝试使用来自 android ndk r9d 和 r10c 的 x86 独立工具链:

./make-standalone-toolchain.sh --toolchain=x86-4.8 --arch=x86 --install-dir=/softdev/x86-toolchain-gcc4.8-r9d --ndk-dir=/softdev/android-ndk-r9d/ --system=darwin-x86_64
4

4 回答 4

8

正如 gcc-8 或更高版本支持下的 n4sm 所述-static-pie,它使用 PIE 生成静态二进制文件。请注意,这是一个选项而不是两个选项。如果您尝试使用-static -pie它,它将不会按照您的想法进行。

我刚刚对 te.c 的休闲进行了快速测试:

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

运行arm-linux-androideabi-gcc -o conftest -static -FPIE -pie te.c不会产生错误。然而file -k conftest输出

conftest: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped

readelf -l conftest输出 Elf 文件类型为 DYN (Shared object file) 入口点 0x500 有 7 个程序头,从偏移量 52 开始

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x000e0 0x000e0 R   0x4
  INTERP         0x000114 0x00000114 0x00000114 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /system/bin/linker]
...

PHDR 和 INTERP 标头的存在表明 -pie 在 arm 编译器中以静默方式覆盖 -static。为什么会这样,我不知道,但我认为这是一个错误,当 -static 和 -pie 一起使用时不会发出警告。相反,像您这样的程序员会留下这样的错误印象,即这两个选项可以一起使用。

只是为了澄清这里唯一的行为差异是 x86 编译器在同时看到 --static 和 --pie 时出错,而 arm 版本会默默地忽略 --static 如果给出 --pie 。如果只给出一个这些,则两个编译器的行为是相同的。

于 2015-02-01T03:55:20.510 回答
1

如果 -pie 和 -static 同时给出,gcc 将发出意外错误。

-馅饼

在支持它的目标上生成与位置无关的可执行文件。为了获得可预测的结果,您还必须在指定此链接器选项时指定用于编译的同一组选项(-fpie、-fPIE 或模型子选项)。

-pie 实际上用 /system/bin/linker 用 INTERP 创建了一个 DYN 类型的 elf 文件

使用 -pie 编译的可执行文件

-静止的

在支持动态链接的系统上,这会阻止与共享库的链接。在其他系统上,此选项无效。

-static 创建一个没有INTERP的EXEC类型elf文件

于 2016-07-29T07:27:39.860 回答
1

现在可以直接使用 -static-pie 选项!

例如:

#include <stdio.h>

/* /tmp/test.c */

int main(int argc, char **argv) { 
    printf("Hello world!\n"); 
}

您只需使用 -static-pie 选项:

gcc /tmp/test.c -static-pie -o /tmp/test

使用 readelf 我们得到了这个:

  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000008158 0x0000000000008158  R      0x1000
  LOAD           0x0000000000009000 0x0000000000009000 0x0000000000009000
                 0x000000000009473d 0x000000000009473d  R E    0x1000
  LOAD           0x000000000009e000 0x000000000009e000 0x000000000009e000
                 0x00000000000284b8 0x00000000000284b8  R      0x1000
  LOAD           0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
                 0x0000000000005370 0x0000000000006a80  RW     0x1000
  DYNAMIC        0x00000000000c9c18 0x00000000000cac18 0x00000000000cac18
                 0x00000000000001b0 0x00000000000001b0  RW     0x8
  NOTE           0x00000000000002e0 0x00000000000002e0 0x00000000000002e0
                 0x0000000000000020 0x0000000000000020  R      0x8
  NOTE           0x0000000000000300 0x0000000000000300 0x0000000000000300
                 0x0000000000000044 0x0000000000000044  R      0x4
  TLS            0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
                 0x0000000000000020 0x0000000000000060  R      0x8
  GNU_PROPERTY   0x00000000000002e0 0x00000000000002e0 0x00000000000002e0
                 0x0000000000000020 0x0000000000000020  R      0x8
  GNU_EH_FRAME   0x00000000000ba130 0x00000000000ba130 0x00000000000ba130
                 0x0000000000001c8c 0x0000000000001c8c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
                 0x0000000000003220 0x0000000000003220  R      0x1

我不知道我们什么时候可以使用这个选项,但对我来说,我正在使用gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

于 2021-03-14T13:27:17.160 回答
-1

Google 的 NDK 工具包含一些关于 PIE 使用的信息。访问build/core/build-binary.mk,见第 209 行。它说:

# 为超出特定 API 级别的可执行文件启用 PIE,除非“-static”

我想,这是linux动态链接原理的限制。由于Android解释器(/system/bin/linker)在静态链接文件中决定加载哪个地址的elf文件没有解释器,所以elf文件会被linux内核映射到内存中固定地址。这是有关此更改Google 问题的讨论

如果我有任何错误,请弄清楚:)

于 2015-03-20T07:34:03.627 回答