摩托罗拉刚刚发布了基于x86的Android手机。关于为ARM编写的本机应用程序/库(例如netflix)如何在这款手机上运行,我感到有点困惑。
如果有人能够解释,我会感激不尽。
答案 0 :(得分:52)
是的,ARM本机代码使用名为 Houdini
的仿真功能在Intel x86上运行这个库的作用是动态读取ARM指令并将它们转换为等效的x86指令。这就是为什么许多应用程序可以在x86上运行而不必实际构建等效库的原因。
答案 1 :(得分:9)
您实际上可以为不同的架构包含不同的本机代码,不确定Netflix是如何运行的,但如果您打开apk,则可以看到/lib/armeabi-v7a/
,因此我假设可以有一个类似/lib/x86/
<的文件夹/ p>
编辑:我刚检查了亚马逊购物应用程序,它有arm和x86的本机代码。所以也许这就是netflix如何做到的。
答案 2 :(得分:3)
Android Studio 3模拟器使用QEMU作为后端
https://en.wikipedia.org/wiki/QEMU
QEMU可以说是领先的开源跨拱模拟器。它是GPL软件,除x86和ARM外还支持许多更多的arch。
Android然后在QEMU和可能的补丁之上添加了一些UI魔法,但核心肯定在QEMU上游。
QEMU使用一种称为二进制翻译的技术来实现相当快速的仿真:https://en.wikipedia.org/wiki/Binary_translation
二进制转换基本上将ARM指令转换为等效的x86指令。
因此,要了解细节,最好的方法是:
<强>理论强>
因此,很明显任何CPU都可以模拟任何给定足够内存的CPU。
难题是如何快速 。
练习:QEMU用户模式模拟
QEMU具有用户态模式,只要您的来宾和主机是相同的操作系统,就可以非常轻松地在x86计算机上使用用户态ARM代码来查看发生的情况。
在这种模式下,二进制转换会处理基本指令,系统调用只会转发给主机系统调用。
,对于Linux on Linux with Linux独立(无glibc)的hello world:
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
然后汇编并运行为:
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。
要试一试,请查看以下设置:
<强> KVM 强>
如果你在QEMU上运行Android X86,你会发现它的速度要快得多。
原因是QEMU使用KVM,这是一个Linux内核功能,可以直接在主机上运行访客指令!
如果你碰巧拥有一台功能强大的ARM机器(从2019年开始很少见),你也可以用更快的速度在ARM上运行ARM。
出于这个原因,如果您在X86主机上,我建议您坚持使用A86P的X86模拟:How to compile the Android AOSP kernel and test it with the Android Emulator?,除非您确实需要触摸低级别的东西。