GCC:-静态和-pie对于x86不兼容?

GCC:-静态和-pie对于x86不兼容?,gcc,android-5.0-lollipop,gcc4.7,Gcc,Android 5.0 Lollipop,Gcc4.7,我正在为Android 5.0重新编译一些可执行文件,因为它要求可执行文件是PIE。我能够为ARM重新编译它,只需在配置时添加一些参数(使用独立的工具链): 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 configu

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

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
我需要静态链接可执行文件。出了什么问题,我该如何解决

另外,还尝试使用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

我刚刚在te.c做了快速测试:

int main( int argc, const char* argv[] )
{
   return 0;
}
运行armlinux和androideabigcc-o conftest-static-FPIE-pie te.c不会产生错误。但是
文件-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(共享对象文件) 入口点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头的存在表明arm编译器中的-pie静默重写-static。这是为什么我不知道,但我会认为它是一个错误,当静态和-Py一起使用时不会发出警告。相反,像您这样的程序员给人的错误印象是,这两个选项可以在arm上一起使用


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

谷歌的NDK工具包含一些关于饼图用法的信息。 访问,参见第209行。它说:

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

我想,这是linux动态链接原则的局限。 因为Android解释器(/system/bin/linker)决定在静态链接文件中加载哪个地址的elf文件没有解释器,所以linux内核将elf文件映射到内存中的固定地址。 下面是关于这一变化的讨论


如果我有任何错误,请解决:)

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

-馅饼

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

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

-静止的

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


-静态创建一个EXEC类型的elf文件,无需INTERP

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

例如:

#include <stdio.h>

/* /tmp/test.c */

int main(int argc, char **argv) { 
    printf("Hello world!\n"); 
}
通过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

Ian,《黄金》链接器的作者说:“在GNU/Linux上,饼只是一个可执行的共享库。你如何实现静态链接的饼?”“但是与-pie链接实际上只是生成一个共享库。共享库需要ld.so。”。可能在ARM上,您将没有真正的静态二进制文件,而是使用ld.so解释器的二进制文件。也测试x86_64。您可以静态链接库,但使用动态libc(不要使用
-static
选项)。我不确定它在内部是如何工作的,但至少我可以用这两个参数为ARM编译,而不能在X86上编译。用“-static”文件编译的是1,7mb,而没有它(在X86上测试)的只有400Kb。因此,我觉得即使有“-pie”,也可以用“-static”文件使用
file-k
检查二进制类型,使用
readelf-l
检查ELF的INTERP部分(如果有,它不是真正的静态二进制),使用
ldd
检查链接库。我认为您的arm二进制文件可能不是真正的静态二进制文件。不幸的是,我现在无法测试,但我已尝试在没有“-static”的情况下编译arm,文件明显更小(400kb vs 1,7mb)-静态可能会将多个库链接到您的二进制文件中;但是你应该检查的是“ELF”的真正类型——静态或动态。我知道在glibc世界中,静态的会产生动态的ELF。使用
file-k
readelf-l
(使用
| grep-a2interp
)检查此项;用它们的输出更新帖子。好的,那么您建议删除“-static”参数?你能确认它也适用于x86吗?@4ntoine我觉得x86版本错误当且仅当两者都给出时,但我会检查这一点。请记住,如果提供了-pie或-FPIE,arm版本实际上并不是在构建一个静态可执行文件,它只是不抱怨而已。@4ntoine只是更新了答案以澄清差异,希望能回答您的问题。否则,我不太确定要问什么。对于工具链测试,
echo'main(){}>te.c
通常也能工作。因为gcc-8
  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