如果您可以接受仅支持 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)