что значит mov ассемблер
STM Урок 201. Assembler. Первый проект. Команды MOV, LDR, STR, B. Часть 1
С данного урока начнём знакомиться с таким интересным языком, как ассемблер.
Я всегда люблю говорить, что ассемблер – это очень лёгкий язык, но писать на нём очень трудно. И вскоре вы поймёте, почему.
Язык C, который мы использовали, является языком высокого уровня, так же как и C++. Инструкции данных языков представляют собой практически английские слова, обозначающие те или иные действия. Только данные действия производятся над абстрактными величинами – массивами, переменными и т.д. Процессор, для которого мы пишем код, таких величин не знает. Поэтому данные языки ещё называют человеко-понятными.
Assembler же является машино-понятным языком, так как оперирует он с помощью своих команд, представляющих собой мнемоники тех или иных действий, регистрами процессора, ячейками памяти, адреса которых также, как правило, находятся в регистрах процессора (регистрах общего назначения или РОН).
Хоть и тяжело писать на ассемблере, всё же я буду стараться построить данный курс так, чтобы большинству было легче понять, что и как творится в коде. Поэтому мы язык ассемблер будем проходить постепенно, по несколько команд за урок, а не будем их изучать сразу все, прежде чем писать код.
Писать мы будем в среде программирования Keil, хотя вполне могли бы писать и в Eclipse, просто там мы много бы сил отдали бы настройке проекта, также синтаксис AT&T, который используется по умолчанию в ассемблере GNU с его бесконечными знаками процентов и долларов, мне не очень нравится, хотя в Eclipse также можно настроить и синтаксис Intel. В Keil же по умолчанию используется Intel, а также присутствует ряд полезных макросов, а также настройка проекта там занимает минимальное время.
Я, конечно, не буду томить вас бесконечной теорией, мы будем к ней возвращаться постепенно, но несколько слов по теории сказать всё же придётся.
Писать код мы будем пока для контроллера STM32F103, установленном на недорогой отладочной плате. Пока будем использовать три мануала – STM32F10xxx-20xxx-21xxx-L1xxxx-Programming-Manual, Cortex M3 Technical Reference Manual и ARMv7-M Architecture Reference Manual, которые найти, я думаю, у вас не составит особого труда, ссылки я на них давать не буду по понятным причинам, дабы не нарушить чьих-то авторских прав. Также будут использоваться некоторые интернет ресурсы – понятно, что больше всего будет использоваться ресурс разработчика ядра – arm.com.
Вот как выглядит схематически процессор Cortex M3, который является сердцем контроллера
Мы видим, что в самом центре находится ядро, которое взаимодействует с остальными блоками, в частности в процессор входит сторожевой таймер (DWT), модуль защиты памяти (MPU), контроллер вложенных векторных прерываний NVIC (Nested Vectored Interrupt Controller), модуль точек останова FPB (Flash Patch and Breakpoint), шинная матрица (Bus Matrix), которая соединяет процессор и интерфейс отладки с внешними шинами, расширенный высокопроизводительный порт доступа к шине (AHB-AP).
Ядро, выполненное по архитектуре ARMv7-M, по сравнению с предыдущими архитектурами, претерпело ряд изменений, в частности, применение инструкций нового набора инструкций Thumb-2, позволило в некоторых случаях добиться производительности на 70% больше по сравнению с ядром ARM7TDMI-S, исполняющим инструкции Thumb, и на 35% по сравнению с тем же ядром, исполняющим инструкции ARM. Также применение 3-ступенчатого конвейера обработки инструкций (этап выборки, этап декодирования, этап исполнения) также приводит к ускорению выполнению программы. Также наличие раздельных шин для данных и команд позволяет одновременно считывать процессором и то и другое, что тоже сказывается положительно на производительности работы ядра.
Ядро включает следующий набор регистров
Объяснять, для чего служит тот или иной регистр, сейчас нет никакого смысла, так как все равно никто этого не запомнит, запоминается лучше тогда, когда происходит использование на практике.
Как выглядят ассемблерные инструкции, мы также будем разбираться в процессе написания кода.
В нашем коде мы сегодня добьёмся самой простой задачи. Мы попытаемся зажечь светодиод, установленный на плате и подключенный к ножке PC13.
Чтобы нам писать ассемблерный код, надо будет для начала создать пустой проект, поэтому откроем Keil и создадим пустой проект, выбрав следующий пункт меню
Зададим имя проекту и сохраним его в заранее созданном каталоге
Здесь не выбираем вообще ничего
У нас появится вот такое дерево проекта
Переименуем группу, а то как-то некрасиво
Прежде чем наполнять наш проект файлами с исходным кодом, надо его настроить.
В настройках проекта сначала выставим правильную частоту тактирования кварцевого резонатора
Разрешим создание файла прошивки формата HEX
Также настроим создание файла прошивке в бинарном формате, введя вот такую строку:
Вышеуказанная строка может портиться благодаря функционалу WordPress, поэтому скопировать её лучше из моего проекта, который будет прикреплен в виде архива внизу страницы.
В каталоге с проектом создадим подкаталоги user и inc, подключив путь к последнему здесь
Отключим генерирование предупреждений с кодом 6314
Для тех, кто не знает, предупреждение с кодом 6314 – это сообщение о несоответствии секций определённым шаблонам. Для нас это не страшно, поэтому мы данное предупреждение и отключили, чтобы не маячило.
Выберем правильный отладчик
В свойствах отладчика включим данную настройку
Для того, чтобы были доступны настройки отладчика, плата должна быть подключена к компьютеру.
Включим автоперезагрузку после заливки ПО
Пока, в принципе, с настройками всё. Если, что, то потом донастроим.
Первая команда в ассемблере MOV
Эта команда используется для копирования значения из приёмника в источник. Синтаксис команды:
Mov приемник, источник
Пример:
Mov edx, ecx ; правильно
Размер источника и приемника должны быть одинаковыми.
Mov al, ecx; не правильно
Этот код пытается поместить DWORD (32-битное) значение в байт (8 битов).
Правильные команды:
Mov al, bl
Mov cl, dl
Mov cx, dx
Mov ecx, ebx
Можно получить значение из памяти и поместить его в регистр. Например, имеем следующую схему памяти:
смещение | 3A | 3B | 3C | 3D | 3E | 3F | |||
данные | 0D | 0A | 7A | 5E | EF | 7D | FF | AD | C7 |
Данные, которые имеют смещение 3A: 25, 7A, 5E, 72, EF, и т.д. Чтобы поместить значение со смещения 3A, например, в регистр, можно воспользоваться командой mov:
mov eax, dword ptr [0000003Ah] ; eax=725E7A25h
При работе с памятью самый младший байт сохраняется в наиболее значимом байте: порядок байтов задом на перед.
dword (32-бит) значение 10203040 шестнадцатиричное сохраняется в памяти как: 40, 30, 20, 10
word (16-бит) значение 4050 шестнадцатиричное сохраняется в памяти как: 50, 40
Пример2:
mov cl, byte ptr [34h] ; cl получит значение 0Dh
mov dx, word ptr [3Eh] ; dx получит значение 7DEFh
Размеры данных для префикса ptr:
Размер можно не указывать:
mov eax, [00403045h]
Пример3:
mov eax, 403045h ; eax= 00403045h
mov cx, [eax] ; CX=значение (размера word) из памяти указанной в EAX (403045)
Стек это область в памяти, на которую указывает регистр стека ESP(SP). Есть две команды, для размещения значения в стеке и извлечения его из стека: PUSH и POP. Команда PUSH размещает значение в стеке, т.е. помещает значение в ячейку памяти, на которую указывает регистр ESP, после этого значение регистра ESP уменьшается на 4. Команда POP извлекает значение из стека, т.е. извлекает значение из ячейки памяти, на которую указывает регистр ESP, после этого увеличивается значение регистра ESP на 4. Значение, помещенное в стек последним, извлекается первым.
Пример:
(1) mov ecx, 100
(2) mov eax, 200
(3) push ecx
(4) push eax
(5) xor ecx, eax
(6) add ecx, 400
(7) mov edx, ecx
(8) pop ebx
(9) pop ecx
1: поместить 100 в ecx
2: поместить 200 в eax
3: разместить значение из ecx (=100) в стеке (размещается первым)
4: разместить значение из eax (=200) в стеке (размещается последним)
5/6/7: выполнение операций над ecx, значение в ecx изменяется
8: извлечение значения из стека в ebx: ebx=200.
9: извлечение значения из стека в ecx: ecx=100.
Пример: Работа со стеком.
Смещение | 120A | 120B |
Значение | ||
ESP |
ESP стоит в том месте, на которое он указывает)
Mov ax, 4560h
Push ax
Смещение | 120A | 120B |
Значение | ||
ESP |
Mov cx, FFFFh
Push cx
Смещение | 120A | 120B |
Значение | FF | FF |
ESP |
Pop edx
Смещение | 120A | 120B |
Значение | FF | FF |
ESP |
edx = 4560FFFFh.
Пересылка данных
cmovcc
bswap
Особенности команды mov:
1) нельзя осуществлять пересылку из одной области памяти в другую. При такой необходимости нужно использовать в качестве промежуточного буфера любой доступный регистр общего назначения. Пример: переслать байты из ячейки памяти fls в ячейку fld:
Data
Fls dd 947503b3h
Code
Start
Mov eax, fls
Mov fld,eax
End start
2) нельзя загрузить в сегментный регистр значение непосредственно из памяти. Для выполнения такой загрузки нужно использовать промежуточный объект (регистр общего назначения или стек).
3) нельзя пересылать содержимое одного сегментного регистра в другой сегментный регистр. Выполнить такую пересылку можно, используя в качестве промежуточных регистры общего назначения.
Пример: инициализировать регистр es значением регистра ds:
Mov ax,ds
Move es,ax
Можно также использовать стек и команды push и pop:
Push ds ; поместить значение регистра ds в стек
Pop es ; записать в es число из стека
Нельзя использовать сегментный регистр cs в качестве операнда назначения.
5) оператор ptr можно применять и когда требуется принудительно поменять размерность операндов. К примеру, требуется переслать значение 0ffh во второй байт поля flp:
Data
Code
start:
mov byte ptr (flp+1),0ffh
End start
Для двунаправленной пересылки данных применяют команду xchg. Эту же операцию можно выполнить применив последовательность из нескольких команд mov. Общий вид записи:
Содержимое операнда2 копируется в операнд1, а старое содержимое операнда1 — в операнд2. XCHG можно выполнять над двумя регистрами или над регистром и переменной.
Например:
Xchg eax,ebx ; обменять содержимое регистров eax и ebx.
То же, что три команды на языке С:
Xchg al,al ; а эта команда не делает ничего
xchg ax, word ptr [si] ; обменять содержимое регистра ах и слова в памяти по адресу в [si].
Для условной пересылки данных используется команда:
CMOVcc
Набор команд, которые копируют содержимое источника в приемник, если удовлетворяется то или иное условие.
Можно использовать команды CMOVcc сразу после команды СМР (сравнение) с теми же операндами, например:
ASSEMBLER&WIN32. КУРС МОЛОДОГО БОЙЦА. УРОК 3.mov — команда ассемблера
Posted by key under assembler
Основы Ассемблера
Когда вы пишете программу на ассемблере, вы просто пишете команды процессору. Команды процессору — это просто коды или коды операций или опкоды. Опкоды — фактически «читаемый текст»- версии шестнадцатеричных кодов. Из-за этого, ассемблер считается самым низкоуровневым языком программирования, все в ассемблере непосредственно преобразовывается в шестнадцатеричные коды. Другими словами, у вас нет компилятора, который преобразовывает язык высокого уровня в язык низкого уровня, ассемблер только преобразовывает коды ассемблера в данные.
В этом уроке мы обсудим несколько опкодов, которые имеют отношение к вычислению, поразрядным операциям, и т.д. Другие опкоды: команды перехода, сравнения и т.д, будут обсуждены позже.
Комментарии в ваших программах оставляются после точки с запятой. Точно также как в дельфи или си через //.
Числа в ассемблере могут представляться в двоичной, десятеричной или шестнадцатеричной системе. Для того, чтобы показать в какой системе использовано число надо поставить после числа букву. Для бинарной системы пишется буква b (пример: 0000010b, 001011010b), для десятеричной системы можно ничего не указывать после числа или указать букву d (примеры: 4589, 2356d), для шестнадцатеричной системы надо указывать букву h, шестнадцатеричное число надо обязательно писать с нулём в начале (примеры: 00889h, 0AC45h, 056Fh, неправильно F145Ch, С123h).
Самая первая команда будет хорошо всем известная MOV. Эта команда используется для копирования (не обращайте внимания на имя команды) значения из одного места в другое. Это ‘место’ может быть регистр, ячейка памяти или непосредственное значение (только как исходное значение). Синтаксис команды:
mov приемник, источник
Вы можете копировать значение из одного регистра в другой.
Вышеприведенная команда копирует содержание ecx в edx. Размер источника и приемника должны быть одинаковыми, например: эта команда — НЕ допустима:
mov al, ecx ; не правильно
Этот опкод пытается поместить DWORD (32-битное) значение в байт (8 битов). Это не может быть сделано mov командой (для этого есть другие команды).
А эти команды правильные, потому что у них источник и приемник не отличаются по размеру:
mov al, bl
mov cl, dl
mov cx, dx
mov ecx, ebx
Вы также можете получить значение из памяти и поместить эго в регистр. Для примера возьмем следующую схему памяти:
смещение | 34 | 35 | 36 | 37 | 38 | 39 | 3A | 3B | 3C | 3D | 3E | 3F | 40 | 41 | 42 |
данные | 0D | 0A | 50 | 32 | 44 | 57 | 25 | 7A | 5E | 72 | EF | 7D | FF | AD | C7 |
(Каждый блок представляет байт)
Значение смещения обозначено здесь как байт, но на самом деле это это — 32-разрядное значение. Возьмем для примера 3A, это также — 32-разрядное значение: 0000003Ah. Только, чтобы с экономить пространство, некоторые используют маленькие смещения.
Посмотрите на смещение 3A в таблице выше. Данные на этом смещении — 25, 7A, 5E, 72, EF, и т.д. Чтобы поместить значение со смещения 3A, например, в регистр, вы также используете команду mov:
dword (32-бит) значение 10203040 шестнадцатиричное сохраняется в памяти как: 40, 30, 20, 10
word (16-бит) значение 4050 шестнадцатиричное сохраняется в памяти как: 50, 40
Вернемся к примеру выше. Вы также можете это делать и с другими размерами:
mov cl, byte ptr [34h] ; cl получит значение 0Dh
mov dx, word ptr [3Eh] ; dx получит значение 7DEFh
Вы, наверное, уже поняли, что префикс ptr обозначает, что надо брать из памяти некоторый размер. А префикс перед ptr обозначает размер данных:
Byte — 1 байт
Word — 2 байта
Dword — 4 байта
Иногда размер можно не указывать:
mov eax, [00403045h]
Так как eax — 32-разрядный регистр, ассемблер понимает, что ему также требуется 32-разрядное значение, в данном случае из памяти со смещением 403045h.
Можно также непосредственные значения:
Эта команда просто запишет в регистр edx, значение 5006. Скобки, [ и ], используются, для получения значения из памяти (в скобках находится смещение), без скобок, это просто непосредственное значение.
Можно также использовать регистр как ячейку памяти (он должен быть 32-разрядным в 32-разрядных программах):
mov eax, 403045h ; пишет в eax значение 403045
mov cx, [eax] ; помещает в регистр CX значение (размера word) из памяти
; указанной в EAX (403045)
В mov cx, [eax], процессор сначала смотрит, какое значение (= ячейке памяти) содержит eax, затем какое значение находится в той ячейке памяти, и помещает это значение (word, 16 бит, потому что приемник, cx, является 16-разрядным регистром) в CX.
(1) mov ecx, 100
(2) mov eax, 200
(3) push ecx ; сохранение ecx
(4) push eax
(5) xor ecx, eax
(6) add ecx, 400
(7) mov edx, ecx
(8) pop ebx
(9) pop ecx
Анализ:
1: поместить 100 в ecx
2: поместить 200 в eax
3: разместить значение из ecx (=100) в стеке (размещается первым)
4: разместить значение из eax (=200) в стеке (размещается последним)
5/6/7: выполнение операций над ecx, значение в ecx изменяется
8: извлечение значения из стека в ebx: ebx станет 200 (последнее размещение, первое извлечение)
9: извлечение значения из стека в ecx: ecx снова станет 100 (первое размещение, последнее извлечение)
Чтобы узнать, что происходит в памяти, при размещении и извлечении значений в стеке, см. на рисунок ниже:
Смещение | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 120A | 120B |
Значение | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
ESP |
(стек здесь заполнен нулями, но в действительности это не так, как здесь). ESP стоит в том месте, на которое он указывает)
mov ax, 4560h
push ax
Смещение | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 120A | 120B |
Значение | 00 | 00 | 60 | 45 | 00 | 00 | 00 | 00 | 00 |
ESP |
mov cx, FFFFh
push cx
Смещение | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 120A | 120B |
Значение | FF | FF | 60 | 45 | 00 | 00 | 00 | 00 | 00 |
ESP |
Смещение | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 120A | 120B |
Значение | FF | FF | 60 | 45 | 00 | 00 | 00 | 00 | 00 |
ESP |
edx теперь 4560FFFFh.
Вызов подпрограмм возврат из них — CALL, RET. Команда call передает управление ближней или дальней процедуре с запоминанием в стеке адреса точки возврата. Команда ret возвращает управление из процедуры вызывающей программе, адрес возврата получает из стека. Пример:
..code..
call 0455659
..more code..
Код с адреса 455659:
add eax, 500
mul eax, edx
ret
Когда выполняется команда call, процессор передает управление на код с адреса 455659, и выполняет его до команды ret, а затем возвращает управление команде следующей за call. Код который вызывается командой call называется процедурой. Вы можете поместить код, который вы часто используете в процедуру и каждый раз когда он вам нужен вызывать его командой call.
Подробнее: команда call помещает регистр EIP (указатель на следующюю команду, которая должна быть выполнена) в стек, а команда ret извлекает его и передаёт управление этому адресу. Вы также можете определить аргументы, для вызываемой программы (процедуры). Это можно сделать через стек:
push значение_1
push значение_2
call procedure
Внутри процедуры, аргументы могут быть прочитаны из стека и использованы. Локальные переменные, т.е. данные, которые необходимы только внутри процедуры, также могут быть сохранены в стеке. Я не буду подробно рассказывать об этом, потому, что это может быть легко сделано в ассемблерах MASM и TASM. Просто запомните, что вы можете делать процедуры и что они могут использовать параметры.
Одно важное замечание:
регистр eax почти всегда используется для хранения результата процедуры.
Это также применимо к функциям windows. Конечно, вы можете использовать любой другой регистр в ваших собственных процедурах, но это стандарт.
Система команд x86
Влияние команды на флаги и форматы команды:
Описание:
Команда MOV копирует второй операнд (операнд-источник) в первый операнд (операнд-назначение). Оба операнда могут быть регистрами общего назначения, сегментными регистрами, непосредственными значениями и переменными в памяти. Оба операнда должны иметь одинаковую размерность — байт, слово или двойное слово.
Если операнд-назначение — сегментный регистр (DS, ES, FS, GS или SS), тогда в скрытую часть этого регистра также загружаются данные из соответствующего дескриптора. Эти данные извлекаются из элемента таблицы дескрипторов для данного селектора. Сегментный регистр CS не может быть загружен командой MOV. Попытка использования соответствующего кода приводит к генерации особой ситуации #UD. Для загрузки регистра CS должны использоваться команды JMP, CALL или RET.
Пустой селектор (значения 0000, … 0003) может быть загружен в регистры DS, ES, FS и GS не вызывая особой ситуации. Однако попытка использования нулевых селекторов при обращении к памяти вызывает особую ситуацию #GP(0), и никакого обращения к памяти не происходит.
Ниже представлен листинг всех проверок и действий, предпринимаемых процессором при загрузке сегментного регистра в защищенном режиме:
IF (Селектор не нулевой) THEN #GP(0); FI;
Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(Селектор);
Поле RPL селектора должно быть равно CPL, иначе #GP(Селектор);
AR байт должен задавать сегмент данных, доступный для записи, иначе #GP(Селектор);
Поле DPL AR байта должно быть равно CPL, иначе #GP(Селектор);
Сегмент должен быть помечен, как присутствующий, иначе #SS(Селектор);
Загрузить SS селектором;
Загрузить SS дескриптором;
IF (загружается DS, ES, FS или GS не нулевым селектором)
Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(Селектор);
AR байт должен задавать сегмент данных, или кодовый сегмент доступный для чтения, иначе #GP(Селектор);
IF (Данные или несогласованный код)
THEN RPL и CPL должны быть меньше или равны DPL в AR байте, иначе #GP(Селектор);
Сегмент должен быть помечен, как присутствующий, иначе #NP(Селектор);
Загрузить селектор в сегментный регистр;
Загрузить дескриптор в сегментный регистр;
IF (Загружается DS, ES, FS или GS нулевым селектором)
Загрузить селектор в сегментный регистр;
Очистить внутренний флаг корректности дескриптора (descriptor valid bit);
Команда загрузки сегмента стека SS запрещает все прерывания до завершения выполнения следующей команды (которая может быть командой MOV в ESP). Более эффективным методом загрузки нового указателя стека является команда LSS. Существуют и другие команды, которые задерживают прием прерываний при выполнении следующей за ними команды, но комбинация таких команд (например, STI и MOV SS,EAX) не означает, что прерывания не будут восприниматься на протяжении двух команд. Такие последовательности могут вызвать серьезные сбои, т.к. станет возможным поступление прерывания сразу после команды загрузки стекового сегмента SS.
В процессорах 32-разрядной архитектуры (Intel386, …) команды пересылки между сегментными регистрами и регистрами общего назначения не требуют наличия префикса 16-битного размера операнда (66h) не зависимо от текущего режима работы. Т.е. в этом случае всегда пересылаются 16-битные данные. Многие ассемблеры при встрече подобных мнемоник (например, MOV DS,AX) автоматически вставляют префикс 16-битного размера операнда перед командой пересылки. Это не влияет на результат исполнения команды, а замедляет только время исполнения. Простейшим выходом из данной ситуации является программирование 32-битной мнемоники (MOV DS,EAX), она преобразуется ассемблером в тот же самый код операции, но без префикса размера операнда. Поскольку пересылка данных в этом случае происходит межу 16-битным и 32-битным регистрами, то в 32-битном регистре в операции учавствуют только его младшие 16 бит. Если 32-битный регистр является операндом-назначением такой операции, то значения в его старших 16 битах после окончания пересылки могут быть различны в различных моделях процессоров. В Pentium Pro, … они заполняются нулями, а для более ранних процессоров Intel их значения не определены.
Операция:
Особые ситуации защищенного режима:
#GP(0), если операнд-назначение находится в сегменте, запрещенном для записи, если используется некорректный эффективный адрес операнда в памяти в сегментах CS, DS, ES, FS, GS или нулевой селектор, а также при попытке загрузки регистра SS нулевым селектором.
#GP(Селектор), если индекс загруженного селектора не попадает в пределы таблицы дескрипторов, если при загрузке регистра SS запрашиваемый уровень привилегий селектора RPL или уровень привилегий соответствующего дескриптора сегмента DPL не равны текущему уровню привилегий CPL, если регистр SS загружается селектором, который указывает на сегмент запрещенный для записи, если регистр DS, ES, FS или GS загружается селектором сегмента, который не является доступным для чтения кодовым сегментом или сегментом данных, если регистр DS, ES, FS или GS загружается селектором сегмента, который является сегментом данных или несогласованным кодовым сегментом, и уровень привилегий дескриптора этого сегмента DPL меньше по значению запрашиваемого уровня привилегий селектора RPL и текущего уровня привилегий CPL.
#SS(0) при использовании некорректного эффективного адреса в сегменте SS.
#SS(Селектор), если регистр SS загружается селектором сегмента, который помечен как неприсутствующий.
#NP(Селектор), если регистр DS, ES, FS или GS загружается селектором сегмента, который помечен как неприсутствующий.
#PF(Код ошибки), страничная ошибка.
#AC(0) при невыровненной ссылке в память при текущем уровне привилегий равном 3.
#UD при попытке загрузки регистра CS.
Особые ситуации режима реальной адресации:
#GP, если любая часть операнда находится вне пространства эффективных адресов в сегментах CS, DS, ES, FS или GS.
#SS, если любая часть операнда находится вне пространства эффективных адресов в сегменте SS.
#UD при попытке загрузки регистра CS.
Особые ситуации режима V86:
Такие же, как и в режиме реальной адресации.
#PF(Код ошибки), страничная ошибка.
#AC(0) при невыровненной ссылке в память.
Замечание:
В процессоре Pentium III существуют некоторые ситуации, когда отладчик будет получать неверную информацию в регистрах отладки от команд MOV SS и POP SS. Обратитесь к технической документации Intel за описанием всех возможных случаев проявления ошибки.