web-dev-qa-db-fra.com

Comment le code natif Android écrit pour ARM courir sur x86?

Motorola vient de sortir un téléphone Android basé sur x86. Je suis un peu confus quant à la façon dont les applications/bibliothèques natives écrites pour ARM (netflix par exemple) peuvent fonctionner sur ce téléphone.

Je serais reconnaissant si quelqu'un pouvait expliquer.

30
Ayush

Oui, le code natif ARM fonctionne sur Intel x86 à l'aide d'une fonction d'émulation nommée Houdini

Cette bibliothèque lit les instructions ARM à la volée et les convertit en instructions x86 équivalentes. C'est la raison pour laquelle de nombreuses applications peuvent fonctionner telles quelles sur x86 sans avoir à créer une bibliothèque équivalente.

enter image description here

52
Royston Pinto

Vous pouvez réellement inclure différents codes natifs pour différentes architectures, vous ne savez pas comment Netflix fonctionne, mais si vous ouvrez apk, vous pouvez voir /lib/armeabi-v7a/. Je suppose donc qu'il peut exister un dossier du type /lib/x86/

Edit: Je viens de vérifier l’application Amazon Shopping, elle possède un code natif pour arm et x86. Alors peut-être que Netflix le fait aussi.

9
nandeesh

L'émulateur Android Studio 3 utilise QEMU comme backend

https://en.wikipedia.org/wiki/QEMU

QEMU est sans doute le premier émulateur cross-open open source. Il s’agit d’un logiciel sous licence GPL, qui prend en charge de nombreux autres archs en plus de x86 et d’ARM.

Ensuite, Android ajoute juste un peu de magie d’interface utilisateur au-dessus de QEMU et éventuellement des correctifs, mais le noyau est définitivement dans QEMU en amont.

QEMU utilise une technique appelée traduction binaire pour obtenir une émulation relativement rapide: https://en.wikipedia.org/wiki/Binary_translation

La traduction binaire traduit essentiellement ARM - instructions en instructions x86 équivalentes.

Par conséquent, pour comprendre les détails, le meilleur moyen consiste à:

  • lisez le code source QEMU: https://github.com/qemu/qemu
  • étudiez la traduction binaire en général, écrivez éventuellement votre propre implémentation de jouet

Théorie

  • Les processeurs sont " Turing complete " (dans les limites de la mémoire)
  • Les processeurs ont un comportement déterministe simple qui peut être simulé avec des machines de Turing à mémoire finie

Par conséquent, il est clair que tout processeur peut émuler tout processeur doté de suffisamment de mémoire.

La question difficile est de savoir comment faire cela rapide.

Pratique: Simulation en mode utilisateur QEMU

QEMU a un mode utilisateur qui permet de jouer très facilement avec userland ARM - code sur votre ordinateur x86 pour voir ce qui se passe, tant que votre invité et votre hôte utilisent le même système d’exploitation.

Dans ce mode, la traduction binaire prend en charge les instructions de base et les appels système sont simplement redirigés vers les appels du système hôte.

Par exemple, pour Linux sur Linux avec un monde de salut indépendant de Linux (sans glibc):

main.S

.text
.global _start
_start:
asm_main_after_prologue:
    /* write */
    mov x0, 1
    adr x1, msg
    ldr x2, =len
    mov x8, 64
    svc 0

    /* exit */
    mov x0, 0
    mov x8, 93
    svc 0
msg:
    .ascii "hello syscall v8\n"
len = . - msg

GitHub en amont .

Puis assemblez et exécutez en tant que:

Sudo apt-get install qemu-user gcc-aarch64-linux-gnu
aarch64-linux-gnu-as -o main.o main.S
aarch64-linux-gnu-ld -o main.out main.o
qemu-aarch64 main.out 

et il produit le résultat attendu:

hello syscall v8

Vous pouvez même exécuter ARM - des programmes compilés avec la bibliothèque standard C, puis déboguer le programme par GDB! Voir cet exemple concret: Comment procéder en une seule étape ARM Assemblage dans GDB sur QEMU?

Puisque nous parlons de traduction binaire, nous pouvons également permettre à certains utilisateurs de voir la traduction exacte effectuée par QEMU:

qemu-aarch64 -d in_asm,out_asm main.out

Ici:

  • in_asm fait référence à l'assembly ARM input input
  • out_asm fait référence à l'assemblage généré par l'hôte X86 qui est exécuté

La sortie contient:

----------------
IN: 
0x0000000000400078:  d2800020      mov x0, #0x1
0x000000000040007c:  100000e1      adr x1, #+0x1c (addr 0x400098)
0x0000000000400080:  58000182      ldr x2, pc+48 (addr 0x4000b0)
0x0000000000400084:  d2800808      mov x8, #0x40
0x0000000000400088:  d4000001      svc #0x0

OUT: [size=105]
0x5578d016b428:  mov    -0x8(%r14),%ebp
0x5578d016b42c:  test   %ebp,%ebp
0x5578d016b42e:  jne    0x5578d016b482
0x5578d016b434:  mov    $0x1,%ebp
0x5578d016b439:  mov    %rbp,0x40(%r14)
0x5578d016b43d:  mov    $0x400098,%ebp
0x5578d016b442:  mov    %rbp,0x48(%r14)
0x5578d016b446:  mov    $0x4000b0,%ebp
0x5578d016b44b:  mov    0x0(%rbp),%rbp
0x5578d016b44f:  mov    %rbp,0x50(%r14)
0x5578d016b453:  mov    $0x40,%ebp
0x5578d016b458:  mov    %rbp,0x80(%r14)
0x5578d016b45f:  mov    $0x40008c,%ebp
0x5578d016b464:  mov    %rbp,0x140(%r14)
0x5578d016b46b:  mov    %r14,%rdi
0x5578d016b46e:  mov    $0x2,%esi
0x5578d016b473:  mov    $0x56000000,%edx
0x5578d016b478:  mov    $0x1,%ecx
0x5578d016b47d:  callq  0x5578cfdfe130
0x5578d016b482:  mov    $0x7f8af0565013,%rax
0x5578d016b48c:  jmpq   0x5578d016b416 

ainsi, dans la section IN, nous voyons notre écriture manuscrite ARM code d'assemblage, et dans la section OUT, nous voyons l'assembly x86 généré.

Testé sous Ubuntu 16.04 AMD64, QEMU 2.5.0, binutils 2.26.1.

Emulation de système complet QEMU

Cependant, lorsque vous démarrez Android dans QEMU, il ne s'agit pas d'un binaire utilisateur, mais d'une simulation complète du système, qui exécute le noyau Linux et tous les périphériques de la simulation.

La simulation du système complet est plus précise, mais un peu plus lente, et vous devez donner une image de noyau et de disque à QEMU.

Pour l'essayer, jetez un coup d'œil aux configurations suivantes:

KVM

Si vous utilisez Android X86 sur QEMU, vous remarquerez que le processus est beaucoup plus rapide.

La raison en est que QEMU utilise KVM , qui est une fonctionnalité du noyau Linux pouvant exécuter les instructions de l’invité directement sur l’hôte!

Si vous possédez une puissante ARM - machine (encore rare en 2019), vous pouvez également exécuter ARM sur ARM avec KVM Plus vite.

Pour cette raison, je vous recommande de vous en tenir à la simulation AOSP X86 si vous êtes sur un hôte X86, sauf si vous devez vraiment toucher à quelque chose de bas niveau.

Dans Trend Micro Safe Mobile Workforce , nous avons un environnement d'exécution ARM (pas houdini d'Intel) pour la bibliothèque native dans les applications Android. Ainsi, nous pouvons prendre en charge l'exécution de APK avec seulement ARM lib sur un puissant serveur x86.

0
Sun Junwen