Разное

Ассемблер сложение чисел: Сложение чисел на Assembler — CodeTown.ru

Сложение чисел на 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 на конце как бы намекает что регистры содержат то что мне нужно, но что за остальная часть? — я правильно понимаю что

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). Нужно как-то подругому выводить результат, но мне непонятно как?

Теперь коротко вопросы:

  1. Почему в отладчике я вижу какие-то непонянтые значения регистров?
  2. Как переделать вывод результата?

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 цифр, которые представляют Ваш результат.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *