GCC:-静态和-pie对于x86不兼容?
我正在为Android 5.0重新编译一些可执行文件,因为它要求可执行文件是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
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