当我在Android (Nexus 5)上运行本机代码时,我会得到错误。
错误:只支持与位置无关的可执行文件(PIE)。
同样的代码在我的三星Galaxy S3 (Android4.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替换为APP_PLATFORM := android-16时(当我阅读这里时,PIE支持出现在Jelly ( appeared 16)中),同样的可执行文件在Android上工作得很好。
有没有一种使用APP_PLATFORM := android-9编译本机代码并在Android上运行的方法?
发布于 2014-07-22 06:18:51
我构建了两个可执行文件:一个使用APP_PLATFORM := android-9,另一个使用APP_PLATFORM := android-16。要在Java中运行本机代码,我需要这样做:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
// Run the file which was created using APP_PLATFORM := android-16
} else {
// Run the file which was created using APP_PLATFORM := android-9
}发布于 2014-10-17 10:17:32
如果你只支持Android 4.1+,只需设置APP_PLATFORM := android-16就可以了。它在幕后设置了APP_PIE := true。您的二进制文件将在旧的SDK上分割错误。
如果还需要支持较低的SDK级别,则需要创建两个二进制文件。我看到的其他一些答案建议用不同的APP_PLATFORMs维护两个独立的源树,但是您不需要这样做。可以使单个Android.mk输出为饼形和非饼形二进制。
NDK10c及更高版本:
确保默认情况下禁用饼图,因为手动启用它比禁用它容易。除非您的APP_PLATFORM是>=16,否则PIE默认不会启用。确保您的APP_PLATFORM没有设置(默认为Androd-3,或android-14,自NDK 15以来),低于android-16,或者设置APP_PIE := false。
然后,下面的Android.mk创建一个饼和一个非饼二进制(),但是有一个警告(见下文)。
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和任何库,这可能令人沮丧,而且很难跟踪。您可以做的是将主可执行文件编译成一个静态库,然后只从这个静态库构建可执行文件。静态库不需要饼饼。
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:
NDK10b默认启用饼,并且不允许禁用它,除非使用可怕的黑客。真的,更新到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)发布于 2014-12-29 17:45:23
Chromium项目发布了一个包装器,允许PIE二进制文件在JB发布前运行。请注意,为了使此工作,饼可执行文件需要一些额外的标志:
CFLAGS += -fvisibility=default -fPIE
LDFLAGS += -rdynamic -fPIE -pie在我的例子中,我为3种体系结构发送了~2MB二进制文件,并且不想为继续支持ICS而向APK添加6MB的未压缩数据。run_pie非常小(6-7kB),所以它符合要求。
run_pie不应该使用饼标志构建,也不应该在Android 5.0+上执行(当然,非饼类二进制文件是被禁止的)。不幸的是,它不能静态构建,因为它需要与-ldl链接,而且NDK只提供了该库的共享版本。
Java端看起来可能如下所示:
String dir = mContext.getFilesDir().getPath();
String command = dir + "/busybox netstat";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
command = dir + "/run_pie " + command;
}其中,busybox是一个饼形可执行文件,并生活在应用程序的私有文件目录中。
还请参阅:前面对本主题这里和这里的讨论。
编辑JFDee:在我的示例中,在使用饼式可执行文件运行run_pie时,我一直得到错误"dlopen() failed:无法加载库“。我必须显式地将LD_LIBRARY_PATH设置为可执行文件所在的目录,即当前路径。
在这种情况下,"run_pie“调用的修改示例代码行如下所示:
...
command = "LD_LIBRARY_PATH=. " + dir + "/run_pie " + command;
...https://stackoverflow.com/questions/24818902
复制相似问题