Mak*_*iev 52 android android-ndk
当我在Android L(Nexus 5)上运行本机代码时,我收到错误.
错误:仅支持位置独立可执行文件(PIE).
在我的三星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
Run Code Online (Sandbox Code Playgroud)
但是,当我替换APP_PLATFORM := android-9为APP_PLATFORM := android-16(正如我在这里阅读,PIE支持出现在Jelly Been(API级别16)),相同的可执行文件在Android L上正常工作.
有没有办法APP_PLATFORM := android-9在Android L上使用并运行它来编译本机代码?
Sim*_*nen 49
如果您只能支持Android 4.1+,那么只需设置APP_PLATFORM := android-16即可.它背后的场景APP_PIE := true.您的二进制文件将在较旧的SDK上进行分段.
如果您还需要支持较低的SDK级别,则需要创建两个二进制文件.我见过的其他一些答案建议使用不同的APP_PLATFORMs维护两个独立的源树,但是您不需要这样做.可以使单个Android.mk输出PIE和非PIE二进制文件.
NDK 10c及更高版本:
确保默认情况下禁用PIE,因为手动启用它比禁用它更容易.默认情况下,PIE不会启用,除非您的APP_PLATFORM> = 16.确保您的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)
Run Code Online (Sandbox Code Playgroud)
然后,您必须添加某种逻辑来调用代码中的正确二进制文件.
不幸的是,这意味着你必须两次编译可执行模块,这可能很慢.您还需要两次指定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)
Run Code Online (Sandbox Code Playgroud)
虽然仍然需要一定量的样板,但这似乎工作得很好.
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)
Run Code Online (Sandbox Code Playgroud)
小智 14
Chromium项目发布了一个包装器,允许PIE二进制文件在JB之前的Android版本上运行.请注意,您的PIE可执行文件需要一些额外的标志才能使其工作:
CFLAGS += -fvisibility=default -fPIE
LDFLAGS += -rdynamic -fPIE -pie
Run Code Online (Sandbox Code Playgroud)
在我的情况下,我为3个架构运送了大约2MB的二进制文件,并且不想向APK添加6MB的未压缩数据以继续支持ICS. run_pie是非常小(6-7kB)所以它符合要求.
run_pie应该不与PIE标志建成,它应该不会在Android上执行5.0以上(因为,当然,非PIE二进制文件禁止).不幸的是,它不能静态构建,因为它需要链接,-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;
}
Run Code Online (Sandbox Code Playgroud)
哪里busybox是PIE可执行文件并存在于应用程序的私有文件目录中.
编辑JFDee:在我的情况下,当我使用PIE可执行文件运行run_pie时,我不断收到错误"dlopen()失败:无法加载库".我必须将LD_LIBRARY_PATH显式设置为可执行文件所在的目录,即当前路径.
在这种情况下,"run_pie"调用的修改示例代码行将如下所示:
...
command = "LD_LIBRARY_PATH=. " + dir + "/run_pie " + command;
...
Run Code Online (Sandbox Code Playgroud)
我构建了两个可执行文件:一个用于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
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
84535 次 |
| 最近记录: |