Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
|
1 | |
TAJGA FASM Tutorial10.09.2014, 12:34. Показов 8923. Ответов 6
Метки нет (Все метки)
Содержание
5
|
10.09.2014, 12:34 | |
Ответы с готовыми решениями:
6
Вызываю dll (написанную на vc++2008) из Fasm. Через 40 секунд вылет из программы.Без вызова dll из Fasm программа не вылетает. Tutorial Best CSS3 Tutorial __asm__ tutorial |
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11.09.2014, 12:02 [ТС] | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1. О туториале
Для кого? Туториал предназначен для новичков, какие-либо познания в программировании не требуется. Хотя изучение ассемблера в качестве первого языка программирования довольно сложно, это возможно. Необходимо лишь знать как работать в командной строке (command.com в DOS/win95/98/ME, cmd.exe в winNT/2K/XP). Некоторое знание программирования весьма желательно, но не обязательно. Какая OS? Я решил написать туториал для DOS, потому что он позволяет использовать компьютер наиболее полно, в отличие от Windos. Я хочу рассмотреть некоторые вопросы которые недоступны в Windos, так что DOS — единственный вариант. Перейти от DOS к Windos не очень сложно, если Вы знаете защищенный режим, так же существуют туториалы Iczelion'а рассказывающие об этом. Лично мне не нравится начинать изучение ассемблера под Windos, из-за того что там некоторые вещи скрыты от нас. Статус написания туториала Туториал очень далек от завершения, но содержит достаточно информации для начала. В настоящее время пишется 7-я глава об арифметических инструкциях. Дополнительные разделы В туториал включена так же статья связанная с особенностями FASM: Правовая информация Туториал предоставляется без всяких гарантий (Вы используете его на свой страх и риск ). Это так же значит, что Вы можете делать с ним всё, что хотите. Если Вы планируете включить туториал или его часть в свой проект, или перевести его на другой язык, или что-то в этом духе, было бы хорошо написать автору и упомянуть ник vid где-нибудь. Как бы то ни было, если Вам так будет удобнее — распространяйте под своим именем, Вы заработаете какую-нибудь репутацию (возможно, ламера). Вы можете посодействовать улучшению этого туториала отправляя свои замечания на форум FASM, форум WASM или на e-mail если хотите. Так же, если Вы что-то найдёте непонятным, пожалуйста сообщите об этом, что бы я мог исправить это для будущих читателей. Оригинальный туториал конвертировал в HTML Decard. Он так же написал утилиту для перевода исходников FASM в HTML с подсветкой синтаксиса. 2. Вступление Зачем использовать Ассемблер FASM? На самом деле, не существует никакого стандарта на синтаксис Ассемблера. Возможно найти множество ассемблеров (компиляторов Ассемблера) с весьма разными синтаксисами. Наиболее общепринятый – это MASM, потом TASM с почти одинаковым синтаксисом. Мое мнение – этот синтаксис весьма глупый, но это то, что люди обычно называют Синтаксис Ассемблера. Не плохо бы узнать как минимум его основы, что бы понять чужой код. Но здесь больше не будет упоминания о MASM или TASM. Еще один распространенный синтаксис имеет NASM. Это очень хороший ассемблер, с подобным FASMу синтаксисом, но он немногим более сложноват, да и макроязык у него похуже. Для действительно больших проектов он, возможно, лучше чем FASM, но существует не так много больших проектов, написанных на любом из ассемблеров. Другой, принятый социумом – это Linux'овый as. Все, что перечислено выше – сложные ассемблеры с множеством бесполезных возможностей. FASM – маленький, быстрый (быстрейший), свободный (в отличие от некоторых других). Вы можете писать на нем программы быстрее или с той же скоростью как и в других ассемблерах. Когда я впервые увидел FASM, я уже знал MASM/TASM и был поражен, насколько истинен его синтаксис. И, позже, когда я постиг его макроязык, я начал писать код в два раза быстрее чем прежде. Предоставьте ему шанс. 2.1. Использование FASM Компилятор Для начала нужно скачать компилятор FASM. Есть несколько версий: для DOS, Win32 консоли, версия Win32 GUI. И для Linuxа — использоваться не будет. Скачайте две версии для windos. Дополнительно можете использовать какое-либо IDE. Компиляция В GUI версии, стОит нажать CTRL-F9 и открытый файл откомпилируется (или F9 чтобы еще и запустить его потом). В консольной версии напишите в командной строке следующий текст:
3. Начало работы Здесь я предвижу, что у вас есть некоторые основные понятия о том, что такое байты и кое-какие идеи об ASCII-кодах. Возможно, я расскажу об ASCII в более поздних версиях туториала. Для начала попытаемся скомпилировать пустой исходный файл. Прямо сейчас создайте пустой файл empty.asm и напишите в командной строке:
Теперь мы сотворим файл, содержащий кое-какие данные. Создайте текстовый файл содержащий в себе строку:
Пора проанализировать (?) исходник: db — это директива которая значит определить байт (от английского define byte). Итак, эта директива поместит байт в целевой файл. Значение байта должно следовать непосредственно за директивой. К примеру, db 0 поместит в целевой файл байт со значением 0. Но если Вы хотите ввести таким образом какой-то символ, надо бы помнить его ASCII значение. В таком случае можно поместить символ между апострофами ' или кавычками " и компилятор найдет это значение за Вас. Вот так работает этот код.
Но что, если Вы хотите чего-то большего, к примеру файл содержащий Это моя первая длинная строка в FASM? Можно написать:
4. Первая программа Вам наверняка интересно, зачем я шучу с созданием каких-то текстовых файлов, когда Вы хотите научиться Ассемблеру. Но текстовые файлы — лишь некоторые наборы байт. Вы только что научились не создавать текстовый файл, а узнали как описАть файл, содержащий любые данные, какие хотите. И это как раз то, что представляет собой запускаемая программа — файл со специальными данными, массив числовых значений, называемых машинный код. Вам всего лишь нужно знать смысл этих числовых значений . Конечно, очень трудно запомнить все эти цифры и их значение, но для этих целей и существует Ассемблер. Он переводит программу с языка понятного человеку в машинный код. Итак, Вам осталось лишь изучить этот язык, понятный человеку .
3
|
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11.09.2014, 12:11 [ТС] | 3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Теперь уделим внимание ДОСовым программам COM, изредка называемых memory image. Это самые простые выполняемые (запускаемые) файлы в DOS и Windows. Итак, давайте создадим первый COM файл, который ничего не делает:
Итак, машинный код — это набор инструкций. Следует различать директивы и инструкции. Инструкция определяет данные, которые определяют что процессор будет делать во время выполнения. К примеру db 0,0 — директива задающая два нулевых байта, но это еще и инструкция, потому что 2 нуля имеют специальное значение для процессора (пока оставим значение без внимания). org 100h — это директива, а не инструкция, так как она не определяет никаких данных. Вы вникните в это на практике. Инструкция int 20h — простая, ей не надо никаких аргументов. Но что, если какой-то инструкции нужны аргументы? Для таких случаев процессор имеет свои собственные переменные. Эти переменные называются регистры. Первые регистры, которые мы узнаем — это al, ah, bl, bh, cl, ch, dl, dh, их размер равен байту (они могут содержать значение от 0 до 255).
Как же тогда установить значение регистра? Для этого есть инструкции, к примеру:
Другой пример:
ПРИМЕЧАНИЕ: Вы часто (постоянно?) будете видеть, как люди говорят об инструкции mov. Но mov — не инструкция, и int тоже. mov al,bl и int 20h — это примеры инструкций. mov и int называются мнемоники инструкций. Но согласитесь, все называют их инструкциями, и Вы, вероятно, будете вскоре тоже (и я, наверное, тоже, к сожалению . Аргументы инструкций (части инструкций без мнемоники, такие как al и 10 в mov al,10) называются операндами инструкции (или аргументами инструкции
ПРИМЕЧАНИЕ: если используете какую-нибудь Windows и файловый менеджер (вроде Total Commander), то увидите окно, которое появляется и сразу исчезает. Но ваш символ отображается в этом окне, и Вы вероятно не можете это заметить. Необходимо запустить DOS-оболочку (cmd в 2K/XP, command в более старых windows) и запускать программу из нее (лучше попробуйте FAR). В любом случае, если Вы не можете справиться с этим, забудьте о ассемблере на некоторое время, и подучитесь пользоваться операционной системой. Но потом, не забудьте вернуться к ассемблеру! ОК. Итак давайте взглянем на программу выводящую символ "a":
ПРИМЕЧАНИЕ: в Ассемблере символ, заключенный в кавычки - то же самое, что и ASCII-код для этого символа. Итак, вывод нескольких символов "ab":
5. Метки, адреса и переменные ОК, давайте перейдем к переменным. В предыдущей главе я писал, что переменные — это общий термин для места, где хранится какое-либо значение. Регистры, к примеру, тоже переменные. Но количество регистров ограничено. (очень ограничено, каких-то 8 + несколько специальных) и их практически всегда недостаточно. По этой причине используется память RAM ПРИМЕЧАНИЕ: когда говорят о переменных, обычно имеют ввиду переменные в памяти. 5.1. Метки Проблема заключается в том, что нужно знать где в памяти хранится какое-то значение (переменной). Позиция в памяти (называемая адрес) представляет собой число. Но достаточно сложно помнить это число для каждой переменной.
Другая проблема с адресами — когда Вы изменяете свою программу, адрес тоже может измениться, и придется корректировать этот номер повсюду где он используется. Исходя из этих соображений, вместо реальных адресов используют метки. Метка — всего лишь какое-то слово (не строка, она не заключается в кавычки), которое в программе исполняет роль адреса в памяти. Когда Вы компилируете программу, каждая метка заменяется соответствующим адресом. Для написания метки используются: символы латинского алфавита a .. z, A .. Z), цифры 0 .. 9, знак подчеркивания "_" и точка ".". Но первый символ метки не должен быть числом или точкой. Так же, имя метки не может совпадать с директивой или инструкцией (мнемоникой инструкции). В FASM'е метки чувствительны к регистру ("a" не то же, что "A"). Примеры меток
Можно дать определение метки используя директиву label. После этой директивы нужно указать метку (имя метки). Например:
2
|
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11.09.2014, 12:16 [ТС] | 4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Все это определяет метки, означающие адреса данных, определяемых следом за этими директивами.
5.2. Определение переменных Теперь можно вернуться к проблеме переменных: как определить переменную в памяти. Ваша программа скомпилированная в машинный код для выполнения загружается в память, где процессор выполняет ее инструкция за инструкцией. Взгляните на это:
Теперь взгляните на это:
Итак, программа, где есть переменная размером один байт и значением 105:
Теперь, как же получить доступ к переменной? Для начала необходимо знать ее адрес. Для этого можно использовать метку (про это рассказывалось ранее, перечитайте, если забыли):
Как добраться до содержимого переменной? Возможно, Вы думаете, к примеру так:
Проблема в том, что мы знаем, что изменяем значение переменной по адресу variable1 на 10, но каков размер переменной? В предыдущих двух случаях был определенный размер — байт. Так как использовался регистр al, размер которого равен байту, то компилятор решил, что и переменная находящаяся по адресу variable1 имеет размер один байт. Чтобы разрешить существующую неопределенность воспользуемся операторами размера. Сейчас будем говорить о двух таких операторах: byte и word. Можно помещать такие операторы перед операндом инструкции, чтобы компилятор мог знать размер переменной:
Но может быть сложно постоянно запоминать и указывать размер переменных, когда их используем. Для таких целей можно установить размер переменной при ее определении. Всего лишь написАть оператор размера после имени метки:
ПРИМЕЧАНИЕ: оператор размера, заданный при определении метки имеет меньший приоритет, чем при использовании в инструкции, так что здесь будет использован байт:
Теперь поговорим об адресах подробнее. Я уже говорил, что адрес — это число (!) которое определяет какую-то позицию в памяти. Мы научились представлять эти числа метками, так что теперь числовые значения адресов — забота компилятора. Но Вы до сих пор ничего не знаете о формате этих чисел. Я попытаюсь разъяснить это в данной главе. Как вы возможно знаете, данные в памяти хранятся в виде битов, которые могут иметь значение 0 или 1. Можно рассматривать память как одномерный массив битов. 8 идущих друг за другом битов образуют один байт. Адрес — это номер (индекс, позиция в массиве) байта. К примеру адрес 0 — это адрес первого бита в памяти (или адрес первого байта), адрес 1 — это адрес восьмого бита (или адрес второго байта) и так далее. Адреса в COM-файлах — это числа размером в слово, так что
Теперь некоторый пример с адресами. Исследуйте этот файл:
ОК. Это выглядит красиво, но это совсем не правда. Проблема в том, что обычно, в одно и тоже время, в памяти загружено много программ (операционная система, драйвер мыши, Ваша программа и так далее). И в этом случай программе необходимо знать, в каком месте памяти она загружена, чтобы она могла добраться до своих переменных. По этой причине адреса являются относительными. Это значит, что для каждой загруженной в память программы резервируется некоторая область, называемая сегмент. Все адреса в памяти, к которым обращается эта программа, в этом случае зависят от начала этой области. Так, [0] не значит первый байт памяти, это значит первый байт сегмента. Код
сегмент (segment) непрерывная область памяти, описываемая селектором ПРИМЕЧАНИЕ: Я говорил, что адреса в COM-файле — word'ы. Это значит, что они находятся в диапазоне 0..65535. Так, максимальный размер сегмента = 65536 байт. Это можно обойти меняя содержимое сегментных регистров, но не придавайте этому особого значения сейчас. ПРИМЕЧАНИЕ: Сегмент — это регион памяти. Но термин сегмент часто используется для адреса начала этого региона. Печально, но факт. Итак, абсолютный адрес в памяти состоит из двух частей: селектора (то есть адрес начала сегмента) и второй части, значения размером word, называемой офсет или смещение — то есть адрес от начала сегмента. Код
офсет (offset) смещение в байтах от начала сегмента Я не буду углубляться в сегментные регистры, в то, как хранится в них адрес начала сегмента (здесь есть разница). Примите их как "черный ящик" пока — это работает и мы можем не обращать внимание на них.
1
|
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11.09.2014, 12:26 [ТС] | 5 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.4. Объяснение директивы org
Когда Ваша программа загружена, ей, как правило, нужна какая-то внешняя информация (информация из программы, которая ее запустила). Лучший пример — аргументы в командной строке, или необходимость знать, кто нас запустил. Конечно, эти данные должны находиться в том же сегменте, что и программа. В COM-файлах все это, предоставленное программе DOS'ом, хранится в первых 256 байтах сегмента. Так что программа загружается по смещению 256. ПРИМЕЧАНИЕ: 256-ти байтная структура перед началом COM-файла называется PSP — program segment prefix (префикс программного сегмента) Теперь, представим такую COM программу:
Так, программа выше будет обращаться не к нужной переменной, а куда-то в PSP (первые 256 байт сегмента). Чтобы она работала правильно, используем:
Я не буду говорить о данных в PSP, пока не стоит о них беспокоиться. Вы уже должны иметь кое-какое достаточно точное представление о байтовых переменных. Вы уже знаете, что они состоят из 8 бит (сейчас это не так важно) и они могут принимать значение от 0 до 255. О word переменных Вы знаете, что они имеют размер 16 бит и принимают значения от 0 до 65535. Заметили Вы или нет - word – это 2 байта. Теперь давайте подумаем, как хранить какое-либо значение в этих двух байтах. Каждый байт может быть от 0 до 255. Комбинируя их значения, мы получим 256*256, то есть 65536 возможных значений. Но как же эти 65536 значений хранить в 2-х байтах? Предположим, один из байтов (байт №1) равен 0. Тогда в другой байт (байт №2) можно записать значения 0..255. Так мы храним значения от 0 до 255. Когда байт №1 равен 1, мы можем хранить другие 256 чисел - от 256 до 511. Когда в байте №1 находится число 2, получаем следующие 256 чисел от 512 до 767 и так далее. Итого 256*256, как я и говорил, 65536. Это как в десятичных числах: каждая цифра принимает значения от 0 до 9, а истинное их значение зависит от позиции. Крайняя цифра – от 0 до 9, следующая (? предыдущая?) цифра 10*(0..9), далее – 100*(0..9) и так далее. Тоже самое в word: в одном из байтов – 0..255, в другом – 256*(0..255). Тот байт, в котором хранятся значения 0..255 называется младший байт, другой (где хранятся значения 256*(0..255)) – старший байт.
ПРИМИЧАНИЕ: Когда младший байт идет первым, это называется little endian encoding, когда первым идет старший - big endian encoding, но эти термины не особо важны для начинающих ассемблерщиков. 6.2. WORD регистры Помимо байтовых регистров (таких как al,ah,dl...), в процессоре, конечно, есть также WORD регистры. Вы знаете, что слово (WORD) – комбинация из 2-х байтов, так же и с регистрами. WORD регистры – это комбинация байтовых регистров. Первые WORD регистры, которые мы изучим – это ax, bx, cx и dx. ax – комбинация из al и ah. al - это младший байт, ah – старший. Так же: bx = bh:bl, cx = ch:cl, dx = dh:dl. (обратите внимание на вторую букву в названиях байтовых регистров L=LOW младший, H=HIGH старший). Если хотите эмулировать регистр ex в памяти, то это будет так:
Теперь, если хотите установить значение регистра ax в 52, используйте:
ПРИМЕЧАНИЕ: Вы знаете, что операнд инструкции может быть числом (числовой константой), такой как 0, 256, 12345 и так далее. Но все Ассемблеры, которые я знаю позволяют использовать так же какое-либо арифметическое выражение. Во время компиляции это выражение будет вычислено и заменено его результатом. Так, mov dx,(1 + 5) – тоже, что и mov dx, 6. Или проще, код выше может быть записан:
В процессоре есть также другие WORD регистры: sp, bp, si, di. Но нельзя непосредственно обращаться к их половинкам, можно только к целому слову. Это ограничение процессора, тут уж его не поделаешь. К примеру, если хотите установить старший байт регистра si в 17, нужно (?) делать так:
ПРИМЕЧАНИЕ: регистр sp всегда, а bp обычно имеют специальное предназначение в коде сгенерированном большинством (всеми?) не-ассемблерными компиляторами. Регистры si and di можно использовать как хотите. 6.3. Вывод строки с использованием int 21h ah=9 Это должно бы быть частью 3-й главы об адресах, но Вам нужно было бы знать регистр dx, про который рассказано здесь.. Здесь мы будем говорить о еще одном использовании int 21h. Вы уже знаете, что когда в ah содержится 2 то int 21h выводит символ из dl на экран. Но если мы хотим отобразить какой-то более длинный текст, нам придется устанавливать dl для каждого символа и это кривой способ. Не лучше ли просто хранить желаемую строку где-то, и потом просто отображать ее? Для этих целей мы можем использовать int 21h записав 9 в ah и адрес строки - в dx. Что-то вроде:
Пример вывода строки на экран:
1
|
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11.09.2014, 12:42 [ТС] | 6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
У такого метода маркировать конец строки есть одно ограничение – нельзя отобразить символ $. К примеру:
Подробнее об int 21h/ah=9. Как Вы, вероятно, уже поняли, это выводит на экран каждый символ (точнее - каждый символ, чей ASCII-код содержится в байте) от адреса в dx до первого символа $ после адреса в dx. ASCII коды от 0 до 31 (я так думаю) имеют специальное значение для int 21h/ah=9. Эти коды имеют соответствующие им символы (смайлики и так далее), но int 21h/ah=9 не отображает их, а делает кое-что другое. К примеру символ с ASCII кодом 7 производит короткий звуковой сигнал. Попробуйте:
Другие обычные значения – это 10 и 13. 10 перемещает курсор в первую позицию текущей строки. 13 перемещает курсор на строку вниз (при достижении нижней границы экрана, он скроллируется вверх). Так что, комбинация их переместит курсор в начало следующей строки. Это должно (но не всегда) работать при любом их порядке, но лучше 13 всегда писать первым. Эти два символа часто называют EOL. Вот например:
Другой пример с адресами, но с использованием WORD регистров. Проверьте себя - осмыслили ли вы третий раздел:
7 - Переходы и ветвления Вы должны уже знать немного о том, как инструкции выполняются процессором. Он берет машинный код инструкции, выполняет его, и переходит к следующей инструкции. Это продолжается до тех пор, пока не встретится инструкция int 20h. В этой главе мы изучим кое-что об инструкциях меняющих такой ход вещей. 7.1. Счётчик команд Процессор загружает первую инструкцию (он знает из скольких байтов она состоит), выполняет ее и переходит к другой инструкции. Но как работает этот механизм? В процессоре есть специальный WORD регистр ip, где хранится адрес исполняемой инструкции. После того, как инструкция выполнится, процессор прибавляет ее размер к ip и исполняет инструкцию по адресу [ip]. Упрощённо, механизм работает примерно так:
Код
Счётчик команд (instruction pointer) Регистр процессора, в котором хранится офсет команды, следующей за выполняемой в данный момент Регистр ip не похож на остальные регистры (такие как ax,ax,bp...). Его содержимое нельзя изменить используя инструкцию mov. mov ip,5 не будет работать. Но есть специальные инструкции, способные менять этот регистр. Это jmp (от jump - прыжок, скачок). У этой инструкции должен быть один операнд, новый адрес для регистра ip. Так jmp 5 имеет тот же эффект как и mov ip,5 (если б такая инструкция была). Например:
ПРИМЕЧАНИЕ: разумеется, когда ip меняется инструкцией jmp, то размер этой инструкции к нему не прибавляется. Если быть более точным jmp 5, не копирует в регистр ip число 5, подобно инструкции mov. На самом деле к текущему значению ip (то есть к адресу инструкции следующей за jmp) прибавляется или отнимается определенное число – смещение от текущего адреса до адреса 5. Это смещение вычисляется Ассемблером при компиляции, и на этом пока можно не заострять особого внимания. Просто имейте это ввиду; знание этого факта, возможно, облегчит Вашу жизнь в будущем. Такой переход называется относительным. Помимо этого существуют и абсолютные переходы когда в ip загружается значение, например, из другого регистра. 7.3. Сравнения и условные переходы Если Вы умеете программировать на каком-то языке, должно быть знаете о ветвлении, то есть выполнении частей программы по определенному условию. К примеру: скажем, нам необходимо получить значение не больше, чем 10 в al. Тогда если значение в al > 10, нужно установить al в 10. Это и есть ветвление – если какое-то условие выполняется, то что-то исполняется, иначе – нет. Реализация этого на Ассемблере: когда условие не выполняется, перепрыгиваем через условный кусок кода, иначе (условие выполняется) - просто продолжаем выполнение. Это как код С:
Примеры сравнения:
Более сложная версия: записать максимум из {ax,bx} в cx:
1
|
Ушел с форума
16276 / 7601 / 1064
Регистрация: 11.11.2010
Сообщений: 13,616
|
|||||||||||||||||||||
11.09.2014, 13:12 [ТС] | 7 | ||||||||||||||||||||
Таким образом, мы сравниваем ax с bx, затем, если ax меньше чем bx переход не произойдет и мы продолжим mov cx, bx записав большее значение в cx, как и нужно, и потом перейдем к метке done пропустив инструкцию, исполняемую в случае, если ax больше. Если ax больше чем bx, произойдет jmp AX_bigger, так что следующая инструкция будет mov cx, ax помещающая большее значение (из ax) в cx. Вы видите, код разделился на 2 ветви: одна для ax>bx, другая для ax<=bx. В итоге обе ветви ведут к инструкции после done:, и в этом месте cx всегда содержит максимальное значение. К стати, здесь могла бы быть инструкция jae вместо ja, так как для случая ax=bx обе ветви имеют одинаковый эффект.
ПРИМЕЧАНИЕ: Различные мнемоники инструкций условного ветвления могут обозначать одну и ту же инструкцию. Так, jna - это тоже, что и jbe; jnb эквивалентна jae; jb - jnae; ja - jnbe.
2
|
11.09.2014, 13:12 | |
11.09.2014, 13:12 | |
Помогаю со студенческими работами здесь
7
irrlicht. tutorial 1 Подскажите tutorial по Билдеру Tutorial на русском языке ASP.NET 1.x QuickStart Tutorial Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |