Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is libc++_static.a not compiled with -ffunction-sections and -fdata-sections #748

Closed
R1kk3r opened this issue Jul 19, 2018 · 14 comments

Comments

Projects
None yet
5 participants
@R1kk3r
Copy link

commented Jul 19, 2018

Description

When building my Android app with a native library, I chose to use c++_static instead of c++_shared because my code use only a subset (std::string, std:vector and std::map) of the c++ library. The idea was to decrease my APK size as much as possible. Since I have one native library only, using a static c++ library should be safe.

Somehow, it seems that the whole c++ library have been embedded inside my tiny native library. The flag --gc-sections has not effect and looking with objdump it seems that the object files of libc++_static.a were not compiled with -ffunction-sections -fdata-sections. Is there any reason for that?

Environment Details

  • NDK Version: ndk 16, ndk 17
  • Build system: cmake
  • Host OS: Mac
  • Compiler: Clang
  • ABI: arm64-v8a
  • STL: c++_static
  • NDK API level: 21
@enh

This comment has been minimized.

Copy link
Contributor

commented Jul 19, 2018

i think pirama is already looking at this in the context of openmp...

@DanAlbert DanAlbert added this to the r18 milestone Jul 19, 2018

@DanAlbert DanAlbert added the ndk-build label Jul 19, 2018

@DanAlbert

This comment has been minimized.

Copy link
Member

commented Jul 19, 2018

I noticed recently that ndk-build only uses -ffunction-sections by default, not -fdata-sections (it does --gc-sections). We use ndk-build to build libc++, so I just need to fix that.

@stephenhines

This comment has been minimized.

Copy link
Contributor

commented Jul 19, 2018

Although this makes things smaller for the .a files, it will make the .so files larger. Pirama is indeed looking at this for OpenMP, and it isn't clear that -fdata-sections is a win.

@DanAlbert

This comment has been minimized.

Copy link
Member

commented Jul 19, 2018

Although this makes things smaller for the .a files, it will make the .so files larger.

Isn't that only true if you forget --gc-sections?

@stephenhines

This comment has been minimized.

Copy link
Contributor

commented Jul 19, 2018

I'm talking about libc++_shared.so and things like that where you can't arbitrarily strip out functions that you aren't using. Yes, --gc-sections is often a nice win, but it has to be weighted against what the goals of the shared object are. For prebuilt libraries, you are going to see a different set of tradeoffs.

@pirama-arumuga-nainar

This comment has been minimized.

Copy link

commented Jul 19, 2018

While testing https://android-review.googlesource.com/c/toolchain/llvm_android/+/719087, I found that the static libraries in the Clang runtimes got bigger as expected. The shared libraries got smaller, as one would expect with gc-sections, for all architectures except aarch64.

@stephenhines hypothesizes that the stricter alignment requirements for functions in aarch64 gets carried to the shared library during linking, even though the functions don't get separate sections in the shared library. I have to verify this or identify a different cause. As mentioned in the previous comment, gc-sections does not get big wins in libraries like libc++.so, where every symbol is potentially useful.

@DanAlbert

This comment has been minimized.

Copy link
Member

commented Jul 19, 2018

I'm talking about libc++_shared.so and things like that where you can't arbitrarily strip out functions that you aren't using.

Ah, duh. I was thinking you meant the user's library.

@pirama-arumuga-nainar

This comment has been minimized.

Copy link

commented Jul 20, 2018

The shared libraries got smaller, as one would expect with gc-sections, for all architectures except aarch64.

The increase for aarch64 was against the current clang in r18. The difference stems due to changes unrelated to ffunction-sections - likely due to switching to lld. With LLD, the text and data sections are aligned to 64K and the libraries are larger by ~100K. So there shouldn't be any increase from adding these flags for libc++.

@stephenhines

This comment has been minimized.

Copy link
Contributor

commented Jul 20, 2018

There's another issue open about the huge alignment requirements. We could certainly lower that threshold for text/data and still preserve correctness. For libraries like this, perhaps that is more important.

@R1kk3r

This comment has been minimized.

Copy link
Author

commented Jul 20, 2018

Correct me if I'm wrong but -ffunction-sections and -fdata-sections basically create a section for each function (which allow stripping using --gc-sections afterwards). Thus, due to this section separation, I guess that some of the compiler optimisations cannot be applied anymore. I read somewhere that using such flags makes the code slower as well.

In my case, using the libc++.a instead of the libc++.so is mostly because of a size issue which makes sense to compile libc++.a with those flags. I may be wrong, but I don't think that the scenario where a project makes use of the whole libc++ API (in which case compiling without those flags could make sense since the whole code will be used anyway) is a common use case. Personally, I don't really care if the code is a bit slower.

On the other hand, compiling the libc++.so with those flags does not make sense to me since the purpose of the shared library is to offer a complete API set. In that case, those flags will just produce slower and maybe even bigger code.

@DanAlbert

This comment has been minimized.

Copy link
Member

commented Aug 9, 2018

Easy enough to do like has been suggested here for libc++: build all the sources twice, once with -ffunction-sections -fdata-sections for the static library and once without for the shared library.

It does make me wonder about our defaults though. Right now we default to -ffunction-sections but not -fdata-sections. I think on average the right thing to do is probably use both for static libraries and neither for shared libraries. That should produce the optimal result for everything except static libraries used via WHOLE_STATIC_LIBRARIES, but since we can't know how the library will be used it's probably best to assume that isn't the case and leave that to the user to optimize for if they need to.

Thoughts?

@pirama-arumuga-nainar

This comment has been minimized.

Copy link

commented Aug 9, 2018

I agree with the first suggestion to use the -f*-sections only for the static library.

As for the defaults, I don't think -fdata-sections is universally useful. If a function refers to multiple global data, each global needs its own section start address. Without -fdata-sections, there'd just be a reference to the data section and two offsets into it. https://stackoverflow.com/a/29951897 has a more detailed explanation. However, the flag is useful or a wash for libc++ since it has few, if any, global data.

So -ffunction-sections, while ensuring that --gc-sections is passed to the linker, seems like a good default.

OTOH, I could also make the case for not setting either and leaving the user to consider the trade-offs and opt into whatever behavior they want. Granted there's greater potential benefit (in terms of size) with setting this flag and a smaller potential disadvantage (in terms of execution speed).

I guess it all comes down to informed choice - if there's a best-practices guide for the NDK, this trade-off should be mentioned there.

@DanAlbert

This comment has been minimized.

Copy link
Member

commented Aug 10, 2018

Merged into r18.

@DanAlbert DanAlbert closed this Aug 10, 2018

halx99 pushed a commit to halx99/android-ndk that referenced this issue Sep 14, 2018

Explicitly build c++_static.
Test: ./checkbuild.py libc++
Bug: android-ndk/ndk#748
Change-Id: I744b500a2e532698617b83db28f1eba4f87f3102

halx99 pushed a commit to halx99/android-ndk that referenced this issue Sep 14, 2018

Explicitly build c++_static.
Test: ./checkbuild.py libc++
Bug: android-ndk/ndk#748
Change-Id: I744b500a2e532698617b83db28f1eba4f87f3102
(cherry picked from commit 332fe35)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.