В прошлой статье был рассмотрен вызов кода C в программе на ассемблере. Но также можно, наоборот, вызывать функции ассемблера в программе на языке С. Например, когда нам надо оптимизировать некоторые участки кода, увеличить производительность, в этом случае можно прибегнуть к ограниченному использованию ассемблера.
Например, определим файл copy.s, который будет содержать определение функции copy
для копирования одной строки в другую:
// Функция copy, которая копирует символы из одной строки в другую // Параметры функции // X0 - адрес входящей строки // X1 - адрес исходящей строки // // Результат функции // X0 - длина строки .global copy copy: MOV X4, X1 // сохраняем адрес начала строки, чтобы потом вычислить ее длину // в цикле получаем все байты, пока не дойдем до нулевого байта loop: LDRB W5, [X0], #1 // загружаем из X0 один байт - один символ в W5 и увеличиваем адрес в X0 на 1 байт CMP W5, #0 // сравниваем с нулевым байтом STRB W5, [X1], #1 // если символы равны, заменяем байт по адресу X1 и увеличиваем адрес в X1 на 1 байт B.NE loop // если ненулевой байт, переход обратно к метке loop для копирования следующего символа SUB X0, X1, X4 // помещаем в регистр X0 длину строки - X0 = X1 - X4 RET // выход из функции
В функции проходим по каждому байту из строки, адрес которой хранится в регистре Х0 и копируем его в строку, адрес которой хранится в регистре Х1. Когда дойдем до нулевого байта, то выходим из цикла, в регистр Х0 помещаем длину строки и завершаем выполнение функции.
Допустим, мы хотим использовать эту функцию в коде на C. Пусть у нас есть главный файл программы на языке С, который называется app.c и который использует копирование с помощью вышеопределенной функции:
#include <stdio.h> extern int copy(char *, char * ); int main(void) { char *source = "Hello Work"; // строка, которую копируем char target[20]; // куда копируем строку int length = copy(source, target); printf("Target: %s \n", target); printf("String length: %d \n", length); return 0; }
Функция copy
фактически принимает две строки или в терминах языка С два указателя на тип char. Также через регистр X0 она возвращает количество символов в строке,
то есть возвращается значение типа int
. Таким образом, прототипом этой функции в языке С будет:
int copy(char *, char * );
И в начале программы объявляем прототип данной функции с оператором extern.
В самой программе копируем строку source
в символьный массив target
и получаем из функции copy
количество скопированных символов.
В конце скомпилируем и собирем все с помощью следующей команды:
aarch64-none-linux-gnu-gcc -o app app.c copy.s -static // На Windows aarch64-linux-gnu-gcc -o app app.c copy.s -static // На Linux x86-64 gcc -o app app.c copy.s -static // На Linux ARM64
В результате будет создан один файл app
, при выполнении которого на консоль будет выведено
Target: Hello Work String length: 11
Стоит учитывать, что в данном случае длина строки включает конечный нулевой байт.