Наше портфолио
на основных мобильных площадках
Приложения для Android на Ассемблере

В данной статье мне хотелось бы поделиться необычным подходом к разработке мобильных приложений на Android. Стандартный подход заключается в работе на Android Studio и создании простого мобильного приложения типа «Hello World» на языках Java или Kotlin. Однако, можно сделать всё и по-другому, и скоро вы это увидите. Для сначала небольшая предыстория.

logo

Как работает сотовый телефон на системе Android?

Однажды моя девушка по имени Анастасия спросила: «Как работает мой гаджет? Что у него внутри? Как электричество заставляет всё это работать?»

Анастасие не было чуждо программирование, Более того, она реализовала несколько проектов на языке Basic, которые включали программирование и электронику. Возможно, это заставило её получить больше информации о работе телефона. К счастью, один из курсов информатики в университете был посвящён именно этому — или, по крайней мере, дал мне достаточно опыта, чтобы найти хороший ответ.

Следующие пару тройку недель мы провели, постигая основны — как микроскопические примеси в кремниевой решётке изменяют свои свойства, превращая их в полупроводники; как можно управлять потоком электронов через эти полупроводники, образуя транзисторы. Затем мы перешли на уровень выше, и я рассказал ей, как можно построить логические вентили, такие как NAND (логическое И-НЕ) и NOR (логическое ИЛИ-НЕ), комбинируя транзисторы особым образом.

Мы продолжили свое исследование логических элементов различного типа и объединяли их для выполнения вычислений (таких как добавление двух двоичных чисел) и ячеек памяти. Когда же у нас всё начао получатся, мы разработали простой воображаемый процессор, который содержал для начало, два регистра общего назначения и пару простых инструкций и написали простую программу, которая умножит эти два числа.

Если Вам интересна эта тема, то ознакомиться с информацией о работе 8 битных процессоров можно тут - руководство по 8-битному компьютеру с нуля — оно раскроет почти всё аспекты. Хотел бы я иметь такое руководство в свое время =)

Hello, Android!

В какой то я осознал, что у Анастасии уже достаточно своего опыта, чтобы понять, как работает процессор её телефона. У неё был Galaxy S6 Edge, созданный на архитектуре ARM (как большинство современных смартфонов). Настало время создать программу «Hello, World», её первое приложение для Android, но только на ассемблере:

.text .globl _start _start: mov %r0, $1 // дескриптор файла номер 1 (стандартный вывод) ldr %r1, =message mov %r2, $message_len mov %r7, $4 // вызов системной функции 4 (запись) swi $0 mov %r0, $0 // выход из программы с кодом 0 (ok) mov %r7, $1 // вызов системной функции 1 (выход) swi $0 .data message: .ascii "Hello, Worldn" message_len = . - message

Если вы никогда раньше не видели ассемблерный код, этот блок кода может вас напугать, но не беспокойтесь — мы пройдёмся по нему вместе.

Программа состоит из двух разделов: текст, содержащий инструкции машинного кода, и данные, начиная со строки 15, которые содержат переменные, строки и другую информацию. Раздел .text доступен только для чтения, а .data — еще и для записи.

В строке 2 мы определяем глобальную функцию с именем _start. Это точка входа в программу. По сути, операционная система начнёт выполнять ваш код с этой точки. А фактическое определение функции находится в строке 4.

Функция выполняет две вещи: строки 5–9 выводят сообщение на экран, а строки 11–13 завершают программу. На самом деле вы можете удалить строки 11–13, и программа выведет строку «Hello, World» и завершится, но это не будет чистым выходом — она просто завершится с ошибкой, пытаясь выполнить некоторую случайную недопустимую операцию, которая окажется следующей в памяти.

Печать на экран происходит с помощью «системного вызова», по другому системной функции. «Системный вызов» — это функция операционной системы. Мы вызываем такую функцию write(), которую мы указываем, загружая значение 4 в регистр процессора с именем r7 (строка 8), а затем выполняем инструкцию swi $=0 (строка 9), которая переходит прямо в ядро Linux, на котором работает Android.

Параметры для системного вызова передаются через другие регистры: r0 указывает номер дескриптора файла, который мы хотим напечатать. Мы помещаем в него значение 1 (строка 5), которое указывает стандартный вывод (stdout) - вывод на экран

То, куда попадают данные, записанные в стандартный поток вывода, зависит от того, как была запущена программа. Если запустить программу простейшим образом из эмулятора терминала, данные выводятся на экран. В других случаях они могут, сохраняться в файл на диске или передаваться по сети.

Регистр r1 указывает на адрес памяти данных, которые мы хотим записать, поэтому мы загружаем туда адрес строки «Hello, World» (строка 6), а регистр r2 сообщает, сколько байтов мы хотим записать. Мы установили для него значение message_len (строка 7), которое вычисляется в строке 18 с использованием специального синтаксиса: символ точки обозначает текущий адрес памяти, поэтому . - message означает текущий адрес памяти минус адрес message. Поскольку мы определяем message_len сразу после message, это вычисляется как длина message.

Вообщем то, код в строках 5–9 эквивалентен коду на С:

#define message "Hello, Worldn"
write(1, message, strlen(message));

Завершение программы — нам просто нужно загрузить код выхода в регистр r0 (строка 11), затем мы загружаем значение 1, которое является номером вызова системной функции exit(), в r7 (строка 12), и снова вызываем ядро (строка 13).

Вы можете найти полный список системных вызовов Android и их номеров в исходном коде операционной системы. Если Вам интересно можно посмотреть реализацию функций write() и exit(), которые вызывают соответствующие системные функции.

Сборка программы или разработка мобильного приложения для android

Для компиляции любой подобной ассемблерной программы вам понадобится Android NDK (Native Development Kit), содержащий набор компиляторов и инструментов сборки для платформы ARM. Его всегда можно скачать с официального сайта или установить через Android Studio:

Подключение NDK

После установки NDK вам нужно найти файл под названием arm-linux-androideabi-as, это ассемблер для платформы ARM. Если же Вы загрузили всё через Android Studio, найдите этот файл в папке Android SDK. К примеру у меня он находился здесь (относительно SDK):

ndk-bundletoolchainsarm-linux-androideabi-4.9prebuiltwindows-x86_64bin

После нахождения файла с ассемблер, сохраните свой исходный код в файл с именем hello.s (s — это стандартное расширение для файлов ассемблера в системах GNU). Затем выполните исполните следующую команду, чтобы преобразовать его в машинный код:

arm-linux-androideabi-as -o hello.o hello.s

Это создаст объектный ELF-файл с именем hello.o. Для его преобразования в двоичный файл, который может работать на устройстве андройд, требуется последний шаг — вызов компоновщика:

arm-linux-androideabi-ld -o hello hello.o

Теперь всё! Теперь у нас есть файл hello, содержащий вашу программу, готовый к запуску.

Запуск программы мобильного приложения для android на устройстве

Мобильные приложения для Android обычно распространяются в формате APK. Это специальный тип ZIP-файла, который должен создается определённым образом, и включает классы Java (можно просто писать части своего приложения, используя собственный код C / C ++, но точкой входа по-прежнему должен быть Java).

Чтоб было прощемы избежим этой сложности при запуске нашего приложения и будем использовать adb, чтобы скопировать его в TEMP папку устройства Android, а затем adb shell, чтобы запустить мобильное приложение и увидеть результат:

adb push hello /data/local/tmp/hello
adb shell chmod +x /data/local/tmp/hello

И запуск приложения:

adb shell /data/local/tmp/hello

Какие программы напишете вы?

Теперь у вас есть рабочее окружение, похожее на то, что было у Анастасии. Она провела несколько дней, изучая ARM-ассемблер, и придумала простой проект, который она хотела реализовать: Игру где игроки поочерёдно считают, и всякий раз, когда число делится на 7 или содержит цифру 7, они должны сказать «бум».

Окончание этой игры было довольно сложной задачей, так как Анастасия написала метод, который выводил числа на экран по одной цифре за раз — поскольку идея заключалась в том, чтобы писать всё с нуля, используя ассемблерный код и без вызова стандартных функций библиотеки языка С. Нескольких дней заморочек и тяжёлой работы она завершила проект!

Написание ассемблерного кода для устройства Android — это отличный способ познакомиться с архитектурой ARM и лучше понять внутреннюю работу устройства, которое вы используете ежедневно. Советую вам пойти дальше и разработать небольшое мобильное приложение на ассемблере для вашего телефона на Android. Это очень интересно и даст полное погружение в процесс.

Список статей

Реализованные проекты
Больше проектов
Среди наших клиентов
СВЯЖИТЕСЬ С НАМИ
Мы верим, что мобильные решения помогают бизнесу работать эффективнее. Наша компания делает мобильную разработку доступной для бизнеса. Сделать шаг к мобильности бизнеса еще никогда не было так просто!
Бизнес Парк «Румянцево»
Москва, шоссе Киевское, 22-й км, вл. 4 блок Е.
Телефон: 8 (800) 201 6-48-6
E-mail: support@s-m-system.ru
Наше портфолио
ВСЁ ПРОСТО