Remove all symbols except "no_mangle extern" ones in Rust's `staticlib`? (since it is to be used by C program and all other symbols are useless)

I am building a static lib (.a) from some Rust code, and this .a file will be used (linked) by an iOS app. However, that .a file contains tons of symbols - Rust functions that are only to be used internally instead of exposing to the iOS app. Indeed, the Rust code uses #[no_mangle] pub extern "C" fn to expose the apis that will be used by the iOS app. All other functions will never be used and should not appear in the final app.

Therefore, I wonder how can I remove all symbols except "no_mangle extern" ones in Rust's staticlib?

Thanks for any suggestions!

Are you actually running nm or objdump on the final app? Just because a symbol appears in a static library doesn't really have any bearing on whether it ends up in the final executable binary...

1 Like

That is a good question.

  • For android: Yes, the .so file extracted from the release apk file. I see lots of such symbols.
  • For ios: Yes and no. From previous experience (C++ part of app already on app store) I guess they still exist; and by logic thinking, since I forbid xcode to strip symbols (to allow Flutter find the C-compatible ones by string), and since I look at .a and see lots of should-be-stripped symbols, I think they should exist there.

Make sure you understand the difference between stripping symbols and link-time optimization (lto). LTO (which Xcode does in its release profile) will, depending on the optimizer profile i.e. speed or size (speed is the default for an iOS project), either inline code and remove unused code or just remove unused code, respectively. Symbols are metadata and are simply about providing visibility into text/data in the executable for linking and debugging. So they generally get carried up until the point where they can be discarded, which is usually the assembly of the final executable binary.

You can check your iOS app by performing an app store build and then looking in <DerivedData>/Products/App Store-iphoneos/[Foo | Frameworks/Bar.framework/Bar]

1 Like

For iOS: Try to pass --gc-sections to the linker. This is what rustc normally does. It removes all functions that are not reachable from an exported symbol.

For Android: Do you use dylib or cdylib as crate type? You should use the later as the former keeps all functions necessary for linking a rust crate against it and keeps the crate metdata (which contains a lot of useful information for reverse engineering programs, including all names for all public and private items, source spans, ...) Cdylib omits the crate metadata and only exports #[no_mangle] functions.

1 Like

@dcow-uno @bjorn3 Thanks! I will do more experiments on iOS according to your suggestions.

@bjorn3 I use cdylib. But it exports a lot of things besides nomangle indeed...

@bjorn3 More details about how I use cdylib but still see tons of symbols that should not be exported: stop exporting every symbol · Issue #37530 · rust-lang/rust · GitHub

Replied on that issue.

1 Like