CodeNet / Языки программирования / Ассемблер / СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
Мнемоники инструкций и директивы ----------------------------------------------------------------- Основным полем в строке программы на Ассемблере является поле <инструкция/директива>. Это поле может содержать мнемонику инструкции или директиву (две совершенно различные вещи). Ранее в данной главе вы уже встречали мнемоники инструкций. Они представляют собой удобные для чтений имена инструкций, не- посредственно выполняемых процессором 8086. MOV, ADD, MUL и JMP - все это мнемоники инструкций, соответствующие инструкциям процес- сора 8086 перемещения данных, сложения, умножения и перехода со- ответственно. Турбо Ассемблер ассемблирует каждую мнемонику инструкции не- посредственно в соответствующую инструкцию на машинном языке. Каждый раз, когда вы включаете в программу на языке Ассемблера одну мнемонику инструкции, результатом является одна инструкция в выполняемом коде. В отличие от мнемоник инструкций, директивы совсем не гене- рируют выполняемого кода. Вместо этого они управляют различными аспектами работы Турбо Ассемблера - от типа ассемблируемого кода (процессоры 8086, 80286, 80386 и т.д.) до используемых сегментов и формата создаваемых файлов листингов. Хотя это не единственное отличие, вы можете рассматривать мнемоники инструкций, как гене- рирующие реальную программу на машинном языке процессора 8086, а директивы - как ответственные за обеспечение средств высокого уровня Турбо Ассемблера, которые облегчают программирование на Ассемблере. В данном руководстве мы уделяем большое внимание различным аспектам мнемоник и директив Турбо Ассемблера, которые обсуждают- ся также в Главе 3 "Справочного руководства". Имеется несколько директив, которые необходимы в любой программе на Ассемблере (в особенности это касается директив определения сегментов, которые мы обсудим несколько позднее). Другая директива, которая всегда необходима в программе - это директива END. Директива END ----------------------------------------------------------------- Каждая программа должна содержать директиву END, отмечающую конец исходного кода программы. Все строки, которые следуют за директивой END, Турбо Ассемблером игнорируются. Если вы опустите директиву END, то генерируется ошибка. Вы можете посчитать, что концом программы является конец файла, но это не так: всегда тре- буется указывать директиву END. END является типичной директивой в том смысле, что она не порождает никакого кода. Например: DOSSEG .MODEL SMALL .STACK 200h .DATA ProgramStart: mov ah,4ch int 21h END ProgramStart Это, возможно, простейшая программа на Ассемблере. Она ниче- го не делает, просто немедленно возвращает управление DOS. Обра- тите внимание на использование директивы END для завершения кода, из которого состоит данная программа. Без сомнения вы заметили, что на одной строке с директивой END содержится метка ProgramStart. Кроме завершения программы, директива END может выполнять еще и вторую функцию, указывая, где должно начинаться выполнение при запуске программы. По той или иной причине вы можете не захотеть начать выполнение программы в файле .EXE с первой инструкции. Директива END предусматривает та- кие случаи. Предположим, например, вы запускаете программу, полу- ченную в результате ассемблирования и компоновки следующего кода: DOSSEG .MODEL SMALL .STACK 200h .DATA Delay: mov cx,0 DelayLoop: loop DelayLoop ret ProgramStart: call Delay ; пауза на время, ; необходимое для ; выполнения 64 циклов mov ah,4ch int 21h END ProgramStart Выполнение здесь начинается не на первой инструкции исходно- го кода (MOV CX,0) по метке Delay. Вместо этого выполнение начи- нается с инструкции CALL Delay по метке ProgramStart, как опреде- лено в директиве END. Если программа состоит только из одного модуля (то есть од- ного исходного файла), то в директиве END всегда нужно определять адрес запуска программы. В программе, состоящей из нескольких мо- дулей, определять адрес запуска программы следует только в дирек- тиве END модуля, содержащего инструкцию, с которой должно начать- ся выполнение программы. В директивах END других модулей должно указываться только ключевое слово END и нечего более. В самом деле: каждая программа должна иметь точку начала выполнения, но было бы бессмысленно иметь несколько таких точек. Убедитесь в том, что вашей программе имеется один (и только один) адрес нача- ла выполнения. (Кстати, если в вашей программе имеется два таких адреса, компоновщик TLINK использует только первый адрес, который он обнаруживает, и игнорирует другой.) Операнды ----------------------------------------------------------------- Мнемоники инструкций и директивы сообщают Турбо Ассемблеру, что нужно делать. С другой стороны, операнды указывают Турбо Ас- семблеру, какие регистры, параметры, ячейки памяти и т.д. нужно связать с каждым вхождением инструкции или директивы. Инструкция MOV (перемещение данных) сама по себе ничего не означает. Чтобы указать Турбо Ассемблеру, откуда нужно извлечь перемещаемое зна- чение и где его сохранить, необходимы операнды. Для различных инструкций требуются 0, 1, 2 или более операн- дов. В действительности различными директивами может восприни- маться любое число операндов, которое может уместиться на одной строке. Правильное число операндов зависит от конкретной инструк- ции или директивы. (В общем случае допускается три операнда.) Возможные операнды включают в себя регистры, константы, метки, переменные в памяти и текстовые строки. Какие функции выполняет инструкция с одним операндом, доста- точно очевидно: она выполняет операции с этим операндом. Напри- мер: push ax заносит регистр AX в стек. Инструкции без операндов еще более очевидны. Однако, что происходит в случае инструкции с двумя опе- рандами, один из которых является источником, а остальные прием- ником? Например, когда процессор 8086 выполняет инструкцию: mov ax,bx то из какого регистра он считывает значение, и в какой регистр записывает? Вы можете посчитать, что словесным эквивалентом данной инструкции будет "переместить содержимое AX в BX", но это не так. Вместо этого инструкция MOV помещает содержимое BX в AX. Можно использовать следующее правило: замените в инструкции MOV запятую между операндами знаком равенства, после чего она приобретет вид оператора присваивания, аналогичный языку Си (или Паскаль). При таком подходе инструкция MOV преобразуется в вид: ax = bx; Это позволит вам легче запомнить работу данной инструкции. На самом деле в использовании правого операнда в качестве источника есть некоторая доля путаницы, но по крайней мере в Ас- семблере процессора 8086 это так, и скоро вы это используете. Регистровые операнды ----------------------------------------------------------------- Вероятно регистровые операнды являются наиболее часто ис- пользуемыми в инструкциях операндами. Регистры могут использо- ваться в качестве источника (исходный операнд) или приемника (це- левой операнд) и при некоторых обстоятельствах могут даже содер- жать адрес, на который нужно выполнить переход. С регистрами мож- но делать много того, чего нельзя делать с константами, метками или переменными в памяти. С другой стороны, имеются некоторые инструкции, в которых можно использовать только регистровые опе- ранды. Приведем некоторые примеры регистровых операндов: mov al,ax push dl xchg al,dl ror dx,cl in al,dx inc sl Регистровые операнды могут использоваться вместе с другими операндами: mov al,1 add [BaseCount],cx cmp si,[bx] Использование регистровых операндов не требует обширных по- яснений. Чтобы использовать регистр в качестве операнда, вы зада- ете имя этого регистра и использующую регистр инструкцию. Если имеется два операнда и регистровым операндом является самый пра- вый операнд, то он будет исходным регистром (источником), а если самым левым операндом - то это целевой регистр (приемник). Если в инструкции требуется два источника, то может присутствовать еще один исходный регистр. Например, во фрагменте программы: . . . mov cx,1 mov dx,2 sub dx,cx . . . регистр CX устанавливается в значение 1, DX - в значение 2, а за- тем из регистра DX вычитается CX и результат (1) снова записыва- ется в регистр DX. В инструкции SUB CX является правым операндом, поэтому это исходный регистр (источник). DX - самый левый опе- ранд, поэтому он одновременно является вторым источником и прием- ником. Кстати, действие данной инструкции SUB (вычитание) выража- ется словами, как "вычесть CX из DX". Использование метода преобразования в код языка Си для облегчения запоминания инструк- ций позволяет преобразовать данную инструкцию SUB к виду: dx -= cx; а на Паскале это будет выглядеть, как: dx := dx - cx;