30

摩托罗拉刚刚发布了一款基于 x86 的 Android 手机。对于为 ARM(例如 netflix)编写的本机应用程序/库如何在这款手机上运行,​​我有点困惑。

如果有人可以解释,我将不胜感激。

4

4 回答 4

55

是的,ARM 本机代码使用名为Houdini的仿真功能在 Intel x86 上运行

这个库所做的是动态读取 ARM 指令并将它们转换为等效的 x86 指令。这就是为什么许多应用程序可以在 x86 上按原样运行而无需实际构建等效库的原因。

在此处输入图像描述

于 2012-10-22T05:44:53.343 回答
9

您实际上可以为不同的体系结构包含不同的本机代码,不确定 Netflix 是如何运行的,但如果您打开 apk,您可以看到/lib/armeabi-v7a/,所以我假设可能有一个类似的文件夹/lib/x86/

编辑:我刚刚检查了亚马逊购物应用程序,它具有 arm 和 x86 的本机代码。所以也许这就是 netflix 的做法。

于 2012-10-22T05:25:02.753 回答
6

Android Studio 3 模拟器使用 QEMU 作为后端

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

QEMU 可以说是领先的开源跨拱仿真器。它是 GPL 软件,除了 x86 和 ARM 之外,还支持很多很多的拱门。

Android 然后只是在 QEMU 之上添加了一些 UI 魔法,可能还有一些补丁,但核心肯定在 QEMU 上游。

QEMU 使用一种称为二进制翻译的技术来实现相当快速的仿真:https ://en.wikipedia.org/wiki/Binary_translation

二进制翻译基本上将 ARM 指令翻译成等效的 x86 指令。

因此,要了解细节,最好的方法是:

理论

  • CPU 是“图灵完备的”(达到内存限制)
  • CPU 具有简单的确定性行为,可以使用有限内存的图灵机进行模拟

因此,很明显,只要有足够的内存,任何 CPU 都可以模拟任何 CPU。

难题是如何快速做到这一点。

实践:QEMU用户态模拟

QEMU 有一个用户态模式,只要你的客户和主机是同一个操作系统,它就可以很容易地在你的 x86 机器上使用用户态 ARM 代码来查看正在发生的事情。

在这种模式下,二进制翻译负责基本指令,系统调用只是转发给主机系统调用。

例如,对于具有 Linux 独立式(无 glibc)hello world 的 Linux 上的 Linux:

电源

.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 上游.

然后组装并运行为:

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 

它输出预期的:

hello syscall v8

您甚至可以运行针对 C 标准库编译的 ARM 程序,并通过 GDB 单步调试程序!看这个具体的例子:How to single step ARM assembly in GDB on QEMU?

由于我们正在讨论二进制翻译,我们还可以启用一些日志记录来查看 QEMU 正在执行的确切翻译:

qemu-aarch64 -d in_asm,out_asm main.out

这里:

  • in_asm指 ARM 来宾输入程序集
  • out_asm指的是运行的 X86 主机生成的程序集

输出包含:

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

因此,在该IN部分中,我们看到了我们手写的 ARM 汇编代码,在该OUT部分中,我们看到了生成的 x86 程序集。

在 Ubuntu 16.04 amd64、QEMU 2.5.0、binutils 2.26.1 中测试。

QEMU 全系统仿真

然而,当您在 QEMU 中启动 Android 时,它当然不会运行用户级二进制文件,而是进行完整的系统模拟,在该模拟中运行实际的 Linux 内核和所有设备。

全系统模拟更准确,但速度稍慢,并且您需要将内核和磁盘映像提供给 QEMU。

要尝试这一点,请查看以下设置:

虚拟机

如果你在 QEMU 上运行 Android X86,你会发现它要快得多。

原因是QEMU使用了KVM,这是一个Linux内核特性,可以直接在主机上运行guest指令!

如果您碰巧拥有一台功能强大的 ARM 机器(截至 2019 年还很少见),您还可以更快地在带有 KVM 的 ARM 上运行 ARM。

出于这个原因,如果您在 X86 主机上,我建议您坚持使用 X86 模拟 AOSP,如:如何编译 Android AOSP 内核并使用 Android 模拟器对其进行测试?,除非你真的需要接触一些低层次的东西。

于 2017-06-12T17:10:46.180 回答
-1

Trend Micro Safe Mobile Workforce中,我们有一个 ARM 运行时(不是英特尔的 houdini),用于 Android 应用程序中的本机库。这样我们就可以支持在强大的 x86 服务器上仅使用 ARM lib 运行 APK。

于 2015-05-02T03:09:05.777 回答