Благодаря взаимодействию с C/C++ мы можем получать в коде ассемблера ввод пользователя и обрабатывать его, используя встроенные функции C/C++. Рассмотрим, как это сделать. Для этого определим файл app.c со следующим кодом на языке C:
#include <stdio.h> extern void hello(void); int readLine(char *dest, int maxLen) { // fgets считывает одну строку и возвращает NULL, если произошла ошибка char *result = fgets(dest, maxLen, stdin); if(result != NULL) { // удаляем символ перевода строки в конце строки int len = strlen(result); if(len > 0) { dest[len - 1] = 0; } return len; } return -1; // если произошла ошибка } int main(void) { hello(); }
Здесь мы подключаем внешнюю функцию hello, которая не принимает никаких параметров и ничего не возвращает и которая будет определена в коде ассемблера.
Для считывания данных с консоли определяем функцию readLine
, которая принимает буфер, в который считываются данные, и количество считываемых данных.
Для непосредственного считывания строки с консоли эта функция использует встроенную функцию fgets
. Если при считывании произошла ошибка, то fgets
возвращает
NULL. Если же считывание прошло удачно, то последний считанный байт будет представлять символ перевода строки, который мы заменяем нулевым байтом.
При успешном считывании функция readLine возвращает количество считанных символов, при неудачном считывании - число -1. Данный результат позволит внешнему коду определить, удачно ли завершилось считывание или нет.
Также определим файл hello.asm со следующим кодом на ассемблере
option casemap:none maxLen equ 128 ; максимальное количество символов .data prompt byte "Enter your name: ", 0 ; приглашение к вводу строки message byte "Hello %s!", 10, 0 ; выводимое сообщение username byte maxLen dup (0) ; буфер для ввода данных .code externdef printf:proc ; подключаем функцию printf externdef readLine:proc ; подключаем функцию readLine public hello hello proc sub rsp, 40 ; устанавливаем стек lea rcx, prompt ; загружаем преглашение к вводу call printf ; вызываем функцию printf для отображения приглашения к вводу ; считаем строку с консоли lea rcx, username ; в rcx - строка, в которую считываем данные mov rdx, maxLen ; в rdx - максимальное количество считываемых символов call readLine ; вызываем readLine для считывания строки ; выводим считанное значение с помощью функции printf lea rcx, message ; в rcx - выводимая строка lea rdx, username ; в rdx - значение для спецификатора %s call printf ; выводим строку add rsp, 40 ; восстанавливаем стек ret ; возвращаемся в программу на С hello endp end
Смысл программы будет заключаться в том, что пользователь вводит с консоли свое имя, и консоль в ответ выводит приветствие. С помощью константы maxLen задается максимальное количество вводимых символов. В данном случае это 128 символов.
В секции данных определяем три переменных. Переменная prompt представляет текст-приглашение к вводу имени. Переменная message представляет финальное сообщение, в которое вместо спецификатора
%s
будет подставлятсья введенное имя. И переменная username представляет строку для ввода имени. Она имеет 128 символов и по умолчанию инициализирована нулями.
В секции кода прежде всего пдключаем функции printf и readLine из кода С:
externdef printf:proc externdef readLine:proc
Далее определяется процедура hello. В ней вначале выводим приглашение вводу с помощью функции printf
lea rcx, prompt ; загружаем преглашение к вводу call printf ; вызываем функцию printf для отображения приглашения к вводу
Далее вызываем функцию readLine и тем самым считываем строку с консоли - имя пользователя:
lea rcx, username ; в rcx - строка, в которую считываем данные mov rdx, maxLen ; в rdx - максимальное количество считываемых символов call readLine ; вызываем readLine для считывания строки
После ввода имени выводим его на консоль с помощью функции printf:
lea rcx, message ; в rcx - выводимая строка lea rdx, username ; в rdx - значение для спецификатора %s call printf ; выводим строку
Сначала скомпилируем код ассемблера из файла hello.asm с помощью команды:
ml64 /c hello.asm
И скомпилируем файл app.c в файл приложения с помощью команды:
cl app.c hello.obj
После компиляции запустим файл app.exe:
c:\asm>ml64 /c hello.asm Microsoft (R) Macro Assembler (x64) Version 14.36.32532.0 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: hello.asm c:\asm>cl app.c hello.obj Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32532 for x64 Copyright (C) Microsoft Corporation. All rights reserved. app.c Microsoft (R) Incremental Linker Version 14.36.32532.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:app.exe app.obj hello.obj c:\asm>app Enter your name: Eugene Hello Eugene! c:\asm>