Вызов функций ассемблера из программы на C

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

В прошлой статье был рассмотрен вызов кода 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

Стоит учитывать, что в данном случае длина строки включает конечный нулевой байт.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850