Сравнение двух строк (NASM) 64 бит, Linux

Программа на NASM — сравнение двух строк — t2.asm:

 

section .data

msg1 db «Мой текст»,0   ; 0 — означает конец строки
msg2 db «Мой текст»,0

msg_res_y db «Строки идентичны», 10    ; 10 — переход на новую строку
res_y equ $ — msg_res_y   ; вычислим размер надписи включая знак перехода на новую строку

msg_res_n db «Строки не равны»,10
res_n equ $ — msg_res_n

section .text
global _start

_start:

;загрузим адреса строк в регистры

mov rsi, msg1
mov rdi ,msg2

compare_loop:
;возьмем по байту от каждого сообщения и поместим в r8b. [rsi] — взять байт содержимого из rsi, без квадратных скобок было бы — взять адрес 

mov r8b, [rsi]
mov r9b , [rdi]

cmp r8b, r9b  ; сравним байт из одного слова и байт из другого     
jne res_dif ; jne — если не равны, переход на ссылку res_equal. jne — jump not equal — прыгнуть если не равны/не эквивалентны

;проверяем байт конца строки, не кончилась ли строка, должен  быть 0 если кончилась

cmp r8b, 0

jz res_equal ; строка кончилась, 0, значит весь цикл прошел до конца и строки равные. jz -jump zero — прыгнуть на метку если ноль.

inc rsi  ;перейти к следующему байту/букве
inc rdi ;тоже самое для второго слова
jmp compare_loop ;прыгнуть на метку начала сравнения

res_equal:   
; sys_write

mov rax,1 ; функция вывода текста
mov rdi, 1 ; первый аргумент 1 — это консоль. выводим в stdout, в консоль 
mov rsi, msg_res_y ; строка «строки равны»
mov rdx, res_y ;ее длина, требуется для вызова вывода строки
syscall  ;исполним вывод строки
jmp ext_prog  ; прыгнем на функцию корректного завершения программы

res_dif:
mov rax,1 ; функция вывода
mov rdi, 1 ; первый аргумент 1 — это консоль/stdout
mov rsi, msg_res_n ; строка  «cтроки не равны»
mov rdx, res_n ;ее длина
syscall

ext_prog:
mov rax,60
xor rdi, rdi
syscall

 

Скомпилировать:

nasm -f elf64 t2.asm -o t2.o

ld t2.o -o t2.bin

Запуск скомпилированной программы из папки с программой из консоли

./t2.bin

Это 64 битная программа для Linux.

Для 32 бит она выглядела бы иначе, так как в 32 битах используется лишь часть 64 битных регистров, пример 32 битной программы на рисунке ниже (сегодня  32 бита уже не актуальны):

 

Для версии этой программы для Windows прийдется обращаться к WinAPI, что довольно громоздко, у каждого вызова есть свои параметры и требования в каких регистрах, что должно находится. 

Линкуется программа тоже не через ld, а через golink.

bits 64
default rel ; Обязательно для Windows x64: RIP‑relative адресация

section .data
msg1 db «Мой текст», 0
msg2 db «Мой текст», 0

; В Windows нужен CRLF: 13 (CR) + 10 (LF)
msg_res_y db «Строки идентичны», 13, 10
res_y equ $ — msg_res_y

msg_res_n db «Строки не равны», 13, 10
res_n equ $ — msg_res_n

bytes_written dq 0 ; Буфер, который требует WriteFile

section .text
global _start

_start:
; — Получить дескриптор stdout через GetStdHandle(-11) —
mov ecx, -11 ; STD_OUTPUT_HANDLE = -11 (0xFFFFFFF5)
call GetStdHandle ; результат (HANDLE) будет в RAX
mov rbx, rax ; сохраняем в RBX, чтобы не потерять

; — Цикл сравнения строк (логика та же, что и в Linux) —
mov rsi, msg1
mov rdi, msg2

compare_loop:
mov r8b, [rsi]
mov r9b, [rdi]

cmp r8b, r9b
jne res_dif

cmp r8b, 0
jz res_equal

inc rsi
inc rdi
jmp compare_loop

res_equal:
; — Вызов WriteFile для msg_res_y —
; Соглашение Microsoft x64: RCX, RDX, R8, R9, [стек]
mov rcx, rbx ; 1. hFile (дескриптор консоли)
mov rdx, msg_res_y ; 2. lpBuffer (адрес строки)
mov r8d, res_y ; 3. nNumberOfBytesToWrite (длина строки)
mov r9, bytes_written ; 4. lpNumberOfBytesWritten (адрес переменной)
sub rsp, 32 ; Выравнивание стека по 16 байт + место под 5‑й аргумент
xor eax, eax
mov [rsp+20], eax ; 5. lpOverlapped = NULL (синхронная запись)

call WriteFile
jmp ext_prog

res_dif:
; — Вызов WriteFile для msg_res_n —
mov rcx, rbx
mov rdx, msg_res_n
mov r8d, res_n
mov r9, bytes_written
sub rsp, 32
xor eax, eax
mov [rsp+20], eax

call WriteFile

ext_prog:
; — Выход через ExitProcess(0) —
xor ecx, ecx ; uExitCode = 0
call ExitProcess

; — Объявления внешних функций (WinAPI) —
extern GetStdHandle
extern WriteFile
extern ExitProcess

 

Сборка:

nasm -f win64 t2.asm -o t2.obj
  • Слинковать в .exe (самый простой вариант без Visual Studio — это golink):
    golink /console /entry _start kernel32.dll t2.obj
    

    На выходе получится t2.exe.

 

Оставьте первый комментарий

Отправить ответ