Clang 不会剥离本地静态库的符号

l33*_*33t 2 clang android-ndk

使用Android NDK r18b(使用clang工具链)和Android Studio 3.2.1.

我的相关部分mylib.gradle

task ndkBuild(type: Exec) {
    commandLine "${ndkDir}/ndk-build${ndkExt}"
}
Run Code Online (Sandbox Code Playgroud)

我的Application.mk

APP_PLATFORM := android-17
APP_ABI := armeabi-v7a
# APP_OPTIM := release
APP_CFLAGS += -D_BSD_SOURCE
Run Code Online (Sandbox Code Playgroud)

和我的相关部分Android.mk

include $(CLEAR_VARS)

LOCAL_PATH := $(BASE_PATH)
LOCAL_MODULE := mylib_jni

LOCAL_STATIC_LIBRARIES := \
  lib1 \
  lib2

LOCAL_WHOLE_STATIC_LIBRARIES := \
  mylib_wrap \
  other_wrap

include $(BUILD_SHARED_LIBRARY)
Run Code Online (Sandbox Code Playgroud)

静态库mylib_jni.so构建成功。然后我运行以下命令(来自 NDK):

arm-linux-androideabi-readelf -a mylib_jni.so


未剥离的符号

在输出中,我可以看到lib1and中所有非静态方法的名称lib2(不是上面可以看到的整个库)。这怎么可能?如何从ndk-build命令中获取一些输出,并提供有关为什么不剥离符号的信息?(我找不到options.txt我的 NDK 构建步骤。)

Ale*_*ohn 7

恐怕您对stripvisibility=hidden感到困惑。

前者是在建立共享库的独立,后连接器,步。它的目的是通过删除链接器为调试目的留下的一些额外信息来减小文件的大小(将被打包到 APK 中)。请注意,当所有模块的本机库合并在一起时,gradle(在 Android Studio 3.2+ 中)甚至会在稍后执行此条带。

Strip 影响文件的大小,但不影响符号的可见性

隐藏符号是另一种减小二进制文件大小的技术。还强烈建议这样做,以减少您的库暴露于逆向工程。

默认情况下不会发生这种情况。您必须显式添加此编译器标志:

APP_CFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
Run Code Online (Sandbox Code Playgroud)

您可以将其与丢弃未使用的函数结合起来:

APP_CFLAGS += -ffunction-sections -fdata-sections
APP_LDFLAGS += -Wl,--gc-sections
Run Code Online (Sandbox Code Playgroud)

您必须显式标记外部函数

__attribute__ ((visibility ("default")))
Run Code Online (Sandbox Code Playgroud)

幸运的是,多亏了jni.h,这个属性是为所有函数设置的JNIEXPORT

如果您使用预构建的静态库,您可能还需要

APP_LDFLAGS += -Wl,--exclude-libs,ALL
Run Code Online (Sandbox Code Playgroud)

还考虑提供版本脚本

LOCAL_LDFLAGS += -Wl,-version-script -Wl,mylib_jni.vs
Run Code Online (Sandbox Code Playgroud)