Возвращение результата из функции

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

В прошлой теме функция copy копировала строку и выводила сгенерированную строку на консоль:

// METANIT.COM. Определение функции с параметрами
.global _start 
_start: 
    LDR X0, =input     // строка, их которой надо скопировать символы
    LDR X1, =output    // строка, в которую надо скопировать символы
    BL copy          // вызов функции copy
    MOV X0, 0         // код возврата - 0
    MOV X8, #93       // устанавливаем функцию Linux для выхода из программы
    SVC 0             // Вызываем функцию Linux

// определение функции copy, которая копирует символы из одной строки в другую
// X0 - адрес входящей строки
// X1 - адрес исходящей строки
copy:
    MOV X4, X1          // сохраняем адрес начала строки, чтобы потом вычислить ее длину
// в цикле получаем все байты, пока не дойдем до нулевого байта
loop: 
    LDRB W5, [X0], #1        // загружаем из X0 один байт - один символ в W5 и увеличиваем адрес в X0 на 1 байт
    CMP W5, #0              // сравниваем с нулевым байтом
    B.EQ endloop            // если нулевой байт, переход к метке endloop 
    STRB W5, [X1], #1      // если символы равны, заменяем байт по адресу X1 и увеличиваем адрес в X1 на 1 байт
    B loop                  // перед обратно к метке loop
// печать строки на консоль
endloop:
    SUB X2, X1, X4      // длина строки X2 = X1 - X4
    MOV X1, X4          // в X4 сохранен начальный адрес генерируемой строки
    MOV X0, #1          // 1 = StdOut - стандартный поток вывода
    MOV X8, #64         // функция Linux для вывода в поток
    SVC 0               // вызываем функцию Linux
    RET                 // выход из функции

.data
    input: .asciz "Hello METANIT.COM!\n"
    output:  .fill 20, 1, 0

Но это не лучшее решение, поскольку в одной функции мы смешиваем две различных функциональности - копирование и вывод на консоль. Кроме того, не всегда при копировании строки требуется вывести ее на консоль. Либо было бы неплохо, чтобы сгенерированную строку можно было выводить где-то во внешнем коде. Но чтобы вывести строку на консоль с помощью функции Linux с номером 64, нам необходимо знать ее длину. То есть нам надо из функции во вне вернуть длину строку, чтобы внешний код мог бы выводить ее на консоль.

Как правило, для возвращения результата из функции применяется регистр X0 - при вызове функция помещает значение в этот регистр. А внешний код после вызова функции может взять из этого регистра данное значение.

Так, изменим выше приведенный код следующим образом:

.global _start 
_start: 
    LDR X0, =input     // строка, их которой надо скопировать символы
    LDR X1, =output    // строка, в которую надо скопировать символы
    BL copy          // вызов функции copy

// печать строки на консоль
    MOV X2, X0          // в регистр X2 передаем результ функции copy - длину строки из регистра X0
    MOV X0, #1          // 1 = StdOut - стандартный поток вывода
    LDR X1, =output     // загружаем выводимую строку
    MOV X8, #64         // функция Linux для вывода в поток
    SVC 0               // вызываем функцию Linux
// выход из программы
    MOV X0, 0         // код возврата - 0
    MOV X8, #93       // устанавливаем функцию Linux для выхода из программы
    SVC 0             // Вызываем функцию Linux

// Функция copy, которая копирует символы из одной строки в другую
// Параметры функции
// X0 - адрес входящей строки
// X1 - адрес исходящей строки
//
// Результат функции
// X0 - длина строки
copy:
    MOV X4, X1          // сохраняем адрес начала строки, чтобы потом вычислить ее длину
// в цикле получаем все байты, пока не дойдем до нулевого байта
loop: 
    LDRB W5, [X0], #1        // загружаем из X0 один байт - один символ в W5 и увеличиваем адрес в X0 на 1 байт
    CMP W5, #0              // сравниваем с нулевым байтом
    B.EQ endloop            // если нулевой байт, переход к метке endloop 
    STRB W5, [X1], #1      // если символы равны, заменяем байт по адресу X1 и увеличиваем адрес в X1 на 1 байт
    B loop                  // перед обратно к метке loop
endloop:    
    SUB X0, X1, X4      // помещаем в регистр X0 длину строки -  X0 = X1 - X4
    RET                 // выход из функции

.data
    input: .asciz "Hello METANIT.COM!\n"
    output:  .fill 20, 1, 0

В самой функции помещаем в регистр X0 длину строки

SUB X0, X1, X4    // помещаем в регистр X0 длину строки -  X0 = X1 - X4

Затем после вызова функции из X0 этот результат функции передаем в регистр X2 для последующей печати на консоль:

BL copy          // вызов функции copy
MOV X2, X0      // в регистр X2 передаем результ функции copy - длину строки из регистра X0

Функция вычисления длины строки

Более простой пример - функция, которая вычисляет длину строки:

// функция вычисления длины строки
// параметр
// X0 - входная строка
// результат
// X0 - длина строки
count:
loop:
    LDRB W5, [X0], #1   // загружаем из X0 один байт - один символ в W5 и увеличиваем адрес в X0
    CMP W5, #0          // сравниваем с нулевым байтом
    B.NE loop           // если попался нулевой символ, то выходим из цикла
    // помещаем длину строки в регистр X0
    MOV X0, W5
    RET
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850