在 Android L 上运行本机库错误:仅支持位置无关的可执行文件 (PIE)

2023-12-19

当我在 Android L (Nexus 5) 上运行本机代码时,出现错误。

错误:仅支持位置无关的可执行文件 (PIE)。

相同的代码在我的 Samsung Galaxy S3 (Android 4.3) 上正确执行。

这是我的Application.mk

APP_PROJECT_PATH := $(call my-dir)/..
APP_ABI := armeabi
NDK_TOOLCHAIN_VERSION := 4.7
APP_PLATFORM := android-9
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti

但是当我更换时APP_PLATFORM := android-9 with APP_PLATFORM := android-16(当我读到here https://www.duosecurity.com/blog/exploit-mitigations-in-android-jelly-bean-4-1,PIE 支持出现在 Jelly Been(API 级别 16)中,相同的可执行文件在 Android L 上运行良好。

有没有办法使用编译本机代码APP_PLATFORM := android-9并在 Android L 上运行?


如果您可以接受仅支持 Android 4.1+,只需设置APP_PLATFORM := android-16你就可以出发了。它在幕后设定APP_PIE := true。您的二进制文件在较旧的 SDK 上会出现段错误。

如果您还需要支持较低的 SDK 级别,则需要创建两个二进制文件。我看到的其他一些答案建议使用不同的 APP_PLATFORM 维护两个单独的源树,但您不需要这样做。可以使单个 Android.mk 输出 PIE 和非 PIE 二进制文件。

NDK 10c 及更高版本:

确保默认情况下禁用 PIE,因为手动启用它比禁用它更容易。除非您的 APP_PLATFORM >=16,否则默认情况下不会启用 PIE。确保您的 APP_PLATFORM 未设置(默认为 android-3,或自 NDK 15 起的 android-14),低于 android-16,或已设置APP_PIE := false.

然后,以下 Android.mk 创建一个 PIE 和一个非 PIE 二进制文件,但有一个警告(见下文):

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Enable PIE manually. Will get reset on $(CLEAR_VARS). This
# is what enabling PIE translates to behind the scenes.
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie

LOCAL_MODULE := mymod

LOCAL_SRC_FILES := \
    mymod.c

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_MODULE := mymod-nopie

LOCAL_SRC_FILES := \
    mymod.c

include $(BUILD_EXECUTABLE)

然后,您必须添加某种逻辑来调用代码中正确的二进制文件。

不幸的是,这意味着您必须编译可执行模块两次,这可能会很慢。您还需要指定 LOCAL_SRC_FILES 和任何库两次,这可能会令人沮丧且难以跟踪。您可以做的是将主可执行文件编译为静态库,然后仅从该静态库构建可执行文件。静态库不需要 PIE。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := mymod-common

LOCAL_SRC_FILES := \
  mymod.c

include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)

# Enable PIE manually. Will get reset on $(CLEAR_VARS). This
# is what enabling PIE translates to behind the scenes.
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie

LOCAL_MODULE := mymod

LOCAL_STATIC_LIBRARIES := mymod-common

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_MODULE := mymod-nopie

LOCAL_STATIC_LIBRARIES := mymod-common

include $(BUILD_EXECUTABLE)

尽管仍然需要一定量的样板文件,但这似乎工作得很好。

NDK 10b:

NDK 10b 默认启用 PIE,并且不允许您禁用它,除非有可怕的黑客攻击。真的,只需更新到 10c 即可。我将旧的答案留在这里供参考,但我不会向任何人推荐它。

LOCAL_PATH := $(call my-dir)

# Forcefully disable PIE globally. This makes it possible to
# build some binaries without PIE by adding the necessary flags
# manually. These will not get reset by $(CLEAR_VARS). PIE is
# force-enabled on NDK 10b so we'll need this even if APP_PIE
# is set to false.
TARGET_PIE := false
NDK_APP_PIE := false

include $(CLEAR_VARS)

# Enable PIE manually. Will get reset on $(CLEAR_VARS). This
# is what enabling PIE translates to behind the scenes.
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie

LOCAL_MODULE := mymod

LOCAL_SRC_FILES := \
    mymod.c

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_MODULE := mymod-nopie

LOCAL_SRC_FILES := \
    mymod.c

include $(BUILD_EXECUTABLE)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Android L 上运行本机库错误:仅支持位置无关的可执行文件 (PIE) 的相关文章

随机推荐