GCC: -static and -pie are incompatible for x86?
Asked Answered
M

4

10

I'm recompiling some executable for Android 5.0 as it requires executables to be PIE. I was able to recompile it for ARM with just adding some arguments while configuring (with standalone toolchain):

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"

No error for 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

But i was unable to do the same for x86 as i'm getting error:

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"

error:

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

I need executables to be linked statically. What's wrong and how can i fix it?

PS. Also tried using x86 standalone toolchain from android ndk r9d and r10c:

./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
Mylonite answered 22/11, 2014 at 21:50 Comment(6)
Ian, author of "gold" linker says: sourceware.org/ml/binutils/2012-02/msg00247.html "On GNU/Linux a PIE is just an executable shared library. How would you implement a statically linked PIE?" and sourceware.org/ml/binutils/2012-02/msg00249.html "But linking with -pie really just generates a shared library. And a shared library requires ld.so.". Probably, on ARM you will have not the real static binary, but binary with ld.so interpreter. Test x86_64 too. You can link your libraries statically, but use dynamic libc (don't use -static option).Antechoir
i'm not sure how it works internally, but at least i can compile for ARM with both arguments and can't on X86. Compiled with "-static" file is 1,7mb and without it (test on x86) is only 400Kb. So it makes me feel "-static" is working even if having "-pie"Mylonite
Use file -k to check the binary type, and readelf -l to check INTERP section of ELF (if you have one, it is not the real static binary), and ldd to check linked libraries. I think your arm binary may be not real static binary.Antechoir
unfortunately i can't test now, but i've tried to compile without "-static" for arm and file was significantly smaller (400kb vs 1,7mb)Mylonite
-static may link several libraries into your binary; but what you should check - is the real type of "ELF" static or dynamic. I know that in glibc world -static sometime generates dynamic ELF. Use file -k and readelf -l (with |grep -A 2 INTERP) to check this; update the post with their output.Antechoir
I'm looking forward to hear updates on this!!Ablaze
S
9

As mentioned by n4sm below gcc-8 or later supports -static-pie which produces a static binary with PIE. Note that is one option not two. If you try to use -static -pie it will not do what you think.

I just did quick test with the fallowing in te.c:

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

Running arm-linux-androideabi-gcc -o conftest -static -FPIE -pie te.c produces no error. However file -k conftest outputs

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

readelf -l conftest outputs Elf file type is DYN (Shared object file) Entry point 0x500 There are 7 program headers, starting at offset 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]
...

The presence of the PHDR and INTERP headers indicates that -pie silently overrides -static in the arm compiler. Why this is I don't know but I would consider it a bug that no warning is given when -static and -pie are used together. Instead programmers like you are left with the false impression that the two options can be used to together on arm.

Just to clarify the only behavioral difference here is that the x86 compiler errors on seeing both --static and --pie whereas the arm version silently ignores --static if --pie is given. If only one these is given the behavior is the same for both compilers.

Saltigrade answered 1/2, 2015 at 3:55 Comment(4)
ok, so you just recommend to remove "-static" argument? Can you confirm it's working for x86 too?Mylonite
@Mylonite I was under the impression the x86 version errors if and only if both are given but I'll see check on this. Keep in mind that the arm version isn't actually building a static executable if -pie or -FPIE is supplied it just doesn't complain about it.Saltigrade
@Mylonite just updated the answer to clarify the difference hopefully answers your question. Otherwise I'm not quite sure what's being asked.Saltigrade
For toolchain testing, echo 'main(){}' > te.c usually works too.Torras
G
2

If -pie and -static are both given together, gcc will issue unexpected error.

-pie

Produce a position independent executable on targets that support it. For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option.

-pie actually create a DYN type elf file with INTERP with /system/bin/linker

executable compiled with -pie

-static

On systems that support dynamic linking, this prevents linking with the shared libraries. On other systems, this option has no effect.

-static create a EXEC type elf file with no INTERP

Grosswardein answered 29/7, 2016 at 7:27 Comment(0)
B
2

Now it's directly possible with the -static-pie option!

For example:

#include <stdio.h>

/* /tmp/test.c */

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

You have just to use the -static-pie option:

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

And with readelf we got this:

  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

I don't know since when we can use this option, but for me, I'm using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

Biogenesis answered 14/3, 2021 at 13:27 Comment(1)
Since gcc-8 gcc.gnu.org/bugzilla/show_bug.cgi?id=81498Rugger
G
0

Google's NDK tool contain some info about PIE usage. Visit build/core/build-binary.mk, see line 209. It says:

# enable PIE for executable beyond certain API level, unless "-static"

I guess, it is linux dynamic link principle's limit. Because Android interpreter (/system/bin/linker) determining which address elf file to be loaded in a static linked file has no interpreter, elf file will be mapped to memory into a fixed address by linux kernel. Here is a discuss about this change Google issue

If I have any mistake please figure it out:)

Giorgia answered 20/3, 2015 at 7:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.