Сложение чисел на Assembler — CodeTown.ru
Доброго времени суток, наша рубрика начнется именно с этой темы, в которой мы выполним сложение 2 чисел в Assembler и поверьте: сделать это не так легко, как кажется. Ну и следует отметить, что мы будем разбираться с самых азов, поэтому даже такие примеры стоит разобрать.
Также напомню, что мы работаем в MASM32, и соответственно, вам необходимо его установить. Как это сделать, мы рассказывали в прошлой статье по Assembler.
Как создавать файлы Assembler
Прежде чем привести вам код программы, думаю, не лишним будет написать как и где прописывать код:
1. Создать любой файл с расширением .txt
Не так важно с помощью какой программы вы это сделаете(блокнот, Notepad, и тд)
2. Пишем сам код в этом файле(пример кода будет ниже)
3. Переименовываем этот файл в файл с расширением .asm
4. Перемещаем файл в папку BIN(папка, которую использовали в 1 статье)
Код сложения чисел на Assembler
Ну и собственно небольшой код программы:
.386 .model flat,stdcall .data .code start: mov eax,3 add eax,2 ret end start
Ну что ж, вот так вот выглядит код на Assembler.
Первые 2 строчки являются обязательными для MASM, поэтому их мы будем писать в каждой программе. Они обозначают тип процессора и модель памяти с которой мы работаем.
Третья строчка — это раздел переменные( после этой строки, должны объявляться переменные), как вы видите, у нас в этой программе не будет переменных.
Четвертая — раздел кода. В нашей программе, мы помещаем в регистр eax значение 3, а затем с помощью add(прибавить) добавляем 2, логично, что теперь в этом регистре будет храниться значение 5.
Кто не знает, что такое регистр, то вам лучше почитать об этом здесь.
Затем идет команда ret, которая говорит о выходе из программы и сам выход end start.
Как запускать программы
Итак, мы имеем файл с расширением .asm, лежащий в папке BIN.
Поздравляю вас, это первый код на Assembler!
Но все же, пока не очень понятно, как нам проверить: работает ли программа(то есть скомпилировалась ли она и может ли запускаться)?
Для этого мы ее сейчас и запустим:
1.
Запускаем командную строку(прописать cmd в поиске, ну или другим способом)
2. Перейти в папку BIN с помощью команды cd
У меня эта команда будет выглядеть так: cd C:\Users\Никита\BIN
3. Пишем следующую запись: amake.bat имя файла(без расширения)
Я прописываю: amake.bat first
Также напомню вам, что это сработает только при правильно установленном MASM32, в предыдущей статье мы об этом говорили.
Жмем enter
Если ошибок не возникло то у вас появится что то вроде этого:
Запуск отладчика OLLYDBG
Программа скомпилировалась, а это уже хорошо, теперь нам нужно проверить как она сработала, вдруг она не сложила 2 числа.
Для этого в папке BIN открываем наш отладчик(который устанавливали в 1 статье) OLLYDBG.
В отладчике открываем файл программы (file > open first.exe), и видим наш код уже с другой стороны:
Так как мы работаем с регистром eax, то именно его значение и будем отслеживать.
(в правом окне, 1 значение регистров)
Итак, чтобы пошагово прогнать нашу программу нужно нажать на 4 синию кнопку слева.(стрелка вниз с 3 точками)
После 1 нажатия, значение в eax стало равно 3, после 2 нажатия — 5.
Наша программа работает верно!
Итак, казалось бы простая программа сложения 2 чисел на Assembler, а сколько всего узнали! На сегодня все, оставляйте свои комментарии, если у вас есть вопросы или пожелания.
Скачать исходники
ассемблер — Сложение чисел на ассемблере
Есть такая программа, считывающая два числа, складывающая их и выводящая результат:
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
section .text
global _start
_start:
mov edx, len1
mov ecx, msg1
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
mov ecx, numX
mov edx, 2
mov ebx, STDIN
mov eax, SYS_READ
int 0x80
mov edx, len2
mov ecx, msg2
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
mov ecx, numY
mov edx, 2
mov ebx, STDIN
mov eax, SYS_READ
int 0x80
mov eax, [numX]
sub eax, '0'
mov ebx, [numY]
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [res], eax
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg4
mov edx, len4
int 0x80
mov eax,SYS_EXIT
int 0x80
section .
data
msg1 db 'X=',
len1 equ $-msg1
msg2 db 'Y=',
len2 equ $-msg2
msg3 db 'X+Y='
len3 equ $-msg3
msg4 db 0xA, 0xB
len4 equ 2
segment .bss
numX resb 2
numY resb 2
res resb 1
Вот что показывает objdump -D
app: file format elf32-i386 Disassembly of section .text: 08049000 <.text>: 8049000: ba 02 00 00 00 mov $0x2,%edx 8049005: b9 00 a0 04 08 mov $0x804a000,%ecx 804900a: bb 01 00 00 00 mov $0x1,%ebx 804900f: b8 04 00 00 00 mov $0x4,%eax 8049014: cd 80 int $0x80 8049016: b9 0c a0 04 08 mov $0x804a00c,%ecx 804901b: ba 02 00 00 00 mov $0x2,%edx 8049020: bb 00 00 00 00 mov $0x0,%ebx 8049025: b8 03 00 00 00 mov $0x3,%eax 804902a: cd 80 int $0x80 804902c: ba 02 00 00 00 mov $0x2,%edx 8049031: b9 02 a0 04 08 mov $0x804a002,%ecx 8049036: bb 01 00 00 00 mov $0x1,%ebx 804903b: b8 04 00 00 00 mov $0x4,%eax 8049040: cd 80 int $0x80 8049042: b9 0e a0 04 08 mov $0x804a00e,%ecx 8049047: ba 02 00 00 00 mov $0x2,%edx 804904c: bb 00 00 00 00 mov $0x0,%ebx 8049051: b8 03 00 00 00 mov $0x3,%eax 8049056: cd 80 int $0x80 8049058: a1 0c a0 04 08 mov 0x804a00c,%eax 804905d: 83 e8 30 sub $0x30,%eax 8049060: 8b 1d 0e a0 04 08 mov 0x804a00e,%ebx 8049066: 83 eb 30 sub $0x30,%ebx 8049069: 01 d8 add %ebx,%eax 804906b: 83 c0 30 add $0x30,%eax 804906e: a3 10 a0 04 08 mov %eax,0x804a010 8049073: b8 04 00 00 00 mov $0x4,%eax 8049078: bb 01 00 00 00 mov $0x1,%ebx 804907d: b9 10 a0 04 08 mov $0x804a010,%ecx 8049082: ba 01 00 00 00 mov $0x1,%edx 8049087: cd 80 int $0x80 8049089: b8 04 00 00 00 mov $0x4,%eax 804908e: bb 01 00 00 00 mov $0x1,%ebx 8049093: b9 08 a0 04 08 mov $0x804a008,%ecx 8049098: ba 02 00 00 00 mov $0x2,%edx 804909d: cd 80 int $0x80 804909f: b8 01 00 00 00 mov $0x1,%eax 80490a4: cd 80 int $0x80 Disassembly of section .data: 0804a000 <.data>: 804a000: 58 pop %eax 804a001: 3d 59 3d 58 2b cmp $0x2b583d59,%eax 804a006: 59 pop %ecx 804a007: 3d .byte 0x3d 804a008: 0a 0b or (%ebx),%cl Disassembly of section .bss: 0804a00c <.bss>: ...
Вот что показывает отладчик:
(gdb) run Starting program: /home/rikitikitavi/projects/asm/app X=5 Y=5 Breakpoint 1, 0x08049058 in ?? () (gdb) c Continuing. Breakpoint 2, 0x08049069 in ?? () (gdb) info registers eax 0xa350a05 171248133 ecx 0x804a00e 134520846 edx 0x2 2 ebx 0xa05 2565 esp 0xffffd140 0xffffd140 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8049069 0x8049069 eflags 0x206 [ PF IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 (gdb) si 0x0804906b in ?? () (gdb) info registers eax 0xa35140a 171250698 ecx 0x804a00e 134520846 edx 0x2 2 ebx 0xa05 2565 esp 0xffffd140 0xffffd140 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x804906b 0x804906b eflags 0x206 [ PF IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0
Как видно из objdump по адресу 0x08049069 находится команда сложения — add %ebx,%eax.
Перед выполнением этой команды в регистрах eax и ebx должны быть необходимые числа 5 и 5, вместо этого я вижу 0xa350a05 и 0xa05 соответственно. 05 на конце как бы намекает что регистры содержат то что мне нужно, но что за остальная часть? — я правильно понимаю что — это содержимое регистров al и bl а остальное мусор? Тогда откуда он взялся?
Дальше я прибавляю код 0 к результату записываю в память и вывожу. Если при вводе вводить 4 и 5 то все работает:
rikitikitavi@rikitikitavi:~/projects/asm$ ./app X=4 Y=5 9
а вот если ввести 5 и 5 то все ломатеся:
rikitikitavi@rikitikitavi:~/projects/asm$ ./app X=5 Y=5 :
Мне даже понятно почему ломается — потому что в десятичной системе появляется второй разряд и прибавлять код 0 не совсем корректоно (Хотя результат в принципе правильный : идет сразу после 9 в таблице acsii).
Нужно как-то подругому выводить результат, но мне непонятно как?
Теперь коротко вопросы:
- Почему в отладчике я вижу какие-то непонянтые значения регистров?
- Как переделать вывод результата?
c — добавить два числа в сборку
спросил
Изменено 9 месяцев назад
Просмотрено 33 тысячи раз
Часть коллектива Intel
Я только начинаю заниматься сборкой и хотел создать простую программу, которая складывает два числа и печатает результат
Вот что у меня есть:
.globl main .тип основной, @функция главный: мовл $14, %eax movl $10, %ebx добавить %eax, %ebx вызов printf
Насколько я понимаю, вот что происходит построчно
Строка 1: Я создаю метку main, к которой может получить доступ компоновщик
Строка 2: Я указываю тип метки main для функции
Строка 3: я начинаю определение main
Строка 4: я сохраняю числовое значение 14 в регистре общего назначения eax
Строка 5: я сохраняю числовое значение 10 в регистре общего назначения ebx
Строка 6: я складываю значения в eax и ebx и сохраняю результат в ebx
Строка 7: я вызываю функцию printf (вот где я получаю запутался)
Как указать, какое значение в каком регистре будет напечатано?
И как пройти эту программу? В настоящее время при запуске программа приводит к ошибке сегментации.
- c
- линукс
- сборка
- x86
4
РАЗДЕЛ .data
внешний printf
глобальный основной
ФМТ:
дб "%d", 10, 0
РАЗДЕЛ .text
главный:
мов акс, 14
мов ебкс, 10
добавить eax, ebx
нажать eax
нажмите ФМТ
вызов printf
мов акс, 1
интервал 0x80
К сожалению, я не знаю, какой компилятор/ассемблер вы используете, и я не знаком с синтаксисом at&t, поэтому я дал вам рабочий пример в стиле Intel x86 для Nasm.
$ nasm -f elf32 тест.с -о тест.о $ gcc test.o -m32 -o тест $ ./тест 24
Чтобы использовать printf, вам нужно фактически поместить аргументы в стек, я делаю это здесь в обратном порядке (сначала поместите последние аргументы):
push eax нажмите ФМТ
EAX содержит результат добавления eax, ebx, а метка ‘fmt’ представляет собой массив символов: «%d\n\0» (формат %d, новая строка, нулевой терминатор).
После вызова printf вам необходимо выйти из программы с помощью системного вызова exit, иначе (по крайней мере, для меня) программа выдаст ошибку ПОСЛЕ printf, даже если она сработала, и вы не увидите результата.
Итак, эти две строки:
mov eax, 1 интервал 0x80
выполняют системный вызов sys_exit, помещая порядковый номер выхода на x86 (1) в EAX, а затем вызывая прерывание 0x80, это завершает программу без ошибок.
7
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Требуется, но никогда не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
masm — Сложить 2 числа на ассемблере и вывести результат
спросил
Изменено 5 лет, 9 месяцев назад
Просмотрено 65 тысяч раз
нужна помощь, как сложить два числа и потом распечатать результат вот мой код
.МОДЕЛЬ МАЛЕНЬКАЯ .СТЕК 200Ч .ДАННЫЕ NUM1 БД 12 NUM2 БД 3 ВАЛ БД? БД MSG1 "Сумма: $" .КОД НАЧАТЬ ПРОЦЕСС MOV AX, @ДАННЫЕ ДВИГАТЕЛЬ ДС, AX МОВ АЛ, НОМЕР1 ДОБАВИТЬ AL, NUM2 МОВ ВАЛ, АЛ ЛЕА DX, MSG1 МОВ А.Г., 9ИНТ 21Ч МОВ АГ, 2 МОВ ДЛ, ВАЛ ИНТ 21Ч ДВИГАТЕЛЬ AX, 4C00H ИНТ 21Ч НАЧАТЬ КОНЕЦ КОНЕЦ НАЧАЛО
Я получил вывод, который говорит
Сумма равна 0
В чем ошибка моего кода?
- сборка
- масм
3
Постоянно деля значение на 10, вы получите однозначные числа в остатке, но в «неправильном» порядке (от последнего к первому). Чтобы напечатать его в «правильном» порядке (с первого на последний), вы можете поменять их местами на 9.0122 PUSH ing и POP ing (ключевое слово: LIFO = последний пришел первым вышел):
.МОДЕЛЬ МАЛЕНЬКАЯ
.СТЕК 200Ч
.ДАННЫЕ
NUM1 БД 12
NUM2 БД 3
ВАЛ ДВ ?
MSG1 DB "Сумма:"
ДЕСЯТИЧНАЯ БД "00000$"
.
КОД
НАЧАТЬ ПРОЦЕСС
MOV AX, @ДАННЫЕ
ДВИГАТЕЛЬ ДС, AX
XOR ТОПОР, ТОПОР
МОВ АЛ, НОМЕР1
ДОБАВИТЬ AL, NUM2
АЦП АХ, 0
МОВ ВАЛ, AX
MOV AX, ВАЛ
ЗВОНИТЕ AX_to_DEC
ЛЕА DX, MSG1
МОВ А.Г., 9
ИНТ 21Ч
ДВИГАТЕЛЬ AX, 4C00H
ИНТ 21Ч
НАЧАТЬ КОНЕЦ
AX_to_DEC PROC
мов бх, 10 ; делитель
xor сх, сх ; CX=0 (количество цифр)
Первый_цикл:
xor дх, дх ; Внимание: DIV применим также и к DX!
делитель бх; DX:AX / BX = AX остаток: DX
нажать дх ; ЛИФО
вкл сх ; увеличить количество цифр
тестовый топор, топор ; АХ = 0?
jnz Первый_цикл; нет: еще раз
mov di, ДЕСЯТИЧНОЕ СМЕЩЕНИЕ ; целевая строка DECIMAL
Второй цикл:
поп-топор; вернуть нажатую цифру
или топор, 00110000b ; в ASCII
mov byte ptr [di], al ; сохранить AL
вкл ди ; DI указывает на следующий символ в строке DECIMAL
цикл Second_Loop ; пока не останется цифр
mov byte ptr [di], '$' ; Разделитель конца строки для INT 21 / FN 09час
рет
AX_to_DEC ENDP
КОНЕЦ НАЧАЛО
Вы не можете сделать это так, Вы не увидите число, Вы должны получить ascii, представляющие шестнадцатеричные значения s цифр, которые представляют Ваш результат.
386
.model flat,stdcall
.data
.code
start:
mov eax,3
add eax,2
ret
end start
data
msg1 db 'X=',
len1 equ $-msg1
msg2 db 'Y=',
len2 equ $-msg2
msg3 db 'X+Y='
len3 equ $-msg3
msg4 db 0xA, 0xB
len4 equ 2
segment .bss
numX resb 2
numY resb 2
res resb 1

МОДЕЛЬ МАЛЕНЬКАЯ
.СТЕК 200Ч
.ДАННЫЕ
NUM1 БД 12
NUM2 БД 3
ВАЛ БД?
БД MSG1 "Сумма: $"
.КОД
НАЧАТЬ ПРОЦЕСС
MOV AX, @ДАННЫЕ
ДВИГАТЕЛЬ ДС, AX
МОВ АЛ, НОМЕР1
ДОБАВИТЬ AL, NUM2
МОВ ВАЛ, АЛ
ЛЕА DX, MSG1
МОВ А.Г., 9ИНТ 21Ч
МОВ АГ, 2
МОВ ДЛ, ВАЛ
ИНТ 21Ч
ДВИГАТЕЛЬ AX, 4C00H
ИНТ 21Ч
НАЧАТЬ КОНЕЦ
КОНЕЦ НАЧАЛО
КОД
НАЧАТЬ ПРОЦЕСС
MOV AX, @ДАННЫЕ
ДВИГАТЕЛЬ ДС, AX
XOR ТОПОР, ТОПОР
МОВ АЛ, НОМЕР1
ДОБАВИТЬ AL, NUM2
АЦП АХ, 0
МОВ ВАЛ, AX
MOV AX, ВАЛ
ЗВОНИТЕ AX_to_DEC
ЛЕА DX, MSG1
МОВ А.Г., 9
ИНТ 21Ч
ДВИГАТЕЛЬ AX, 4C00H
ИНТ 21Ч
НАЧАТЬ КОНЕЦ
AX_to_DEC PROC
мов бх, 10 ; делитель
xor сх, сх ; CX=0 (количество цифр)
Первый_цикл:
xor дх, дх ; Внимание: DIV применим также и к DX!
делитель бх; DX:AX / BX = AX остаток: DX
нажать дх ; ЛИФО
вкл сх ; увеличить количество цифр
тестовый топор, топор ; АХ = 0?
jnz Первый_цикл; нет: еще раз
mov di, ДЕСЯТИЧНОЕ СМЕЩЕНИЕ ; целевая строка DECIMAL
Второй цикл:
поп-топор; вернуть нажатую цифру
или топор, 00110000b ; в ASCII
mov byte ptr [di], al ; сохранить AL
вкл ди ; DI указывает на следующий символ в строке DECIMAL
цикл Second_Loop ; пока не останется цифр
mov byte ptr [di], '$' ; Разделитель конца строки для INT 21 / FN 09час
рет
AX_to_DEC ENDP
КОНЕЦ НАЧАЛО