Android NDK aarch64构建中,全局符号表中存在本地符号“__bss_start”。

5

我正在使用 NDK(r19b)创建一个 Android 库,支持 armaarch64x86x86_64 架构。一切正常,只有在为 aarch64 架构构建应用程序时出现以下错误消息。

ld.lld: error: found local symbol '_edata' in global part of symbol table in file libmystuff.so
ld.lld: error: found local symbol '_end' in global part of symbol table in file libmystuff.so
ld.lld: error: found local symbol '__bss_start' in global part of symbol table in file libmystuff.so

当我使用 readelf -s libmystuff.so 检查每个构建变体时,我注意到只有 aarch64 不同。
[arm]
    4021: 007a30f0     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    4022: 007c6b10     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    4023: 007a30f0     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

[x86]
    3848: 00c82c88     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    3849: 00ca4b28     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    3850: 00c82c88     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

[x86_64]
    3874: 0000000000c9b890     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    3875: 0000000000ce5f68     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    3876: 0000000000c9b890     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

[aarch64]
       3: 0000000000b4f168     0 NOTYPE  LOCAL  DEFAULT  ABS _edata
       4: 0000000000b990e8     0 NOTYPE  LOCAL  DEFAULT  ABS _end
       5: 0000000000b4f168     0 NOTYPE  LOCAL  DEFAULT  ABS __bss_start

     865: 0000000000b9e3e8     0 NOTYPE  GLOBAL DEFAULT  ABS __end__
    2468: 0000000000b54168     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start__

我可以肯定地看到_edata_end__bss_start是LOCAL而不是GLOBAL的,但我没有(或者至少我认为我没有)对aarch64做任何特殊处理。它们都使用同样的构建配置。

jni/Application.mk
    NDK_TOOLCHAIN_VERSION := clang
    APP_STL := c++_static
    APP_CFLAGS := -fstack-protector-all -fvisibility=hidden -ffunction-sections -fdata-sections
    APP_CPPFLAGS := -fstack-protector-all -std=c++11 -fvisibility=hidden -ffunction-sections -fdata-sections -frtti
    APP_LDFLAGS := -Wl,--gc-sections,-fvisibility=hidden,--strip-debug

那么,为什么aarch64不同?更好的方法是如何将它们移至GLOBAL?

[更新] 感谢https://github.com/android-ndk/ndk/issues/927提供帮助,我发现最好的解决方案是注意在结尾处加上“-fuse-ld=lld”。

APP_LDFLAGS := -Wl,--gc-sections,--strip-debug -fvisibility=hidden -fuse-ld=lld

这样,我仍然可以保留--gc-sections,不需要使用--no-fatal-warnings。 【更新】 本问题中显示的示例正在使用ndk-build,如果您正在使用带有Gradle的Android Studio,那么您很可能会使用CMake。在这种情况下,请将编译器标志添加如下。
[app/build.gradle]
android {
    ...
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags '-fuse-ld=lld'
            }

好的,我正在使用Android Studio和Gradle。我需要编辑什么? - Edward Falk
请注意,自NDK r22起,LLD是默认的链接器:https://github.com/android/ndk/wiki/Changelog-r22 - Eyjafl
2个回答

3

APP_LDFLAGS := -Wl,-fvisibility=hidden

这个选项有什么作用呢?在bfd的帮助页面中并没有提到这个选项,但是链接器会发出这些符号,所以我想知道这是否是引起问题的原因。

如果不行的话,请尝试将-fuse-ld=gold(或者如果需要支持Windows KIs,则可以使用-fuse-ld=lld)添加到您的APP_LDFLAGS中。 在NDK中,arm64与其他架构最大的区别在于我们仍然使用bfd。

由于这些都是链接器发出的符号,所以这似乎是最有可能的罪魁祸首。


-fuse-ld=gold-fuse-ld=lld 均无效;_edata_end__bss_start 均在 LOCAL 中。我可能需要将其归咎于当前 NDK 的限制。 - solamour
是的,我刚刚注意到你一开始就在使用lld。这绝对很奇怪,而且修复方法也很奇怪。我已经为此提交了 https://github.com/android-ndk/ndk/issues/927。如果你能提供一个测试用例那就太好了(我还没有尝试过任何东西,所以甚至在一个简单的Hello World中也可能出现这种情况?) - Dan Albert
我不太确定如何为NDK提交缺陷,所以感谢您代表我完成了这项工作。我会看看是否能提供一个简单的测试用例来说明问题,尽管如果过于简单,可能很难重现该问题。 - solamour
我注意到的一件事是,如果没有使用 --gc-sections 选项,库的大小会略微增加,因此我的库可能存在我不再使用的残留代码,这可能导致了问题。 - solamour
1
^ 这是将构建失败转换为运行时失败的绝佳方式。 - Dan Albert
显示剩余3条评论

0

当我使用外部libExternal.so文件时,我遇到了这个问题。

由于我没有源代码,所以无法使用LLD重新构建它。

最终,通过在我的项目中禁用链接器警告,我成功地使用了libExternal.so文件。 这个链接对我非常有帮助 https://github.com/android/ndk/issues/927

我在AOSP(Android 10)中制作了一个JNI Android应用,该应用使用了一个sample.cpp文件,该文件使用了libExternal.so。 我的应用程序能够通过mm命令进行构建,并在设备上正常工作。

这是我在AOSP构建(Android 10)中使用的Android.mk文件。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := External
LOCAL_SRC_FILES := libExternal.so
LOCAL_MODULE_TAGS := samples
#LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
#LOCAL_LDFLAGS += -fuse-ld=gold
#LOCAL_EXPORT_LDFLAGS += -fuse-ld=gold
#LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true
include $(BUILD_PREBUILT)

include $(CLEAR_VARS)
LOCAL_MODULE := c++
LOCAL_SRC_FILES := libc++.so
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
#LOCAL_LDFLAGS += -fuse-ld=gold
#LOCAL_EXPORT_LDFLAGS += -fuse-ld=gold
#LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true
include $(BUILD_PREBUILT)

include $(CLEAR_VARS)
LOCAL_MODULE := libsample
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
#LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true
#LOCAL_CFLAGS += -Iinclude
LOCAL_SRC_FILES := sample.cpp
LOCAL_REQUIRED_MODULES := External
#LOCAL_SHARED_LIBRARIES := External cdsprpc cutils c++ base log
LOCAL_SHARED_LIBRARIES := External
LOCAL_MODULE_TARGET_ARCH := arm64
#LOCAL_MODULE_TARGET_ARCH := arm64-v8a
#LOCAL_LDLIBS += $(LOCAL_PATH)/libExternal.so
#https://stackoverflow.com/questions/65597460/how-to-restrict-android-mk-to-compile-a-module-to-generate-only-64bit-library
LOCAL_CFLAGS += -Wall -std=c99 -g
LOCAL_CPPFLAGS += -Wall -std=c++03 -D_GLIBCXX_USE_CXX11_ABI=0 -g
# Does not build even after commenting below line
#LOCAL_LDLIBS := -lm -lstdc++ -ldl
#LOCAL_LDFLAGS += -fuse-ld=gold
#LOCAL_EXPORT_LDFLAGS += -fuse-ld=gold
#include $(BUILD_EXECUTABLE)
LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true
LOCAL_LDFLAGS := -Wl,--no-fatal-warnings
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
res_dir := res $(LOCAL_PATH)/res
#LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS := samples
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dir))
LOCAL_USE_AAPT2 := true
LOCAL_JAVA_LIBRARIES := com.google.android.material_material
LOCAL_STATIC_ANDROID_LIBRARIES := \
        androidx.appcompat_appcompat \
        androidx-constraintlayout_constraintlayout \
        androidx.preference_preference \
        androidx.fragment_fragment \
        androidx.core_core
#LOCAL_REQUIRED_MODULES := sample External
LOCAL_REQUIRED_MODULES := External \
                           libsample \
                           libc++
LOCAL_SHARED_LIBRARIES := External \
                           libsample \
                           libc++
#LOCAL_LDLIBS += -lsample
LOCAL_JNI_SHARED_LIBRARIES := libsample libc++
#LOCAL_JNI_SHARED_LIBRARIES := libsample
#LOCAL_PREBUILT_JNI_LIBS := $(LOCAL_PATH)/libsample.so
LOCAL_PREBUILT_JNI_LIBS := libExternal.so
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PACKAGE_NAME := NativeCPP
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接