#assembly #x86 #nasm #i386
# #сборка #x86 #nasm #i386
Вопрос:
Собираем некоторую сборку x86 для изучения простой задачи вычитания, и я сталкиваюсь с проблемой. Ниже приведен мой код, который я пробовал до сих пор:
section .text
global _start
_start:
MOV EAX, 4 ; sys_write call
MOV EBX, 1 ; file descriptor
MOV ECX, dispMsg
MOV EDX, dispMsgLen
INT 0x80 ; execute instruction set
MOV EAX, 3 ; sys_read call
MOV EBX, 2
MOV [tempf], ECX ; move user-input to tempf
MOV EDX, 3
INT 0x80
MOV EAX, [tempf] ; move tempf to EAX
SUB EAX, '0' ; convert EAX to decimal
MOV EBX, 32 ; move value 32 to EBX
SUB EBX, '0' ; convert EBX to decimal
SUB EAX, EBX ; sub EAX to EBX
ADD EAX, '0' ; convert EAX to ascii
MOV [res], EAX ; move EAX to res
MOV EAX, 4
MOV EBX, 1
MOV ECX, [res]
MOV EDX, 3
INT 0x80
MOV EAX, 1 ; sys_exit call
MOV EBX, 1
INT 0x80
section .bss
tempf resb 3
res resb 3
section .data
dispMsg db 'Input a value', 0xa
dispMsgLen equ $-dispMsg
После компиляции и запуска пользователю предлагается ввести число. Когда они нажимают enter, я ожидаю, что код вычитает ввод пользователя на 32 и выведет результат на консоль. Однако я получаю символ «?» в ромбе в консоли только тогда, когда пользователь вводит число и нажимает enter. Я читал, что это может быть связано с тем, что в переменной [res] ничего нет для печати, но я уверен, что я сохранил разницу между user input - 32
в переменной res.
Любая помощь приветствуется, спасибо, ребята.
Комментарии:
1. Возможно, вы не поняли разницу между кодом ASCII для цифровых символов и целочисленными значениями.
mov ebx, 32
устанавливает EBX = 32 = 0x20 = 0b10000. В самом процессоре он хранится в виде двоичных битов. Вычитание'0'
(число 48 десятичное, иначе 0x30 шестнадцатеричное) оставляет EBX = 32-48 = -16. Итак, вы вычитаете это из кода ASCII для первого байта того, что вы ввели. Используйте отладчик, чтобы просмотреть младший байт EAX (AL), в который вы сохраняетеres
.2. Кстати, вы считываете входные данные из fd=2 (stderr), что странно. Это работает в обычном терминале, потому что все 3 стандартных файловых дескриптора (0, 1 и 2) являются дубликатами одного и того же описания файла для чтения и записи, открытого в tty, когда вы запускаете программу из оболочки bash.
Ответ №1:
Итак, ваш read
системный вызов и его последствия не имеют особого смысла.
MOV EAX, 3 ; sys_read call
MOV EBX, 2
Почему вы пытаетесь прочитать из файлового дескриптора 2? Это стандартная ошибка, и она не обязательно должна быть открыта для чтения. Если вы хотите получить ввод от пользователя, считайте из стандартного ввода, дескриптор файла 0.
MOV [tempf], ECX ; move user-input to tempf
Это не то, что это делает; он принимает (мусорное) значение, которое находится в ECX
(которое, кстати, составляет четыре байта), и сохраняет его по адресу tempf
(который, кстати, составляет всего три байта). Я думаю, вы хотели написать MOV ECX, tempf
. Обратите внимание на отсутствие скобок, потому что мы хотим, чтобы адрес tempf
был в ECX, а не значение, расположенное по этому адресу в памяти.
MOV EDX, 3
Итак, вы собираетесь прочитать три байта. Я не совсем уверен, почему три, но…
INT 0x80
MOV EAX, [tempf] ; move tempf to EAX
… это загружает четыре байта, поскольку EAX
это 32-разрядный регистр.
Если вам просто нужна одна цифра от пользователя (и это все, что ваш код, похоже, способен обрабатывать), тогда вам, вероятно, следует:
- просто прочитайте один байт
- загрузите один байт в 8-разрядный регистр, например
MOV AL, [tempf]
- С этого момента работайте с этим 8-разрядным регистром, например
SUB AL, '0'
, и так далее.