Первая программа для Linux ARM64 и Android на Windows

Последнее обновление: 05.12.2023

Установка Arm GNU Toolchain на Windows

Наиболее популярным инструментом для компиляции кода ассемблера для arm представляет компилятор GAS от проекта GNU, который входит в состав комплекта инструментов для разработки под ARM - Arm GNU Toolchain. Итак, вначале установим данный набор инструментов. Для этого перейдем на официальный сайт компании Arm на страницу https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads. Здесь представлены поседние версии Arm GNU Toolchain для разных архитектур.

GNU Arm Embedded Toolchain для ARM64 ассемблера

(Если в силу географической принадлежности доступ к сайту блокируется, то необходимый пакет инструментов для Windows можно загрузить отсюда - arm-gnu-toolchain-13.2.rel1-mingw-w64-i686-aarch64-none-elf.exe)

Каждая версия Arm GNU Toolchain привязана к определенной версии компиляторов GCC. Например, последняя на момент написания этой статьи версия Arm GNU Toolchain 13.2.Rel1 привязан к версии 13.2 набора компиляторов gcc.

Для ОС Windows доступно несколько групп пакетов по различные архитектуры:

  • AArch32 bare-metal target (arm-none-eabi): для компиляции программ под 32-битные архитектуры без привязки к конкретной операционной системе

  • AArch32 GNU/Linux target with hard float (arm-none-linux-gnueabihf): для компиляции программ под 32-битную ОС Linux

  • AArch64 bare-metal target (aarch64-none-elf): для компиляции программ под 64-битные архитектуры без привязки к конкретной операционной системе

  • AArch64 GNU/Linux target (aarch64-none-linux-gnu): для компиляции программ под 64-битную ОС Linux

Как видно из названия, наборы компиляторов имеют названия типа arm-none-linux-gnueabi, arm-none-eabi, arm-eabi и т.д. Все эти названия формируются по шаблону

arch[-vendor] [-os] - eabi
  • arch: указывает на архитектуру

  • vendor: указывает на производителя

  • os: указывает на целевую операционную систему

  • eabi: сокращение от Embedded Application Binary Interface

Например, пакет инструментов arm-none-eabi предназначен для 32-х битной архитектуры, не зависит от конкретного вендора, операционной системы и компилируется с помощью ARM EABI.

Другой пример: пакет инструментов arm-none-linux-gnueabi предназначен для 32-х битной архитектуры, но создает бинарники непосредственно для ОС Linux и использует GNU EABI.

Поскольку в данном случае в данном случае мы рассматриваем именно arm64, то нас будет интересовать прежде всего те пакеты, которые начинаются на AArch64. И поскольку пакет AArch64 bare-metal target (aarch64-none-elf) не привязан к определенной ОС, то выберем его. Кроме того, он доступен для всех основных ОС. Однако отмечу, что, если планируется писать код именно под Linux (в том числе Android), то лучше использовать AArch64 GNU/Linux target (aarch64-none-linux-gnu) - он создает более компактные (иногда намного меньшие) исполняемые файлы.

Для Windows доступны пакеты в двух вариантах: установочный файл exe, который устанавливает все необходимые файлы в папку C:\Program Files (x86), и zip-архив - по сути те же самые файлы, которые мы можем распаковать в любое нужное для нас расположение. Большой разницы между файлами из exe и zip нет, но для простоты выберем exe-файл (в моем случае это файл arm-gnu-toolchain-12.3.rel1-mingw-w64-i686-aarch64-none-elf.exe

Установка GNU Arm Embedded Toolchain для ARM64 ассемблера под Windows

После загрузки запустим установщик

Установка компилятора gas из GNU Arm Embedded Toolchain для ARM64 под Windows

Прощелкаем по шагам и в конце на последнем окне после установки установим флажок Add path to environment variable, чтобы добавить путь к компилятору и другим инструментам в переменные среды:

Добавление пути к компилятору GNU Arm Embedded Toolchain для ARM64 в переменные среды

Если мы посмотрим на добавленный в переменные среды путь (в данном случае каталог C:\Program Files (x86)\Arm GNU Toolchain aarch64-none-elf\12.3 rel1\bin), то мы найдем файлы компилятора и ряд других файлов:

ассемблер as из GNU Arm Embedded Toolchain для ARM64 под Windows

В этом комплекте нам понадобится прежде всего сам ассемблер - файл aarch64-none-elf-as.exe, который по коду ассемблера Arm64 создает объектный файл. Кроме того, также потребуется файл aarch64-none-elf-as.ld, который также располагается в этой папке и который генерирует из объектного файла исполныемый файл.

Для проверки настройки откроем терминал/командную строку и выведем версию компилятора следующей командой:

aarch64-none-elf-as --version

Мы должны получить вывод типа следующего:

C:\Users\eugen>aarch64-none-elf-as --version
GNU assembler (Arm GNU Toolchain 12.3.Rel1 (Build arm-12.35)) 2.40.0.20230627
Copyright (C) 2023 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `aarch64-none-elf'.
C:\Users\eugen>

Создание первой программы

Теперь напишем первую простейшую программу, которая просто будет выводить на консоль некоторую строку. Для этого создадим на жестком диске какой-нибудь каталог, например, C:\arm. Создадим в этого каталоге новый файл hello.s (обычно файлы с кодом ассемблера arm имеют расширение .s). Определим в этом файл следующий код:

.global _start          // устанавливаем стартовый адрес программы

_start: mov X0, #1          // 1 = StdOut - поток вывода
 ldr X1, =hello             // строка для вывода на экран
 mov X2, #19                // длина строки
 mov X8, #64                // устанавливаем функцию Linux
 svc 0                      // вызываем функцию Linux для вывода строки

 mov X0, #0                 // Устанавливаем 0 как код возврата
 mov X8, #93                // код 93 представляет завершение программы
 svc 0                      // вызываем функцию Linux для выхода из программы

.data
hello: .ascii "Hello METANIT.COM!\n"    // данные для вывода

Для большего понимания я снабдил программу комментариями. GNU Assembler использует тот же самый синтаксис комментариев, что и C/C++ и другие си-подобные языки: одиночный комментарий начинается с двойного слеша //. Также можно использовать многострочный комментарий с помощью символов /∗ и ∗/, между которыми помещается текст комментария (/* текст комментария */

Вначале надо указать линкеру (в нашем случае программа ld) стартовую точку программы. В данной программе стартовая точка программы проецируется на метку _start. И чтобы линкер получил к ней доступ, определяет _start в качестве глобальной переменной с помощью оператора global.

.global _start

Одна программа может состоять из множества файлов, но только один из них может иметь точку входа в программу _start

Далее идут собственно действия программы. Вначале вызывается инструкция mov, которая помещает данные в регистр.

mov X0, #1

Значения X0-X2 представляют регистры для параметров функции в Linux. В данном случае помещаем в регистр X0 значение "#1". Операнды начинаются со знака "#" Число 1 представляет номер стандартного потока вывода "StdOut", в данном случае, грубо говоря, вывод на консоль.

Далее загружаем в регистр X1 адрес строки для вывода на экран с помощью инструкции ldr

ldr X1, =hello 

Затем также с помощью инструкции mov помещаем в регистр X2 длину выводимой строки

mov X2, #19

Для любого системного вызова в Linux параметры помещаются в регистры X0–X7 в зависимости от количества. Затем в регистр X0 помещается код возврата. А сам системный вызов определяется номером функции из регистра X8. Здесь помещаем в X8 функцию с номеро 64 (функция write)

mov X8, #64

Далее выполняем системный вызов с помощью оператора svc

svc 0 

Операционная система, используя параметры в регистрах и номер функции, выведет строку на экран.

После этого нам надо выйти из программы. Для этого помещаем в регистр X0 число 0

mov X0, #0

А в регистр X8 передаем число 93 - номер функции для выхода из программы (функция exit)

mov X8, #93

И с помощью svc также выполняем функции. После этого программа должна завершить выполнение.

В самом конце программы размещена секция данных

.data
hello: .ascii "Hello METANIT.COM!\n"    // данные для вывода

Оператор .data указывает, что дальше идет секция данных. Выражение .ascii выделяет память и помещает в нее указанную далее строку.

Строка завершается символом перевода строки "\n", чтобы не надо было нажимать на Return, чтобы увидеть текст в окне терминала.

Компиляция приложения

Для компиляции приложения откроем терминал/командную строку и командой cd перейдем к папке, где расположен файл hello.s с исходным кодом программы. И для компиляции выполним команду:

aarch64-none-elf-as hello.s -o hello.o

Компилятору aarch64-none-elf-as в качестве параметра передается файл с исходным кодом hello.s. А параметр -o указывает, в какой файл будет компилироваться программа - в данном случае в файл hello.o. Соответственно в папке программы появится файл hello.o

Затем нам нужно скомпновать программу с исполняемый файл с помощью линкера aarch64-none-elf-ld командой:

aarch64-none-elf-ld hello.o -o hello

Полный вывод:

C:\Users\eugen>cd c:\arm

c:\arm>aarch64-none-elf-as hello.s -o hello.o

c:\arm>aarch64-none-elf-ld hello.o -o hello

c:\arm>

После этого в папке программы появится исполняемый файл hello, который мы можем запускать на устройстве с архитектурой ARM под управлением Linux.

компиляция и линковка программы на ассемблере arm64 на Windows

Тестирование приложения на Android

Итак, у нас есть исполняемый файл программы. Мы ее можем протестировать. Для этого нам нужен Linux на устройстве с архитектурой ARM. В качестве такого устройства я возьму самый распространенный вариант - смартфон под управлением Android. Поскольку Android построен на базе Linux и как правило устанавливается на устройства с arm архитектурой.

Для установки файла на Android нам понадобится консольная утилита adb, которая устанавливается в рамках Android SDK. Android SDK обычно устанавливается вместе с Android Studio. Но если Android Studio не установлена, то можно загрузить пакет https://dl.google.com/android/repository/platform-tools-latest-windows.zip. В составе этого пакета или в составе SDK в папке platforms-tools можно найти нужную нам утилиту adb.

тестирование на Android программы на ассемблере arm64, скомпилированной на Windows

Для упрощения работы путь к этой утилите лучше добавить в переменные среды, чтобы не прописывать к ней полный путь.

Теперь переместим скомпилированный файл hello на устройство под Android. Для этого подключим через usb к компьютеру смарфтон с Android и перейдем в консоли с помощью команды cd к папке с файлом hello используем следующую команду

[Путь_к_файлу_adb]/adb push hello /data/local/tmp/hello

То есть в данном случае используем команду push для помещения копии файла hello на смартфон в папку /data/local/tmp/

Установка программы на ассемблере arm64 на Android

Далее перейдем к консоли устройства Android с помощью команды:

adb shell

Далее перейдем к папке /data/local/tmp с помощью команды

cd /data/local/tmp

Затем изменим режим файла, чтобы его можно было запустить:

chmod +x hello

и в конце выполним файл hello

./hello

И на консоль должна быть выведена строка "Hello METANIT.COM!"

Первая программа на ассемблере arm64 на Android с компиляцией на Windows
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850