Skip to content

Instantly share code, notes, and snippets.

@jtprogru
Created February 26, 2026 18:06
Show Gist options
  • Select an option

  • Save jtprogru/f7915019f636095186ca736be7d33b81 to your computer and use it in GitHub Desktop.

Select an option

Save jtprogru/f7915019f636095186ca736be7d33b81 to your computer and use it in GitHub Desktop.
revers.asm

ARM64 (AArch64) Assembler

// ============================================================================
// Работа со строками на ARM64 Assembler (Linux)
// ============================================================================
// Компиляция: as -o string_ops.o string_ops.s && ld -o string_ops string_ops.o
// Запуск: ./string_ops
// ============================================================================

.equ SYS_WRITE,      64
.equ SYS_EXIT,       93
.equ STDOUT,          1

.section .data
    sample:         .asciz "Программирование на Bash - это увлекательно!"
    sample_len = . - sample - 1          // длина без нулевого байта
    
    msg_orig:       .asciz "Исходная строка: "
    msg_orig_len = . - msg_orig - 1
    
    msg_first10:    .asciz "Первые 10 символов: "
    msg_first10_len = . - msg_first10 - 1
    
    msg_last5:      .asciz "Последние 5 символов: "
    msg_last5_len = . - msg_last5 - 1
    
    msg_second:     .asciz "Каждый второй символ: "
    msg_second_len = . - msg_second - 1
    
    msg_reverse:    .asciz "Строка в обратном порядке: "
    msg_reverse_len = . - msg_reverse - 1
    
    newline:        .asciz "\n"
    
    // Буфер для обратной строки
    .balign 16
    reverse_buf:    .skip 128

.section .text
.global _start

// ============================================================================
// Макрос для вывода строки
// ============================================================================
.macro print_str msg_ptr, msg_len
    mov     x0, STDOUT
    ldr     x1, =\msg_ptr
    mov     x2, \msg_len
    mov     x8, SYS_WRITE
    svc     #0
.endm

.macro print_ptr ptr, len
    mov     x0, STDOUT
    mov     x1, \ptr
    mov     x2, \len
    mov     x8, SYS_WRITE
    svc     #0
.endm

.macro print_newline
    mov     x0, STDOUT
    ldr     x1, =newline
    mov     x2, #1
    mov     x8, SYS_WRITE
    svc     #0
.endm

// ============================================================================
// Точка входа
// ============================================================================
_start:
    // Сохраняем длину строки в регистре
    ldr     x19, =sample
    mov     x20, #sample_len
    
    // -------------------------------------------------
    // Исходная строка
    // -------------------------------------------------
    print_str msg_orig, msg_orig_len
    print_ptr x19, x20
    print_newline
    
    // -------------------------------------------------
    // Первые 10 символов
    // -------------------------------------------------
    print_str msg_first10, msg_first10_len
    mov     x0, STDOUT
    mov     x1, x19              // указатель на начало строки
    mov     x2, #10              // 10 байт
    mov     x8, SYS_WRITE
    svc     #0
    print_newline
    
    // -------------------------------------------------
    // Последние 5 символов
    // -------------------------------------------------
    print_str msg_last5, msg_last5_len
    mov     x0, STDOUT
    add     x1, x19, x20         // x1 = указатель на конец строки
    sub     x1, x1, #5           // смещаемся на 5 байт назад
    mov     x2, #5
    mov     x8, SYS_WRITE
    svc     #0
    print_newline
    
    // -------------------------------------------------
    // Каждый второй символ
    // -------------------------------------------------
    print_str msg_second, msg_second_len
    bl      print_every_second
    print_newline
    
    // -------------------------------------------------
    // Строка в обратном порядке
    // -------------------------------------------------
    print_str msg_reverse, msg_reverse_len
    bl      reverse_string
    print_newline
    
    // -------------------------------------------------
    // Выход
    // -------------------------------------------------
    mov     x0, #0
    mov     x8, SYS_EXIT
    svc     #0

// ============================================================================
// Вывод каждого второго символа (байта)
// ============================================================================
// Вход: x19 = указатель на строку, x20 = длина
// ============================================================================
print_every_second:
    stp     x29, x30, [sp, #-16]!
    mov     x29, sp
    
    mov     x1, x19              // указатель на текущий символ
    mov     x2, #0               // счётчик
    
.loop_second:
    cmp     x2, x20
    b.ge    .done_second
    
    // Выводим символ по адресу x1
    mov     x0, STDOUT
    mov     x8, SYS_WRITE
    svc     #0
    
    add     x1, x1, #2           // пропускаем 1 символ
    add     x2, x2, #2
    b       .loop_second
    
.done_second:
    ldp     x29, x30, [sp], #16
    ret

// ============================================================================
// Разворот строки и вывод
// ============================================================================
// Вход: x19 = указатель на строку, x20 = длина
// ============================================================================
reverse_string:
    stp     x29, x30, [sp, #-16]!
    mov     x29, sp
    stp     x19, x20, [sp, #-16]!
    
    ldr     x21, =reverse_buf    // буфер для обратной строки
    add     x22, x19, x20        // указатель на конец строки
    sub     x22, x22, #1         // последний символ (без нулевого)
    mov     x23, #0              // индекс в буфере
    
.loop_reverse:
    cmp     x22, x19
    blt     .done_reverse
    
    // Копируем символ из строки в буфер
    ldrb    w0, [x22]            // загружаем байт
    strb    w0, [x21, x23]       // сохраняем в буфер
    
    sub     x22, x22, #1         // двигаемся назад по строке
    add     x23, x23, #1         // двигаемся вперёд по буферу
    b       .loop_reverse
    
.done_reverse:
    // Выводим обратную строку
    mov     x0, STDOUT
    mov     x1, x21
    mov     x2, x23
    mov     x8, SYS_WRITE
    svc     #0
    
    ldp     x19, x20, [sp], #16
    ldp     x29, x30, [sp], #16
    ret

Версия с комментариями на русском

// ============================================================================
// РАБОТА СО СТРОКАМИ НА ARM64 ASSEMBLER
// ============================================================================
// Архитектура: ARMv8-A (AArch64)
// ОС: Linux
// ============================================================================

.equ SYS_WRITE,      64        // номер системного вызова write
.equ SYS_EXIT,       93        // номер системного вызова exit
.equ STDOUT,          1        // файловый дескриптор stdout

// ============================================================================
// СЕКЦИЯ ДАННЫХ
// ============================================================================
.section .data
    // Основная строка (UTF-8, кириллица = 2 байта на символ)
    sample:         .asciz "Программирование на Bash - это увлекательно!"
    sample_len = . - sample - 1
    
    // Сообщения
    msg_orig:       .asciz "Исходная строка: "
    msg_orig_len = . - msg_orig - 1
    
    msg_first10:    .asciz "Первые 10 символов: "
    msg_first10_len = . - msg_first10 - 1
    
    msg_last5:      .asciz "Последние 5 символов: "
    msg_last5_len = . - msg_last5 - 1
    
    msg_second:     .asciz "Каждый второй символ: "
    msg_second_len = . - msg_second - 1
    
    msg_reverse:    .asciz "Строка в обратном порядке: "
    msg_reverse_len = . - msg_reverse - 1
    
    newline:        .byte 10              // символ перевода строки

// Выравнивание буфера по 16 байт для оптимизации
.balign 16
reverse_buf:    .skip 128             // буфер для обратной строки

// ============================================================================
// СЕКЦИЯ КОДА
// ============================================================================
.section .text
.global _start

_start:
    // Инициализация
    ldr     x19, =sample          // x19 = адрес строки
    mov     x20, #sample_len      // x20 = длина строки
    
    // ====== ИСХОДНАЯ СТРОКА ======
    bl      print_label_orig
    mov     x0, STDOUT
    mov     x1, x19
    mov     x2, x20
    mov     x8, SYS_WRITE
    svc     #0
    bl      print_newline
    
    // ====== ПЕРВЫЕ 10 СИМВОЛОВ ======
    bl      print_label_first10
    mov     x0, STDOUT
    mov     x1, x19
    mov     x2, #10
    mov     x8, SYS_WRITE
    svc     #0
    bl      print_newline
    
    // ====== ПОСЛЕДНИЕ 5 СИМВОЛОВ ======
    bl      print_label_last5
    mov     x0, STDOUT
    add     x1, x19, x20
    sub     x1, x1, #5
    mov     x2, #5
    mov     x8, SYS_WRITE
    svc     #0
    bl      print_newline
    
    // ====== КАЖДЫЙ ВТОРОЙ СИМВОЛ ======
    bl      print_label_second
    bl      every_second_char
    bl      print_newline
    
    // ====== СТРОКА В ОБРАТНОМ ПОРЯДКЕ ======
    bl      print_label_reverse
    bl      reverse_and_print
    bl      print_newline
    
    // ====== ЗАВЕРШЕНИЕ ПРОГРАММЫ ======
    mov     x0, #0                // код возврата 0
    mov     x8, SYS_EXIT
    svc     #0

// ============================================================================
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
// ============================================================================

// Вывод метки "Исходная строка: "
print_label_orig:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =msg_orig
    mov     x2, msg_orig_len
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

print_label_first10:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =msg_first10
    mov     x2, msg_first10_len
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

print_label_last5:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =msg_last5
    mov     x2, msg_last5_len
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

print_label_second:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =msg_second
    mov     x2, msg_second_len
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

print_label_reverse:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =msg_reverse
    mov     x2, msg_reverse_len
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

// Вывод перевода строки
print_newline:
    stp     x29, x30, [sp, #-16]!
    mov     x0, STDOUT
    ldr     x1, =newline
    mov     x2, #1
    mov     x8, SYS_WRITE
    svc     #0
    ldp     x29, x30, [sp], #16
    ret

// ============================================================================
// КАЖДЫЙ ВТОРОЙ СИМВОЛ
// ============================================================================
every_second_char:
    stp     x29, x30, [sp, #-16]!
    
    mov     x1, x19              // указатель на строку
    mov     x2, #0               // индекс
    
.loop_second:
    cmp     x2, x20              // индекс >= длина?
    b.ge    .end_second
    
    // Выводим один символ (байт)
    mov     x0, STDOUT
    mov     x8, SYS_WRITE
    svc     #0                   // write(1, x1, 1)
    
    add     x1, x1, #2           // пропускаем следующий символ
    add     x2, x2, #2
    b       .loop_second
    
.end_second:
    ldp     x29, x30, [sp], #16
    ret

// ============================================================================
// РАЗВОРОТ СТРОКИ
// ============================================================================
reverse_and_print:
    stp     x29, x30, [sp, #-16]!
    
    ldr     x21, =reverse_buf    // буфер результата
    add     x22, x19, x20
    sub     x22, x22, #1         // последний байт строки
    mov     x23, #0              // индекс в буфере
    
.loop_rev:
    cmp     x22, x19
    blt     .print_rev
    
    ldrb    w24, [x22]           // читаем байт с конца
    strb    w24, [x21, x23]      // пишем в буфер
    
    sub     x22, x22, #1
    add     x23, x23, #1
    b       .loop_rev
    
.print_rev:
    mov     x0, STDOUT
    mov     x1, x21
    mov     x2, x23
    mov     x8, SYS_WRITE
    svc     #0
    
    ldp     x29, x30, [sp], #16
    ret

Справочник по регистрам ARM64

Регистр Назначение Сохранение
x0-x7 Аргументы функций и возвращаемые значения Нет
x8 Номер системного вызова Нет
x9-x15 Временные регистры Нет
x16-x17 Внутрипроцедурные вызовы (IP) Нет
x18 Регистр платформы
x19-x28 Callee-saved регистры Да
x29 Указатель кадра стека (FP) Да
x30 Адрес возврата (LR) Да
sp Указатель стека

Команды сборки и запуска

# Ассемблирование
as -o string_ops.o string_ops.s

# Линковка
ld -o string_ops string_ops.o

# Запуск
./string_ops

Особенности UTF-8 в ассемблере

Символ UTF-8 байты Примечание
'П' D0 9F 2 байта
'р' D1 80 2 байта
'!' 21 1 байт
' ' 20 1 байт

Важно: Bash работает с байтами, а не Unicode-символами. Поэтому "первые 10 символов" означает 10 байт, что равно 5 кириллическим буквам. Ассемблерный код делает то же самое для совместимости.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment