Недавно Motorola выпустила Android-телефон на базе x86. Я немного смущен тем, как на этом телефоне могут запускаться собственные приложения/библиотеки, написанные для ARM (например, netflix).
Буду признателен, если кто-нибудь сможет объяснить.
Ответ 3
Эмулятор Android Studio 3 использует QEMU в качестве бэкэнда
https://en.wikipedia.org/wiki/QEMU
QEMU, пожалуй, ведущий эмулятор кросс-арки с открытым исходным кодом. Это программное обеспечение GPL, и в дополнение к x86 и ARM поддерживает множество других арок.
Затем Android просто добавляет немного магии пользовательского интерфейса поверх QEMU и, возможно, некоторые патчи, но ядро определенно находится в QEMU upstream.
QEMU использует технику, называемую бинарным переводом, для достижения достаточно быстрой эмуляции: https://en.wikipedia.org/wiki/Binary_translation
Двоичный перевод в основном переводит инструкции ARM в эквивалентные инструкции x86.
Поэтому, чтобы понять детали, лучше всего:
- прочитайте исходный код QEMU: https://github.com/qemu/qemu
- изучите бинарный перевод в целом, возможно, напишите собственную игрушечную реализацию
теория
- Процессоры " Тьюринга завершены " (до предела памяти)
- Процессоры имеют простое детерминированное поведение, которое можно моделировать на машинах Тьюринга с конечной памятью
Поэтому ясно, что любой процессор может эмулировать любой процессор, если ему достаточно памяти.
Сложный вопрос, как сделать это быстро.
Практика: симуляция пользовательского режима QEMU
QEMU имеет режим пользовательского пространства, который позволяет очень легко играть с пользовательским кодом ARM на вашем компьютере с архитектурой x86, чтобы увидеть, что происходит, если ваш гость и хост находятся в одной ОС.
В этом режиме происходит то, что двоичный перевод выполняет основные инструкции, а системные вызовы просто перенаправляются на системные вызовы хоста.
Например, для Linux на Linux с автономным Linux (без 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 вверх по течению.
Затем собрать и запустить как:
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
Вы даже можете запускать программы ARM, скомпилированные со стандартной библиотекой C, и GDB шаг отлаживает программу! Посмотрите этот конкретный пример: Как выполнить пошаговую сборку ARM в GDB на 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 полная эмуляция системы
Однако, когда вы загружаете Android в QEMU, он, конечно, не запускает бинарный файл пользователя, а скорее выполняет полную симуляцию системы, где он запускает реальное ядро Linux и все устройства в симуляции.
Полная симуляция системы более точна, но немного медленнее, и вам нужно передать ядро и образ диска в QEMU.
Чтобы попробовать это, взгляните на следующие настройки:
KVM
Если вы запустите Android X86 на QEMU, вы заметите, что он намного быстрее.
Причина в том, что QEMU использует KVM, которая является функцией ядра Linux, которая может выполнять гостевые инструкции прямо на хосте!
Если у вас есть мощный компьютер ARM (но редкий по состоянию на 2019 год), вы также можете запустить ARM на ARM с KVM намного быстрее.
По этой причине я рекомендую придерживаться X86-симуляции AOSP, если вы работаете на хосте X86, как указано в разделе: Как скомпилировать ядро Android AOSP и протестировать его с помощью эмулятора Android? Если только вам действительно не нужно прикасаться к чему-то низкому уровню.