Автор: xrnd | Рубрика: Исходники | 27-12-2010
В части 22 учебного курса рассматривались способы преобразования чисел в строку. Однако, вывести в десятичном виде число больше 32 бит не так просто. Сложность в том, что требуется делить число на 10, а число слишком большое и в регистры DX:AX не помещается.
К счастью, в программе на ассемблере можно делить числа любой разрядности 🙂 Правда, одной командой DIV тут не обойтись. Придётся реализовать специальный алгоритм.
Читать полностью »
В прошлой части мы научились преобразовывать числа в строку и выводить на консоль. А в этой займёмся обратной задачей — вводом чисел с консоли и преобразованием строки в число. Поскольку ввод в двоичном и восьмеричном виде используется редко, я рассмотрю только примеры ввода чисел в десятичном виде (со знаком и без знака) и в шестнадцатеричном.
Вводить числа сложнее, чем выводить, так как помимо преобразования необходимо проверять корректность введённой пользователем строки. Хорошая программа должна устойчиво работать при любых входных данных (в том числе специально введённых так, чтобы нарушить её работу).
Ввод строки с консоли
Для ввода строки можно использовать функцию MS-DOS 0Ah. Функция позволяет ввести строку длиной от 1 до 254 символов. При вызове в DX передаётся адрес буфера, первый байт которого должен содержать максимально допустимую длину строки. Длина считается вместе с символом конца строки CR (0dh). В результате работы функции во второй байт буфера записывается фактическая длина введённой строки (не считая символа CR). Начиная с третьего байта в буфер записываются символы строки. Подробнее о работе функции можно узнать в раритетном справочнике по DOS 🙂
Читать полностью »
Автор: xrnd | Рубрика: Исходники | 31-07-2010
Эта статья посвящена разбору примера умножения 32-битных чисел на 16-битном процессоре. Как вы наверно знаете, команда MUL в 16-битном режиме позволяет умножать максимум 16-битные значения, поэтому для умножения 32-битных чисел необходим специальный алгоритм.
Умножать большие числа приходится по частям, а затем складывать эти промежуточные результаты. Чтобы всё стало понятно я напишу небольшую формулу. Допустим, нам надо умножить два 32-битных числа a и b. В результате должно получиться 64-битное число c. Обозначим как a1 — младшее слово a, a2 — старшее слово a, b1 — младшее слово b, b2 — старшее слово b. Тогда получается:
a = (a2<<16) + a1
b = (b2<<16) + b1
Символы <<16 обозначают сдвиг влево на 16 бит. По сути это то же самое, что умножить на 65536.
c = a x b = ((a2<<16) + a1) x ((b2<<16) + b2) =
= (a1 x b1) + ((a2 x b1)<<16) + ((a1 x b2)<<16) + ((a2 x b2)<<32)
Алгоритм очень напоминает способ умножения в столбик. Графически можно изобразить следующим образом:
Читать полностью »
В качестве примера программирования процедур займёмся такой важной проблемой, как вывод на консоль чисел в различных системах счисления. Проблема эта возникает потому, что в ассемблере нет никаких специальных средств для вывода чисел, а с помощью стандартных функций можно выводить только строки.
Следовательно, задача сводится к тому, чтобы преобразовать двоичное число в строку символов, а затем вывести эту строку на экран. Все процедуры в этой части являются лишь примерами, вы можете использовать их или написать свои собственные процедуры, более удобные для вас.
Для начала рассмотрим две полезные процедуры, которые будут использоваться в дальнейшем. Чтобы постоянно не обращаться в коде в функции DOS 09h, удобно написать маленькую процедуру для вывода строки:
;Процедура вывода строки на консоль
; DI - адрес строки
print_str:
push ax
mov ah,9 ;Функция DOS 09h - вывод строки
xchg dx,di ;Обмен значениями DX и DI
int 21h ;Обращение к функции DOS
xchg dx,di ;Обмен значениями DX и DI
pop ax
ret |
;Процедура вывода строки на консоль
; DI - адрес строки
print_str:
push ax
mov ah,9 ;Функция DOS 09h - вывод строки
xchg dx,di ;Обмен значениями DX и DI
int 21h ;Обращение к функции DOS
xchg dx,di ;Обмен значениями DX и DI
pop ax
ret
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 07-05-2010
Сдвиги — это особые операции процессора, которые позволяют реализовать различные преобразования данных, работать с отдельными битами, а также быстро выполнять умножение и деление чисел на степень 2. В этой части мы рассмотрим операции линейного сдвига, а в следующей будут циклические.
Логический сдвиг вправо
Логический сдвиг всегда выполняется без учёта знакового бита. Для логического сдвига вправо предназначена команда SHR. У этой команды два операнда. Первый операнд представляет собой сдвигаемое значение и на его место записывается результат операции. Второй операнд указывает, на сколько бит нужно осуществить сдвиг. Этим операндом может быть либо непосредственное значение, либо регистр CL. Схема выполнения операции показана на рисунке:
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 18-04-2010
Очень часто в программах приходится выполнять действия с числами разного размера, например складывать или умножать байт и слово. Напрямую процессор не умеет выполнять такие операции, поэтому в этом случае необходимо выполнять преобразование типов. Сложность представляет преобразование меньших типов в большие (байта в слово, слова в двойное слово и т.д.)
Преобразовать больший тип в меньший гораздо проще — достаточно отбросить старшую часть. Но такое преобразование небезопасно и может привести к ошибке. Например, если значение слова без знака больше 255, то сделав из него байт, вы получите некорректное значение. Будьте внимательны, если вы используете такие трюки в своей программе.
Преобразование типов без знака
Преобразование типов выполняется по-разному для чисел со знаком и без. Для преобразования чисел без знака необходимо просто заполнить все старшие биты нулями. Например, так будет выглядеть преобразование байта в слово:
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 01-04-2010
Умножение и деление выполняются по-разному для чисел со знаком и без, поэтому в системе команд процессора x86 есть отдельные команды умножения и деления для чисел со знаком и для чисел без знака.
Умножение чисел без знака
Для умножения чисел без знака предназначена команда MUL. У этой команды только один операнд — второй множитель, который должен находиться в регистре или в памяти. Местоположение первого множителя и результата задаётся неявно и зависит от размера операнда:
Размер операнда |
Множитель |
Результат |
Байт |
AL |
AX |
Слово |
AX |
DX:AX |
Отличие умножения от сложения и вычитания в том, что разрядность результата получается в 2 раза больше, чем разрядность сомножителей. Также и в десятичной системе — например, умножая двухзначное число на двухзначное, мы можем получить в результате максимум четырёхзначное. Запись «DX:AX» означает, что старшее слово результата будет находиться в DX, а младшее — в AX. Примеры:
mul bl ;AX = AL * BL
mul ax ;DX:AX = AX * AX |
mul bl ;AX = AL * BL
mul ax ;DX:AX = AX * AX
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 30-03-2010
В системе команд процессоров x86 имеются специальные команды сложения и вычитания с учётом флага переноса (CF). Для сложения с учётом переноса предназначена команда ADC, а для вычитания — SBB. В общем, эти команды работают почти также, как ADD и SUB, единственное отличие в том, что к младшему разряду первого операнда прибавляется или вычитается дополнительно значение флага CF.
Зачем нужны такие команды? Они позволяют выполнять сложение и вычитание многобайтных целых чисел, длина которых больше, чем разрядность регистров процессора (в нашем случае 16 бит). Принцип программирования таких операций очень прост — длинные числа складываются (вычитаются) по частям. Младшие разряды складываются(вычитаются) с помощью обычных команд ADD и SUB, а затем последовательно складываются(вычитаются) более старшие части с помощью команд ADC и SBB. Так как эти команды учитывают перенос из старшего разряда, то мы можем быть уверены, что ни один бит не потеряется 🙂 Этот способ похож на сложение(вычитание) десятичных чисел в столбик.
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 27-03-2010
Числа со знаком и дополнительный код
Помимо того, что процессор работает с двоичными числами, эти числа могут быть со знаком или без знака. Если число без знака, то оно просто представляет собой результат перевода десятичного числа в двоичный вид. Все биты в таком числе являются информационными и оно может принимать только неотрицательные значения.
Для представления чисел со знаком используется специальное кодирование. Старший бит в этом случае обозначает знак числа. Если знаковый бит равен нулю, то число положительное, иначе — отрицательное. Понятно, что положительное число со знаком будет выглядеть точно так же, как и число без знака.
С отрицательными числами чуть сложнее. Исторически для представления отрицательных чисел в компьютерах использовались разные виды кодирования: прямой, обратный и дополнительный код. В настоящее время наиболее часто используется дополнительный код, в том числе и в процессорах x86.
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 19-03-2010
Эта статья по большей части для совсем начинающих. Если вы хорошо разбираетесь в системах счисления, можете обратить внимание лишь на особенности синтаксиса ассемблера FASM в конце статьи.
На самом деле процессор работает только с двоичными числами, состоящими из единиц и нулей 🙂 В виде двоичных чисел хранятся и обрабатываются все данные и команды любой программы. Однако, двоичная запись чисел слишком громоздка и неудобна для человека, поэтому в программах на ассемблере используются и другие системы счисления: десятичная, шестнадцатеричная и восьмеричная.
Читать полностью »