Executando uma biblioteca nativa no Android L. erro: apenas a posição executáveis ​​independentes ( PIE) são suportadas

? Maksim Dmitriev @ | Original: StackOverFlow
---

Quando eu executar código nativo no Android L ( Nexus 5), eu recebo o erro .

erro: apenas a posição executáveis ​​independentes ( PIE) são suportados.

O mesmo código é executado corretamente em meu Samsung Galaxy S3 ( Android 4.3).

Aqui está o meu 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

No entanto, quando eu substituir APP_PLATFORM := android-9 com APP_PLATFORM := android-16 ( Como eu li https://www.duosecurity.com/blog/exploit-mitigations-in-android-jelly-bean-4-1, suporte PIE apareceu em Jelly sido ( nível API 16) ), o mesmo arquivo executável funciona bem no Android L.

Existe uma maneira de compilar o código nativo usando APP_PLATFORM := android-9 e executá-lo em L Android?

---

Top 5 Responder

1Maksim Dmitriev @

Eu construí dois arquivos executáveis ​​: um com APP_PLATFORM := android-9 e outro com APP_PLATFORM := android-16 . Para executar o código nativo em Java Eu preciso disso :

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
}
2Simo Kinnunen @

Se você pode viver com apenas apoiando 4.1+ Android, basta configurar APP_PLATFORM := android-16 e você vai ser bom para ir . Nos bastidores ele define APP_PIE := true . O seu binário vai segmento padrão em SDKs mais velhos.

Se você também precisa de apoiar os níveis mais baixos do SDK, você vai precisar para criar dois binários . Algumas outras respostas que eu já vi têm recomendado manter duas árvores de origem separadas com diferentes APP_PLATFORMs, mas você não precisa fazer isso. É possível fazer uma única saída Android.mk tanto um PIE e um binário não- PIE .

NDK 10c:

Certifique-se de que PIE é desativada por padrão, uma vez que lhe é mais fácil do que manualmente desabilitá-lo . PIE não fica ativada por padrão, a menos que seu APP_PLATFORM for> = 16 . Certifique-se de que o seu APP_PLATFORM não está definida ( inadimplente para android -3), mais baixa do que android -16, ou ajuste APP_PIE := false .

A seguir Android.mk então cria um PIE e um binário não- PIE, mas tem uma ressalva (veja abaixo) :

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)

Em seguida, você tem que adicionar algum tipo de lógica para invocar o binário correto em seu código.

Infelizmente, isso significa que você terá que compilar o módulo executável duas vezes, o que pode ser lento. Você também precisa especificar LOCAL_SRC_FILES e quaisquer bibliotecas por duas vezes, o que pode ser frustrante e difícil de acompanhar. O que você pode fazer é compilar o executável principal como uma biblioteca estática, e construir executáveis ​​a partir do nada, mas que a biblioteca estática. Bibliotecas estáticas não exigem 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)

Isso parece funcionar bastante bem, embora uma certa quantidade de padronizado é ainda necessária .

NDK 10b:

NDK 10b permite PIE por padrão e não permite que você desativá-lo, a não ser com hacks terríveis . Realmente, apenas atualizar a 10c . Estou deixando minha resposta velho aqui para referência, mas eu não recomendo a ninguém.

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)
3Kevin Cernekee @

O projeto Chromium lançou um https://chromium.googlesource.com/chromium/src.git/+/master/tools/android/run_pie/run_pie.c que permite binários TORTA para rodar em pré- JB Android libera . Note-se que o seu executável PIE requer algumas bandeiras extras para fazer este trabalho :

CFLAGS += -fvisibility=default -fPIE
LDFLAGS += -rdynamic -fPIE -pie

No meu caso, eu estava enviando ~ binários 2MB por 3 arquiteturas e não queria adicionar 6 MB de dados não comprimidos para o APK apenas para continuar a apoiar ICS. run_pie É extremamente pequeno ( 6-7kB ) para que ele caber a conta.

run_pie Não deve ser construído com as bandeiras torta, e ele não deve ser executado no Android 5.0+ ( porque, claro, os binários não TORTA são proibidos ) . Infelizmente, ele não pode ser construída estaticamente porque ele precisa estar ligado com -ldl e NDK só fornece uma versão compartilhada de que a biblioteca .

O lado Java poderia ser algo como :

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;
}

onde busybox é um executável PIE e vive no diretório de arquivos privada do app .

Veja também: discussões anteriores sobre este tema https://code.google.com/p/android-developer-preview/issues/detail?id=888 e http://forum.xda-developers.com/google-nexus- 5 / desenvolvimento / fix - ignorando -pie -security- check- t2797731 .